diff --git a/config/Sources.cmake b/config/Sources.cmake
index 83228a385367472751cf0b30f1ed4801841c90bc..4cae57fd99c284a93f7522da18af020a33d6406e 100644
--- a/config/Sources.cmake
+++ b/config/Sources.cmake
@@ -145,6 +145,9 @@ set(vkcv_sources
 		${vkcv_include}/vkcv/VertexData.hpp
 		${vkcv_source}/vkcv/VertexData.cpp
 		
+		${vkcv_include}/vkcv/GeometryData.hpp
+		${vkcv_source}/vkcv/GeometryData.cpp
+		
 		${vkcv_include}/vkcv/Result.hpp
 		
 		${vkcv_include}/vkcv/RayTracingPipelineConfig.hpp
diff --git a/include/vkcv/Core.hpp b/include/vkcv/Core.hpp
index d9749947ee27520fb8fc0f8513c13ef76a7758ea..d7d850f7190c6cc8bf49501df932a53744cec1f0 100644
--- a/include/vkcv/Core.hpp
+++ b/include/vkcv/Core.hpp
@@ -19,6 +19,7 @@
 #include "Drawcall.hpp"
 #include "Event.hpp"
 #include "EventFunctionTypes.hpp"
+#include "GeometryData.hpp"
 #include "GraphicsPipelineConfig.hpp"
 #include "Handles.hpp"
 #include "ImageConfig.hpp"
@@ -959,5 +960,35 @@ namespace vkcv {
 		 * @return Vulkan device memory
 		 */
 		[[nodiscard]] vk::DeviceMemory getVulkanDeviceMemory(const ImageHandle &handle) const;
+		
+		/**
+		 * @brief Creates an acceleration structure handle built with a given list of geometry data.
+		 *
+		 * @param[in] geometryData List of geometry data
+		 * @return Acceleration structure handle
+		 */
+		AccelerationStructureHandle createAccelerationStructure(
+				const std::vector<GeometryData> &geometryData);
+		
+		/**
+		 * @brief the underlying vulkan handle for an acceleration structure
+		 * by its given acceleration structure handle.
+		 *
+		 * @param[in] handle Acceleration structure handle
+		 * @return Vulkan acceleration structure
+		 */
+		[[nodiscard]] vk::AccelerationStructureKHR getVulkanAccelerationStructure(
+				const AccelerationStructureHandle &handle) const;
+		
+		/**
+		 * @brief Return the underlying vulkan handle for an acceleration
+		 * structure by its given acceleration structure handle.
+		 *
+		 * @param[in] handle Acceleration structure handle
+		 * @return Vulkan buffer
+		 */
+		[[nodiscard]] vk::Buffer getVulkanBuffer(
+				const vkcv::AccelerationStructureHandle &handle) const;
+		
 	};
 } // namespace vkcv
diff --git a/include/vkcv/GeometryData.hpp b/include/vkcv/GeometryData.hpp
new file mode 100644
index 0000000000000000000000000000000000000000..0dcea5be480b47f8246e47ccb55d66490ec00a20
--- /dev/null
+++ b/include/vkcv/GeometryData.hpp
@@ -0,0 +1,127 @@
+#pragma once
+/**
+ * @authors Tobias Frisch
+ * @file vkcv/GeometryData.hpp
+ * @brief Types to configure geometry data for acceleration structure building.
+ */
+
+#include "VertexData.hpp"
+
+namespace vkcv {
+	
+	/**
+	 * @brief Enum class to specify the format of vertex in geometry.
+	 */
+	enum class GeometryVertexType {
+		POSITION_FLOAT3,
+		UNDEFINED
+	};
+	
+	/**
+	 * @brief Class to store the details of geometry data for acceleration structure building
+	 */
+	class GeometryData {
+	private:
+		VertexBufferBinding m_vertexBinding;
+		uint32_t m_vertexStride;
+		GeometryVertexType m_vertexType;
+		BufferHandle m_indices;
+		IndexBitCount m_indexBitCount;
+		size_t m_count;
+	
+	public:
+		/**
+		 * @brief Default constructor of invalid geometry data.
+		 */
+		GeometryData();
+		
+		/**
+		 * @brief Constructor of geometry data by providing an vertex buffer binding,
+		 * the used stride for vertex elements and its geometry vertex type.
+		 *
+		 * @param[in] binding Geometry buffer binding
+		 * @param[in] stride Vertex element stride
+		 * @param[in] geometryVertexType Geometry vertex type
+		 */
+		explicit GeometryData(const VertexBufferBinding &binding,
+							  uint32_t stride = sizeof(float) * 3,
+							  GeometryVertexType geometryVertexType =
+									  GeometryVertexType::POSITION_FLOAT3);
+		
+		GeometryData(const GeometryData &other) = default;
+		GeometryData(GeometryData &&other) noexcept = default;
+		
+		~GeometryData() = default;
+		
+		GeometryData &operator=(const GeometryData &other) = default;
+		GeometryData &operator=(GeometryData &&other) noexcept = default;
+		
+		/**
+		 * @brief Return whether the geometry is valid to use.
+		 *
+		 * @return True if the geometry data is valid, otherwise false.
+		 */
+		[[nodiscard]] bool isValid() const;
+		
+		/**
+		 * @brief Return the used vertex buffer binding of the geometry data.
+		 *
+		 * @return Vertex buffer binding
+		 */
+		[[nodiscard]] const VertexBufferBinding &getVertexBufferBinding() const;
+		
+		/**
+		 * @brief Return the stride of vertex elements of the geometry data.
+		 *
+		 * @return Vertex stride
+		 */
+		[[nodiscard]] uint32_t getVertexStride() const;
+		
+		/**
+		 * @brief Return the geometry vertex type of the geometry data.
+		 *
+		 * @return Geometry vertex type
+		 */
+		[[nodiscard]] GeometryVertexType getGeometryVertexType() const;
+		
+		/**
+		 * @brief Set the optional index buffer and its used index bit count.
+		 *
+		 * @param[in] indices Index buffer handle
+		 * @param[in] indexBitCount Index bit count
+		 */
+		void setIndexBuffer(const BufferHandle &indices,
+							IndexBitCount indexBitCount = IndexBitCount::Bit16);
+		
+		/**
+		 * @brief Return the handle from the used index buffer of the vertex
+		 * data.
+		 *
+		 * @return Index buffer handle
+		 */
+		[[nodiscard]] const BufferHandle &getIndexBuffer() const;
+		
+		/**
+		 * @brief Return the index bit count of the indices used in the
+		 * vertex data.
+		 *
+		 * @return Index bit count
+		 */
+		[[nodiscard]] IndexBitCount getIndexBitCount() const;
+		
+		/**
+		 * @brief Set the count of elements to use by the vertex data.
+		 *
+		 * @param count Count of vertex elements
+		 */
+		void setCount(size_t count);
+		
+		/**
+		 * @brief Return the count of elements in use by the vertex data.
+		 *
+		 * @return Count of vertex elements
+		 */
+		[[nodiscard]] size_t getCount() const;
+	};
+	
+} // namespace vkcv
diff --git a/modules/geometry/include/vkcv/geometry/Geometry.hpp b/modules/geometry/include/vkcv/geometry/Geometry.hpp
index cf2b6eb5132e46883a81dc6d45eae18f51f48bea..ea006b009e45c3147b914890039f7a86bf39e519 100644
--- a/modules/geometry/include/vkcv/geometry/Geometry.hpp
+++ b/modules/geometry/include/vkcv/geometry/Geometry.hpp
@@ -111,6 +111,17 @@ namespace vkcv::geometry {
 		[[nodiscard]]
 		virtual VertexData generateVertexData(Core& core) const = 0;
 		
+		/**
+		 * Extracts a geometry data structure from its own
+		 * generated vertex data, which can be used for
+		 * building bottom level acceleration structures.
+		 *
+		 * @param[in, out] vertexData Vertex data with generated geometry
+		 * @return Geometry data from generated vertex data
+		 */
+		[[nodiscard]]
+		virtual GeometryData extractGeometryData(const VertexData &vertexData) const;
+		
 	};
 	
 	/** @} */
diff --git a/modules/geometry/src/vkcv/geometry/Geometry.cpp b/modules/geometry/src/vkcv/geometry/Geometry.cpp
index feaa84a04f2e180b08fd92977d6494ac997af6b2..ec0d56e06ccf9d5cf5d9dd92192f930715adc055 100644
--- a/modules/geometry/src/vkcv/geometry/Geometry.cpp
+++ b/modules/geometry/src/vkcv/geometry/Geometry.cpp
@@ -28,4 +28,17 @@ namespace vkcv::geometry {
 		));
 	}
 	
+	GeometryData Geometry::extractGeometryData(const vkcv::VertexData &vertexData) const {
+		GeometryData data (
+				vertexData.getVertexBufferBindings()[0],
+				sizeof(glm::vec3),
+				GeometryVertexType::POSITION_FLOAT3
+		);
+		
+		data.setIndexBuffer(vertexData.getIndexBuffer(), vertexData.getIndexBitCount());
+		data.setCount(vertexData.getCount());
+		
+		return data;
+	}
+	
 }
diff --git a/projects/rtx_ambient_occlusion/resources/shaders/ambientOcclusion.rchit b/projects/rtx_ambient_occlusion/resources/shaders/ambientOcclusion.rchit
index 95e3d6acba8dcb05d61c87c737a4aeb3a9fe6fce..03806c4f498f7dcd751078216628774a50fa82bd 100644
--- a/projects/rtx_ambient_occlusion/resources/shaders/ambientOcclusion.rchit
+++ b/projects/rtx_ambient_occlusion/resources/shaders/ambientOcclusion.rchit
@@ -11,8 +11,6 @@ layout(location = 0) rayPayloadInEXT Payload {
   vec3 worldNormal;
 } payload;
 
-layout(binding = 1, set = 0) uniform accelerationStructureEXT tlas;     // top level acceleration structure
-
 layout(binding = 2, set = 0, scalar) buffer rtxVertices
 {
     float vertices[];
diff --git a/projects/rtx_ambient_occlusion/src/RTX/ASManager.cpp b/projects/rtx_ambient_occlusion/src/RTX/ASManager.cpp
index 55bbcff533c59aa53b2df43c82f0bd9f24583aab..b18cb3455f98d294ef46a9d306c7bacedd19d7b8 100644
--- a/projects/rtx_ambient_occlusion/src/RTX/ASManager.cpp
+++ b/projects/rtx_ambient_occlusion/src/RTX/ASManager.cpp
@@ -23,14 +23,7 @@ namespace vkcv::rtx {
         // destroy every BLAS, its data containers and free used memory blocks
         for (size_t i=0; i < m_bottomLevelAccelerationStructures.size(); i++) {
             BottomLevelAccelerationStructure blas = m_bottomLevelAccelerationStructures[i];
-            m_core->getContext().getDevice().destroyAccelerationStructureKHR(blas.vulkanHandle, nullptr, m_rtxDispatcher);
-            m_core->getContext().getDevice().destroy(blas.accelerationBuffer.vulkanHandle);
-            m_core->getContext().getDevice().destroy(blas.indexBuffer.vulkanHandle);
-            m_core->getContext().getDevice().destroy(blas.vertexBuffer.vulkanHandle);
-
-            m_core->getContext().getDevice().freeMemory(blas.accelerationBuffer.deviceMemory);
-            m_core->getContext().getDevice().freeMemory(blas.indexBuffer.deviceMemory);
-            m_core->getContext().getDevice().freeMemory(blas.vertexBuffer.deviceMemory);
+            //m_core->getContext().getDevice().destroyAccelerationStructureKHR(blas.vulkanHandle, nullptr, m_rtxDispatcher);
         }
 
         // destroy the TLAS, its data containers and free used memory blocks
@@ -163,43 +156,17 @@ namespace vkcv::rtx {
 		const auto& originalVertexBuffer = vertexData.getVertexBufferBindings()[0].buffer;
 		const auto& originalIndexBuffer = vertexData.getIndexBuffer();
 		
-		std::vector<float> vertices;
-		std::vector<uint16_t> indices;
-	
-		vertices.resize(
-				m_core->getBufferSize(originalVertexBuffer) / sizeof(float)
-		);
-		
-		const float *raw_vertices = reinterpret_cast<float*>(
-				m_core->mapBuffer(originalVertexBuffer, 0, 0)
-		);
-	
-		memcpy(vertices.data(), raw_vertices, vertices.size() * sizeof(float));
-		m_core->unmapBuffer(originalVertexBuffer);
-	
-		indices.resize(
-				m_core->getBufferSize(originalIndexBuffer) / sizeof(uint16_t)
-		);
-	
-		const uint16_t *raw_indices = reinterpret_cast<uint16_t*>(
-				m_core->mapBuffer(originalIndexBuffer, 0, 0)
-		);
-	
-		memcpy(indices.data(), raw_indices, indices.size() * sizeof(uint16_t));
-		m_core->unmapBuffer(originalIndexBuffer);
-		
-		auto vertexBuffer = makeBufferFromData(vertices);
-		auto indexBuffer = makeBufferFromData(indices);
+		const auto vbSize = m_core->getBufferSize(originalVertexBuffer);
 
-        vk::DeviceAddress vertexBufferAddress = getBufferDeviceAddress(vertexBuffer.vulkanHandle);
-        vk::DeviceAddress indexBufferAddress = getBufferDeviceAddress(indexBuffer.vulkanHandle);
+        vk::DeviceAddress vertexBufferAddress = m_core->getBufferDeviceAddress(originalVertexBuffer);//getBufferDeviceAddress(vertexBuffer.vulkanHandle);
+        vk::DeviceAddress indexBufferAddress = m_core->getBufferDeviceAddress(originalIndexBuffer);//getBufferDeviceAddress(indexBuffer.vulkanHandle);
 
         // triangle mesh data
         vk::AccelerationStructureGeometryTrianglesDataKHR asTriangles(
                 vk::Format::eR32G32B32Sfloat,   // vertex format
                 vertexBufferAddress, // vertex buffer address (vk::DeviceOrHostAddressConstKHR)
                 3 * sizeof(float), // vertex stride (vk::DeviceSize)
-                uint32_t(vertices.size() / 3 - 1), // maxVertex (uint32_t)
+                uint32_t(vbSize / (3 * sizeof(float)) - 1), // maxVertex (uint32_t)
                 vk::IndexType::eUint16, // indexType (vk::IndexType) --> INFO: UINT16 oder UINT32!
                 indexBufferAddress, // indexData (vk::DeviceOrHostAddressConstKHR)
                 {} // transformData (vk::DeviceOrHostAddressConstKHR)
@@ -214,7 +181,7 @@ namespace vkcv::rtx {
 
         // Ranges for data lists
         vk::AccelerationStructureBuildRangeInfoKHR asRangeInfo(
-                uint32_t(indices.size() / 3), // the primitiveCount (uint32_t)
+                uint32_t(vertexData.getCount() / 3), // the primitiveCount (uint32_t)
                 0, // primitiveOffset (uint32_t)
                 0, // firstVertex (uint32_t)
                 0  // transformOffset (uint32_t)
@@ -300,13 +267,24 @@ namespace vkcv::rtx {
         m_core->getContext().getDevice().freeMemory(scratchBuffer.deviceMemory, nullptr, m_rtxDispatcher);
                 
         BottomLevelAccelerationStructure blas = {
-                vertexBuffer,
-                indexBuffer,
-                blasBuffer,
+                vertexData.getVertexBufferBindings()[0].buffer,
+                vertexData.getIndexBuffer(),
+				nullptr,
                 blasKHR
         };
         m_bottomLevelAccelerationStructures.push_back(blas);
     }
+	
+	void ASManager::add(const vkcv::GeometryData &geometryData, const vkcv::AccelerationStructureHandle &blas) {
+		BottomLevelAccelerationStructure blasEntry = {
+				geometryData.getVertexBufferBinding().buffer,
+				geometryData.getIndexBuffer(),
+				m_core->getVulkanBuffer(blas),
+				m_core->getVulkanAccelerationStructure(blas)
+		};
+		
+		m_bottomLevelAccelerationStructures.push_back(blasEntry);
+	}
 
     void ASManager::buildTLAS() {
         // TODO: organize hierarchical structure of multiple BLAS
diff --git a/projects/rtx_ambient_occlusion/src/RTX/ASManager.hpp b/projects/rtx_ambient_occlusion/src/RTX/ASManager.hpp
index 7124ce8914161154cd3047ad70d4f0e750d24506..825d5e651d34262e9b60a6345c95512a17132e31 100644
--- a/projects/rtx_ambient_occlusion/src/RTX/ASManager.hpp
+++ b/projects/rtx_ambient_occlusion/src/RTX/ASManager.hpp
@@ -32,9 +32,9 @@ namespace vkcv::rtx {
      * @brief Used as a container to handle bottom-level acceleration structure (BLAS) construction and destruction.
      */
     struct BottomLevelAccelerationStructure {
-        RTXBuffer vertexBuffer;
-        RTXBuffer indexBuffer;
-        RTXBuffer accelerationBuffer;
+        vkcv::BufferHandle vertexBuffer;
+		vkcv::BufferHandle indexBuffer;
+		vk::Buffer accelerationBuffer;
         vk::AccelerationStructureKHR vulkanHandle;
     };
 
@@ -156,6 +156,8 @@ namespace vkcv::rtx {
          * @param[in] vertexData The vertex data.
          */
         void buildBLAS(const vkcv::VertexData &vertexData);
+		
+		void add(const vkcv::GeometryData &geometryData, const vkcv::AccelerationStructureHandle &blas);
 
         /**
          * @brief Build a Top Level Acceleration Structure (TLAS) object from the created
diff --git a/projects/rtx_ambient_occlusion/src/RTX/RTX.cpp b/projects/rtx_ambient_occlusion/src/RTX/RTX.cpp
index 2065d131569101716faf98f3662c4d9ba090a279..4fd33be9bc0b253766cba92e2d1498acac91290b 100644
--- a/projects/rtx_ambient_occlusion/src/RTX/RTX.cpp
+++ b/projects/rtx_ambient_occlusion/src/RTX/RTX.cpp
@@ -1,63 +1,30 @@
 #include "RTX.hpp"
 
 namespace vkcv::rtx {
-
-    RTXModule::RTXModule(Core* core,
+	
+	RTXModule::RTXModule(Core* core,
 						 ASManager* asManager,
-						 const vkcv::VertexData &vertexData,
 						 std::vector<vkcv::DescriptorSetHandle>& descriptorSetHandles){
-        m_core = core;
-        m_asManager = asManager;
-        // build acceleration structures BLAS then TLAS --> see ASManager
-        m_asManager->buildBLAS(vertexData);
-        m_asManager->buildTLAS();
-        RTXDescriptors(descriptorSetHandles);
-    }
-
-
-    RTXModule::~RTXModule()
-    {}
-
-
-    void RTXModule::RTXDescriptors(std::vector<vkcv::DescriptorSetHandle>& descriptorSetHandles)
-    {
-        //TLAS-Descriptor-Write
+		m_core = core;
+		m_asManager = asManager;
+		// build acceleration structures BLAS then TLAS --> see ASManager
+		m_asManager->buildTLAS();
+		RTXDescriptors(descriptorSetHandles);
+	}
+	
+	
+	RTXModule::~RTXModule()
+	{}
+	
+	
+	void RTXModule::RTXDescriptors(std::vector<vkcv::DescriptorSetHandle>& descriptorSetHandles)
+	{
+		//TLAS-Descriptor-Write
 		{
 			vkcv::DescriptorWrites writes;
 			writes.writeAcceleration(1, { m_asManager->getTLAS().vulkanHandle });
 			m_core->writeDescriptorSet(descriptorSetHandles[0], writes);
 		}
-
-        //INDEX & VERTEX BUFFER
-        BottomLevelAccelerationStructure blas = m_asManager->getBLAS(0);//HARD CODED
-
-        //VERTEX BUFFER
-        vk::DescriptorBufferInfo vertexInfo = {};
-        vertexInfo.setBuffer(blas.vertexBuffer.vulkanHandle);
-        vertexInfo.setOffset(0);
-        vertexInfo.setRange(blas.vertexBuffer.deviceSize); //maybe check if size is correct
-
-        vk::WriteDescriptorSet vertexWrite;
-        vertexWrite.setDstSet(m_core->getVulkanDescriptorSet(descriptorSetHandles[0]));
-        vertexWrite.setDstBinding(2);
-        vertexWrite.setDescriptorCount(1);
-        vertexWrite.setDescriptorType(vk::DescriptorType::eStorageBuffer);
-        vertexWrite.setPBufferInfo(&vertexInfo);
-        m_core->getContext().getDevice().updateDescriptorSets(vertexWrite, nullptr);
-
-        //INDEXBUFFER
-        vk::DescriptorBufferInfo indexInfo = {};
-        indexInfo.setBuffer(blas.indexBuffer.vulkanHandle);
-        indexInfo.setOffset(0);
-        indexInfo.setRange(blas.indexBuffer.deviceSize); //maybe check if size is correct
-
-        vk::WriteDescriptorSet indexWrite;
-        indexWrite.setDstSet(m_core->getVulkanDescriptorSet(descriptorSetHandles[0]));
-        indexWrite.setDstBinding(3);
-        indexWrite.setDescriptorCount(1);
-        indexWrite.setDescriptorType(vk::DescriptorType::eStorageBuffer);
-        indexWrite.setPBufferInfo(&indexInfo);
-        m_core->getContext().getDevice().updateDescriptorSets(indexWrite, nullptr);
-    }
+	}
 
 }
\ No newline at end of file
diff --git a/projects/rtx_ambient_occlusion/src/RTX/RTX.hpp b/projects/rtx_ambient_occlusion/src/RTX/RTX.hpp
index 3b731480670ca13a985e1dd07c82fee0f2cc7288..9a71bc170b881cad9a767c63f94e3a6388971aaf 100644
--- a/projects/rtx_ambient_occlusion/src/RTX/RTX.hpp
+++ b/projects/rtx_ambient_occlusion/src/RTX/RTX.hpp
@@ -36,7 +36,6 @@ namespace vkcv::rtx {
          */
         RTXModule(Core* core,
 				  ASManager* asManager,
-				  const vkcv::VertexData &vertexData,
 				  std::vector<vkcv::DescriptorSetHandle>& descriptorSetHandles);
 
         /**
diff --git a/projects/rtx_ambient_occlusion/src/main.cpp b/projects/rtx_ambient_occlusion/src/main.cpp
index 0992d457a294b48590280d06ad8c7321a73f2ee4..1c491097d5cc1db970653c18d18fe3d75ec38451 100644
--- a/projects/rtx_ambient_occlusion/src/main.cpp
+++ b/projects/rtx_ambient_occlusion/src/main.cpp
@@ -55,6 +55,7 @@ int main(int argc, const char** argv) {
 	
 	vkcv::geometry::Teapot teapot (glm::vec3(0.0f), 1.0f);
 	vkcv::VertexData vertexData = teapot.generateVertexData(core);
+	vkcv::GeometryData geometryData = teapot.extractGeometryData(vertexData);
 
 	vkcv::camera::CameraManager cameraManager(core.getWindow(windowHandle));
 	auto camHandle = cameraManager.addCamera(vkcv::camera::ControllerType::TRACKBALL);
@@ -87,14 +88,24 @@ int main(int argc, const char** argv) {
 	vkcv::DescriptorSetHandle rtxShaderDescriptorSet = core.createDescriptorSet(rtxShaderDescriptorSetLayout);
 	descriptorSetHandles.push_back(rtxShaderDescriptorSet);
 	descriptorSetLayoutHandles.push_back(rtxShaderDescriptorSetLayout);
+	
+	vkcv::AccelerationStructureHandle blas = core.createAccelerationStructure({ geometryData });
+	
+	asManager.add(geometryData, blas);
 
 	// init RTXModule
 	vkcv::rtx::RTXModule rtxModule (
 			&core,
 			&asManager,
-			vertexData,
 			descriptorSetHandles
 	);
+	
+	{
+		vkcv::DescriptorWrites writes;
+		writes.writeStorageBuffer(2, geometryData.getVertexBufferBinding().buffer);
+		writes.writeStorageBuffer(3, geometryData.getIndexBuffer());
+		core.writeDescriptorSet(descriptorSetHandles[0], writes);
+	}
 
 	struct RaytracingPushConstantData {
 	    glm::vec4 camera_position;   // as origin for ray generation
diff --git a/src/vkcv/AccelerationStructureManager.cpp b/src/vkcv/AccelerationStructureManager.cpp
index 1cc6cf4659fbaf50e370e7206c88669d9ed2ef18..b0b213d48a052b53b0ee1fb939791760fd0a3e00 100644
--- a/src/vkcv/AccelerationStructureManager.cpp
+++ b/src/vkcv/AccelerationStructureManager.cpp
@@ -36,6 +36,10 @@ namespace vkcv {
 			
 			accelerationStructure.m_accelerationStructure = nullptr;
 		}
+		
+		if (accelerationStructure.m_storageBuffer) {
+			accelerationStructure.m_storageBuffer = BufferHandle();
+		}
 	}
 	
 	const BufferManager &AccelerationStructureManager::getBufferManager() const {
@@ -54,4 +58,227 @@ namespace vkcv {
 		clear();
 	}
 	
+	vk::AccelerationStructureKHR
+	AccelerationStructureManager::getVulkanAccelerationStructure(
+			const AccelerationStructureHandle &handle) const {
+		auto &accelerationStructure = (*this) [handle];
+		return accelerationStructure.m_accelerationStructure;
+	}
+	
+	vk::Buffer AccelerationStructureManager::getVulkanBuffer(
+			const AccelerationStructureHandle &handle) const {
+		auto &accelerationStructure = (*this) [handle];
+		return getBufferManager().getBuffer(accelerationStructure.m_storageBuffer);
+	}
+	
+	static vk::Format getVertexFormat(GeometryVertexType vertexType) {
+		switch (vertexType) {
+			case GeometryVertexType::POSITION_FLOAT3:
+				return vk::Format::eR32G32B32Sfloat;
+			case GeometryVertexType::UNDEFINED:
+				return vk::Format::eUndefined;
+			default:
+				vkcv_log(LogLevel::ERROR, "unknown Enum");
+				return vk::Format::eUndefined;
+		}
+	}
+	
+	static vk::IndexType getIndexType(IndexBitCount indexByteCount) {
+		switch (indexByteCount) {
+			case IndexBitCount::Bit8:
+				return vk::IndexType::eUint8EXT;
+			case IndexBitCount::Bit16:
+				return vk::IndexType::eUint16;
+			case IndexBitCount::Bit32:
+				return vk::IndexType::eUint32;
+			default:
+				vkcv_log(LogLevel::ERROR, "unknown Enum");
+				return vk::IndexType::eNoneKHR;
+		}
+	}
+	
+	AccelerationStructureHandle AccelerationStructureManager::createAccelerationStructure(
+			const std::vector<GeometryData> &geometryData) {
+		std::vector<vk::AccelerationStructureGeometryKHR> geometries;
+		std::vector<vk::AccelerationStructureBuildGeometryInfoKHR> geometryInfos;
+		std::vector<std::vector<vk::AccelerationStructureBuildRangeInfoKHR>> rangeInfos;
+		
+		auto& bufferManager = getBufferManager();
+		
+		vk::DeviceSize accelerationStructureSize = 0;
+		vk::DeviceSize scratchBufferSize = 0;
+		
+		const auto &dynamicDispatch = getCore().getContext().getDispatchLoaderDynamic();
+		
+		geometries.reserve(geometryData.size());
+		
+		for (const GeometryData &data : geometryData) {
+			const auto vertexBufferAddress = bufferManager.getBufferDeviceAddress(
+					data.getVertexBufferBinding().buffer
+			) + data.getVertexBufferBinding().offset;
+			
+			const auto indexBufferAddress = bufferManager.getBufferDeviceAddress(
+					data.getIndexBuffer()
+			);
+			
+			const auto vertexStride = data.getVertexStride();
+			const auto vertexBufferSize = bufferManager.getBufferSize(
+					data.getVertexBufferBinding().buffer
+			);
+			
+			const auto vertexCount = (vertexBufferSize / vertexStride);
+			
+			const vk::Format vertexFormat = getVertexFormat(data.getGeometryVertexType());
+			
+			const vk::IndexType indexType = getIndexType(data.getIndexBitCount());
+			
+			const vk::AccelerationStructureGeometryTrianglesDataKHR asTrianglesData (
+					vertexFormat,
+					vertexBufferAddress,
+					vertexStride,
+					static_cast<uint32_t>(vertexCount - 1),
+					indexType,
+					indexBufferAddress,
+					{}
+			);
+			
+			const vk::AccelerationStructureGeometryKHR asGeometry (
+					vk::GeometryTypeKHR::eTriangles,
+					asTrianglesData,
+					vk::GeometryFlagBitsKHR::eOpaque
+			);
+			
+			geometries.push_back(asGeometry);
+		}
+		
+		geometryInfos.reserve(geometries.size());
+		rangeInfos.reserve(geometries.size());
+		
+		for (size_t i = 0; i < geometries.size(); i++) {
+			const vk::AccelerationStructureBuildGeometryInfoKHR asBuildGeometryInfo(
+					vk::AccelerationStructureTypeKHR::eBottomLevel,
+					vk::BuildAccelerationStructureFlagBitsKHR::ePreferFastTrace,
+					vk::BuildAccelerationStructureModeKHR::eBuild,
+					{},
+					{},
+					1,
+					&(geometries[i])
+			);
+			
+			geometryInfos.push_back(asBuildGeometryInfo);
+			
+			const vk::AccelerationStructureBuildRangeInfoKHR asBuildRangeInfo (
+					static_cast<uint32_t>(geometryData[i].getCount() / 3),
+					0,
+					0,
+					0
+			);
+			
+			rangeInfos.push_back({ asBuildRangeInfo });
+			
+			vk::AccelerationStructureBuildSizesInfoKHR asBuildSizesInfo;
+			getCore().getContext().getDevice().getAccelerationStructureBuildSizesKHR(
+					vk::AccelerationStructureBuildTypeKHR::eDevice,
+					&(asBuildGeometryInfo),
+					&(asBuildRangeInfo.primitiveCount),
+					&(asBuildSizesInfo),
+					dynamicDispatch
+			);
+			
+			accelerationStructureSize += asBuildSizesInfo.accelerationStructureSize;
+			scratchBufferSize = std::max(scratchBufferSize, asBuildSizesInfo.buildScratchSize);
+		}
+		
+		const BufferHandle &asStorageBuffer = bufferManager.createBuffer(
+				typeGuard<uint8_t>(),
+				BufferType::ACCELERATION_STRUCTURE_STORAGE,
+				BufferMemoryType::DEVICE_LOCAL,
+				accelerationStructureSize,
+				false
+		);
+		
+		vk::PhysicalDeviceAccelerationStructurePropertiesKHR accelerationStructureProperties;
+		
+		vk::PhysicalDeviceProperties2 physicalProperties2;
+		physicalProperties2.pNext = &accelerationStructureProperties;
+		
+		getCore().getContext().getPhysicalDevice().getProperties2(&physicalProperties2);
+		
+		const auto minScratchAlignment = (
+				accelerationStructureProperties.minAccelerationStructureScratchOffsetAlignment
+		);
+		
+		const BufferHandle &asScratchBuffer = bufferManager.createBuffer(
+				vkcv::TypeGuard(minScratchAlignment),
+				BufferType::STORAGE,
+				BufferMemoryType::DEVICE_LOCAL,
+				(scratchBufferSize + minScratchAlignment - 1) / minScratchAlignment,
+				false
+		);
+		
+		if ((!asStorageBuffer) || (!asScratchBuffer)) {
+			return {};
+		}
+		
+		const vk::AccelerationStructureCreateInfoKHR asCreateInfo (
+				vk::AccelerationStructureCreateFlagsKHR(),
+				bufferManager.getBuffer(asStorageBuffer),
+				0,
+				accelerationStructureSize,
+				vk::AccelerationStructureTypeKHR::eBottomLevel
+		);
+		
+		vk::AccelerationStructureKHR accelerationStructure;
+		const vk::Result result = getCore().getContext().getDevice().createAccelerationStructureKHR(
+				&asCreateInfo,
+				nullptr,
+				&accelerationStructure,
+				dynamicDispatch
+		);
+		
+		if (result != vk::Result::eSuccess) {
+			return {};
+		}
+		
+		vk::DeviceAddress scratchBufferAddress = bufferManager.getBufferDeviceAddress(
+				asScratchBuffer
+		);
+		
+		if (scratchBufferAddress % minScratchAlignment != 0) {
+			scratchBufferAddress += (
+					minScratchAlignment - (scratchBufferAddress % minScratchAlignment)
+			);
+		}
+		
+		for (auto& geometryInfo : geometryInfos) {
+			geometryInfo.setDstAccelerationStructure(accelerationStructure);
+			geometryInfo.setScratchData(scratchBufferAddress);
+		}
+		
+		std::vector<vk::AccelerationStructureBuildRangeInfoKHR*> pRangeInfos;
+		pRangeInfos.resize(rangeInfos.size());
+		
+		for (size_t i = 0; i < rangeInfos.size(); i++) {
+			pRangeInfos[i] = rangeInfos[i].data();
+		}
+		
+		auto cmdStream = getCore().createCommandStream(vkcv::QueueType::Compute);
+		
+		getCore().recordCommandsToStream(
+				cmdStream,
+				[&geometryInfos, &pRangeInfos, &dynamicDispatch](
+						const vk::CommandBuffer &cmdBuffer) {
+			cmdBuffer.buildAccelerationStructuresKHR(
+					static_cast<uint32_t>(geometryInfos.size()),
+					geometryInfos.data(),
+					pRangeInfos.data(),
+					dynamicDispatch
+			);
+		}, nullptr);
+		
+		getCore().submitCommandStream(cmdStream, false);
+		
+		return add({ accelerationStructure, asStorageBuffer });
+	}
+	
 }
diff --git a/src/vkcv/AccelerationStructureManager.hpp b/src/vkcv/AccelerationStructureManager.hpp
index fff2b12521c6100c6f14796e5fba128039b2c93b..155b576761c4a47e6480404fe5b08fd55bf229d0 100644
--- a/src/vkcv/AccelerationStructureManager.hpp
+++ b/src/vkcv/AccelerationStructureManager.hpp
@@ -12,12 +12,15 @@
 #include <vulkan/vulkan.hpp>
 
 #include "BufferManager.hpp"
+
 #include "vkcv/Handles.hpp"
+#include "vkcv/GeometryData.hpp"
 
 namespace vkcv {
 	
 	struct AccelerationStructureEntry {
 		vk::AccelerationStructureKHR m_accelerationStructure;
+		vkcv::BufferHandle m_storageBuffer;
 	};
 	
 	/**
@@ -56,6 +59,14 @@ namespace vkcv {
 		
 		~AccelerationStructureManager() noexcept override;
 		
+		[[nodiscard]] vk::AccelerationStructureKHR getVulkanAccelerationStructure(
+				const AccelerationStructureHandle &handle) const;
+		
+		[[nodiscard]] vk::Buffer getVulkanBuffer(const AccelerationStructureHandle &handle) const;
+		
+		[[nodiscard]] AccelerationStructureHandle createAccelerationStructure(
+				const std::vector<GeometryData> &geometryData);
+		
 	};
 	
 }
\ No newline at end of file
diff --git a/src/vkcv/BufferManager.cpp b/src/vkcv/BufferManager.cpp
index a6c15b7b3f9ea15bb8a1f969d02b081d64ecff3f..b77325884d5ab636930c3fe5e862bf16ccce47ca 100644
--- a/src/vkcv/BufferManager.cpp
+++ b/src/vkcv/BufferManager.cpp
@@ -56,6 +56,15 @@ namespace vkcv {
 		} else {
 			m_resizableBar = false;
 		}
+		
+		m_shaderDeviceAddress = getCore().getContext().getFeatureManager().checkFeatures<
+		        vk::PhysicalDeviceBufferDeviceAddressFeatures
+		>(
+				vk::StructureType::ePhysicalDeviceBufferDeviceAddressFeatures,
+				[](const vk::PhysicalDeviceBufferDeviceAddressFeatures &features) {
+					return features.bufferDeviceAddress;
+				}
+		);
 
 		m_stagingBuffer = createBuffer(
 				TypeGuard(1),
@@ -96,6 +105,7 @@ namespace vkcv {
 	BufferManager::BufferManager() noexcept :
 		HandleManager<BufferEntry, BufferHandle>(),
 		m_resizableBar(false),
+		m_shaderDeviceAddress(false),
 		m_stagingBuffer(BufferHandle()) {}
 
 	BufferManager::~BufferManager() noexcept {
@@ -110,7 +120,9 @@ namespace vkcv {
 
 		switch (type) {
 		case BufferType::VERTEX:
-			usageFlags = vk::BufferUsageFlagBits::eVertexBuffer;
+			usageFlags = vk::BufferUsageFlagBits::eVertexBuffer
+						| vk::BufferUsageFlagBits::eStorageBuffer
+						| vk::BufferUsageFlagBits::eAccelerationStructureBuildInputReadOnlyKHR;
 			break;
 		case BufferType::UNIFORM:
 			usageFlags = vk::BufferUsageFlagBits::eUniformBuffer;
@@ -123,23 +135,22 @@ namespace vkcv {
 						| vk::BufferUsageFlagBits::eTransferDst;
 			break;
 		case BufferType::INDEX:
-			usageFlags = vk::BufferUsageFlagBits::eIndexBuffer;
+			usageFlags = vk::BufferUsageFlagBits::eIndexBuffer
+						| vk::BufferUsageFlagBits::eStorageBuffer
+						| vk::BufferUsageFlagBits::eAccelerationStructureBuildInputReadOnlyKHR;
 			break;
 		case BufferType::INDIRECT:
 			usageFlags = vk::BufferUsageFlagBits::eStorageBuffer
 						| vk::BufferUsageFlagBits::eIndirectBuffer;
 			break;
 		case BufferType::SHADER_BINDING:
-			usageFlags = vk::BufferUsageFlagBits::eShaderBindingTableKHR
-						| vk::BufferUsageFlagBits::eShaderDeviceAddress;
+			usageFlags = vk::BufferUsageFlagBits::eShaderBindingTableKHR;
 			break;
 		case BufferType::ACCELERATION_STRUCTURE_INPUT:
-			usageFlags = vk::BufferUsageFlagBits::eAccelerationStructureBuildInputReadOnlyKHR
-						| vk::BufferUsageFlagBits::eShaderDeviceAddress;
+			usageFlags = vk::BufferUsageFlagBits::eAccelerationStructureBuildInputReadOnlyKHR;
 			break;
 		case BufferType::ACCELERATION_STRUCTURE_STORAGE:
 			usageFlags = vk::BufferUsageFlagBits::eAccelerationStructureStorageKHR
-						 | vk::BufferUsageFlagBits::eShaderDeviceAddress
 						 | vk::BufferUsageFlagBits::eStorageBuffer;
 			break;
 		default:
@@ -154,6 +165,10 @@ namespace vkcv {
 		if (readable) {
 			usageFlags |= vk::BufferUsageFlagBits::eTransferSrc;
 		}
+		
+		if (m_shaderDeviceAddress) {
+			usageFlags |= vk::BufferUsageFlagBits::eShaderDeviceAddress;
+		}
 
 		const vma::Allocator &allocator = getCore().getContext().getAllocator();
 
diff --git a/src/vkcv/BufferManager.hpp b/src/vkcv/BufferManager.hpp
index 620e062bb7ada4ede0047503456c250e243ee0ad..818c907c1981cab94a4ac932e18f5517c822f540 100644
--- a/src/vkcv/BufferManager.hpp
+++ b/src/vkcv/BufferManager.hpp
@@ -45,6 +45,8 @@ namespace vkcv {
 		std::allocator<char> m_allocator;
 		
 		bool m_resizableBar;
+		bool m_shaderDeviceAddress;
+		
 		BufferHandle m_stagingBuffer;
 
 		bool init(Core &core) override;
diff --git a/src/vkcv/Core.cpp b/src/vkcv/Core.cpp
index b063e0743b8ddc362086ce97d51b8db49f5d4ecc..db8cdf53b1a8929e7650e33687cbaf6d601d07b7 100644
--- a/src/vkcv/Core.cpp
+++ b/src/vkcv/Core.cpp
@@ -358,7 +358,7 @@ namespace vkcv {
 		cmdBuffer.setScissor(0, 1, &dynamicScissor);
 	}
 
-	vk::IndexType getIndexType(IndexBitCount indexByteCount) {
+	static vk::IndexType getIndexType(IndexBitCount indexByteCount) {
 		switch (indexByteCount) {
 		case IndexBitCount::Bit8:
 			return vk::IndexType::eUint8EXT;
@@ -1350,5 +1350,17 @@ namespace vkcv {
 	vk::DeviceMemory Core::getVulkanDeviceMemory(const ImageHandle &handle) const {
 		return m_ImageManager->getVulkanDeviceMemory(handle);
 	}
-
+	
+	AccelerationStructureHandle Core::createAccelerationStructure(const std::vector<GeometryData> &geometryData) {
+		return m_AccelerationStructureManager->createAccelerationStructure(geometryData);
+	}
+	
+	vk::AccelerationStructureKHR Core::getVulkanAccelerationStructure(const AccelerationStructureHandle &handle) const {
+		return m_AccelerationStructureManager->getVulkanAccelerationStructure(handle);
+	}
+	
+	vk::Buffer Core::getVulkanBuffer(const vkcv::AccelerationStructureHandle &handle) const {
+		return m_AccelerationStructureManager->getVulkanBuffer(handle);
+	}
+	
 } // namespace vkcv
diff --git a/src/vkcv/GeometryData.cpp b/src/vkcv/GeometryData.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..6a5cc5771817de4ae9624a3b80c34f5869480e60
--- /dev/null
+++ b/src/vkcv/GeometryData.cpp
@@ -0,0 +1,61 @@
+
+#include "vkcv/GeometryData.hpp"
+
+namespace vkcv {
+	
+	GeometryData::GeometryData() :
+		m_vertexBinding({}),
+		m_vertexStride(0),
+		m_vertexType(GeometryVertexType::UNDEFINED),
+		m_indices(),
+		m_indexBitCount(IndexBitCount::Bit16),
+		m_count(0) {}
+	
+	GeometryData::GeometryData(const VertexBufferBinding &binding,
+							   uint32_t stride,
+							   GeometryVertexType geometryVertexType) :
+		m_vertexBinding(binding),
+		m_vertexStride(stride),
+		m_vertexType(geometryVertexType),
+		m_indices(),
+		m_indexBitCount(IndexBitCount::Bit16),
+		m_count(0) {}
+	
+	bool GeometryData::isValid() const {
+		return m_vertexType == GeometryVertexType::UNDEFINED;
+	}
+	
+	const VertexBufferBinding &GeometryData::getVertexBufferBinding() const {
+		return m_vertexBinding;
+	}
+	
+	uint32_t GeometryData::getVertexStride() const {
+		return m_vertexStride;
+	}
+	
+	GeometryVertexType GeometryData::getGeometryVertexType() const {
+		return m_vertexType;
+	}
+	
+	void GeometryData::setIndexBuffer(const BufferHandle &indices, IndexBitCount indexBitCount) {
+		m_indices = indices;
+		m_indexBitCount = indexBitCount;
+	}
+	
+	const BufferHandle &GeometryData::getIndexBuffer() const {
+		return m_indices;
+	}
+	
+	IndexBitCount GeometryData::getIndexBitCount() const {
+		return m_indexBitCount;
+	}
+	
+	void GeometryData::setCount(size_t count) {
+		m_count = count;
+	}
+	
+	size_t GeometryData::getCount() const {
+		return m_count;
+	}
+	
+}
diff --git a/src/vkcv/RayTracingPipelineManager.cpp b/src/vkcv/RayTracingPipelineManager.cpp
index f33fd4543766c07a341c568582341864483bafd8..70f05b98f719112befafd103ab3b24549a398e79 100644
--- a/src/vkcv/RayTracingPipelineManager.cpp
+++ b/src/vkcv/RayTracingPipelineManager.cpp
@@ -391,8 +391,10 @@ namespace vkcv {
 			return {};
 		}
 		
+		const auto baseAlignment = rayTracingPipelineProperties.shaderGroupBaseAlignment;
+		
 		const size_t tableSizeAlignment = std::max(
-				rayTracingPipelineProperties.shaderGroupBaseAlignment,
+				baseAlignment,
 				rayTracingPipelineProperties.shaderGroupHandleSize
 		);
 		
@@ -400,14 +402,27 @@ namespace vkcv {
 				tableSizeAlignment * shaderGroups.size()
 		);
 		
-		const BufferHandle &shaderBindingTable = getCore().createBuffer(
+		const BufferHandle &shaderBindingTable = bufferManager.createBuffer(
+				TypeGuard(baseAlignment),
 				BufferType::SHADER_BINDING,
-				shaderBindingTableSize
+				BufferMemoryType::DEVICE_LOCAL,
+				(shaderBindingTableSize + baseAlignment - 1) / baseAlignment,
+				false
+		);
+		
+		vk::DeviceAddress bufferBaseAddress = bufferManager.getBufferDeviceAddress(
+				shaderBindingTable
 		);
 		
+		size_t bufferBaseOffset = 0;
+		if (bufferBaseAddress % baseAlignment != 0) {
+			bufferBaseOffset = (baseAlignment - (bufferBaseAddress % baseAlignment));
+			bufferBaseAddress += bufferBaseOffset;
+		}
+		
 		void* mappedBindingTable = bufferManager.mapBuffer(
 				shaderBindingTable,
-				0,
+				bufferBaseOffset,
 				shaderBindingTableSize
 		);
 		
@@ -429,10 +444,6 @@ namespace vkcv {
 		
 		bufferManager.unmapBuffer(shaderBindingTable);
 		
-		const vk::DeviceAddress bufferBaseAddress = bufferManager.getBufferDeviceAddress(
-				shaderBindingTable
-		);
-		
 		vk::StridedDeviceAddressRegionKHR rayGenAddress {};
 		vk::StridedDeviceAddressRegionKHR rayMissAddress {};
 		vk::StridedDeviceAddressRegionKHR rayHitAddress {};