From af5d1d149f58afd1bd17e547be3d07ed91444562 Mon Sep 17 00:00:00 2001 From: Tobias Frisch <tfrisch@uni-koblenz.de> Date: Tue, 29 Nov 2022 18:48:11 +0100 Subject: [PATCH] Add sponza as example scene for ray tracing Signed-off-by: Tobias Frisch <tfrisch@uni-koblenz.de> --- modules/scene/include/vkcv/scene/Mesh.hpp | 11 ++- modules/scene/include/vkcv/scene/Node.hpp | 28 +++++++- modules/scene/include/vkcv/scene/Scene.hpp | 28 +++++++- modules/scene/src/vkcv/scene/Mesh.cpp | 11 ++- modules/scene/src/vkcv/scene/Node.cpp | 45 +++++++++++- modules/scene/src/vkcv/scene/Scene.cpp | 35 ++++++++- projects/rt_ambient_occlusion/CMakeLists.txt | 2 - .../resources/Sponza/Sponza.bin | 3 + .../resources/Sponza/Sponza.gltf | 3 + .../resources/shaders/ambientOcclusion.rchit | 71 +++++++++++++------ .../resources/shaders/ambientOcclusion.rgen | 40 +++++------ .../resources/shaders/ambientOcclusion.rmiss | 1 - projects/rt_ambient_occlusion/src/main.cpp | 71 ++++++++++++++++--- src/vkcv/AccelerationStructureManager.cpp | 65 +++++++++-------- 14 files changed, 315 insertions(+), 99 deletions(-) create mode 100644 projects/rt_ambient_occlusion/resources/Sponza/Sponza.bin create mode 100644 projects/rt_ambient_occlusion/resources/Sponza/Sponza.gltf diff --git a/modules/scene/include/vkcv/scene/Mesh.hpp b/modules/scene/include/vkcv/scene/Mesh.hpp index d0eb3597..a0ad087f 100644 --- a/modules/scene/include/vkcv/scene/Mesh.hpp +++ b/modules/scene/include/vkcv/scene/Mesh.hpp @@ -20,6 +20,13 @@ namespace vkcv::scene { */ typedef typename event_function<const glm::mat4&, const glm::mat4&, PushConstants&, vkcv::Drawcall&>::type RecordMeshDrawcallFunction; + /** + * An event function type to be called on per geometry while creating an + * acceleration structure using the given instance index and geometry index + * of each geometry in a bottom-level acceleration structure. + */ + typedef typename event_function<size_t, size_t, const vkcv::GeometryData&, const glm::mat4&>::type ProcessGeometryFunction; + class Node; /** @@ -92,9 +99,11 @@ namespace vkcv::scene { * * @param[in,out] core Core instance * @param[out] accelerationStructures List of acceleration structures + * @param[in] process Geometry processing event function */ void appendAccelerationStructures(Core& core, - std::vector<AccelerationStructureHandle>&accelerationStructures) const; + std::vector<AccelerationStructureHandle>&accelerationStructures, + const ProcessGeometryFunction &process) const; /** * Return the amount of drawcalls of the mesh diff --git a/modules/scene/include/vkcv/scene/Node.hpp b/modules/scene/include/vkcv/scene/Node.hpp index ff38328a..f1cd316f 100644 --- a/modules/scene/include/vkcv/scene/Node.hpp +++ b/modules/scene/include/vkcv/scene/Node.hpp @@ -50,6 +50,30 @@ namespace vkcv::scene { * @param[in,out] scene Scene */ explicit Node(Scene& scene); + + /** + * Return the amount of nodes managed by this node and its children. + * + * @return Amount of nodes + */ + [[nodiscard]] + size_t getNodeCount() const; + + /** + * Return the amount of meshes managed by this node and its children. + * + * @return Amount of meshes + */ + [[nodiscard]] + size_t getMeshCount() const; + + /** + * Return the amount of mesh parts managed by this node and its children. + * + * @return Amount of mesh parts + */ + [[nodiscard]] + size_t getMeshPartCount() const; /** * Add a given mesh to this node for drawcall recording. @@ -88,9 +112,11 @@ namespace vkcv::scene { * * @param[in,out] core Core instance * @param[out] accelerationStructures List of acceleration structures + * @param[in] process Geometry processing event function */ void appendAccelerationStructures(Core& core, - std::vector<AccelerationStructureHandle>&accelerationStructures) const; + std::vector<AccelerationStructureHandle>&accelerationStructures, + const ProcessGeometryFunction &process) const; /** * Splits child nodes into tree based graphs of nodes diff --git a/modules/scene/include/vkcv/scene/Scene.hpp b/modules/scene/include/vkcv/scene/Scene.hpp index 7c1806e5..a6feb833 100644 --- a/modules/scene/include/vkcv/scene/Scene.hpp +++ b/modules/scene/include/vkcv/scene/Scene.hpp @@ -148,6 +148,30 @@ namespace vkcv::scene { * @return Reference to this scene */ Scene& operator=(Scene&& other) noexcept; + + /** + * Return the amount of nodes managed by this scene in total. + * + * @return Amount of nodes + */ + [[nodiscard]] + size_t getNodeCount() const; + + /** + * Return the amount of meshes managed by this scene in total. + * + * @return Amount of meshes + */ + [[nodiscard]] + size_t getMeshCount() const; + + /** + * Return the amount of mesh parts managed by this scene in total. + * + * @return Amount of mesh parts + */ + [[nodiscard]] + size_t getMeshPartCount() const; /** * Return the amount of materials managed by this scene. @@ -193,9 +217,11 @@ namespace vkcv::scene { * which contains all of its meshes as bottom-level acceleration structures with * its given geometry. * + * @param[in] process Geometry processing event function * @return Acceleration structure */ - AccelerationStructureHandle createAccelerationStructure() const; + AccelerationStructureHandle createAccelerationStructure( + const ProcessGeometryFunction &process = nullptr) const; /** * Instantiation function to create a new scene instance. diff --git a/modules/scene/src/vkcv/scene/Mesh.cpp b/modules/scene/src/vkcv/scene/Mesh.cpp index 4accf44b..03eb8a59 100644 --- a/modules/scene/src/vkcv/scene/Mesh.cpp +++ b/modules/scene/src/vkcv/scene/Mesh.cpp @@ -124,7 +124,8 @@ namespace vkcv::scene { } void Mesh::appendAccelerationStructures(Core &core, - std::vector<AccelerationStructureHandle> &accelerationStructures) const { + std::vector<AccelerationStructureHandle> &accelerationStructures, + const ProcessGeometryFunction &process) const { std::vector<GeometryData> geometryData; geometryData.reserve(m_parts.size()); @@ -149,7 +150,15 @@ namespace vkcv::scene { ); if (handle) { + const size_t instanceIndex = accelerationStructures.size(); + accelerationStructures.push_back(handle); + + if (process) { + for (size_t i = 0; i < geometryData.size(); i++) { + process(instanceIndex, i, geometryData[i], m_transform); + } + } } } diff --git a/modules/scene/src/vkcv/scene/Node.cpp b/modules/scene/src/vkcv/scene/Node.cpp index 550a02c0..5ccf89c0 100644 --- a/modules/scene/src/vkcv/scene/Node.cpp +++ b/modules/scene/src/vkcv/scene/Node.cpp @@ -58,6 +58,44 @@ namespace vkcv::scene { return *this; } + size_t Node::getNodeCount() const { + size_t count = 1; + + for (const auto& node : m_nodes) { + count += node.getNodeCount(); + } + + return count; + } + + size_t Node::getMeshCount() const { + size_t count = 0; + + for (auto& mesh : m_meshes) { + count++; + } + + for (const auto& node : m_nodes) { + count += node.getMeshCount(); + } + + return count; + } + + size_t Node::getMeshPartCount() const { + size_t count = 0; + + for (auto& mesh : m_meshes) { + count += mesh.m_parts.size(); + } + + for (const auto& node : m_nodes) { + count += node.getMeshPartCount(); + } + + return count; + } + void Node::addMesh(const Mesh& mesh) { if (m_meshes.empty()) { m_bounds = mesh.getBounds(); @@ -110,13 +148,14 @@ namespace vkcv::scene { } void Node::appendAccelerationStructures(Core& core, - std::vector<AccelerationStructureHandle> &accelerationStructures) const { + std::vector<AccelerationStructureHandle> &accelerationStructures, + const ProcessGeometryFunction &process) const { for (auto& mesh : m_meshes) { - mesh.appendAccelerationStructures(core, accelerationStructures); + mesh.appendAccelerationStructures(core, accelerationStructures, process); } for (auto& node : m_nodes) { - node.appendAccelerationStructures(core, accelerationStructures); + node.appendAccelerationStructures(core, accelerationStructures, process); } } diff --git a/modules/scene/src/vkcv/scene/Scene.cpp b/modules/scene/src/vkcv/scene/Scene.cpp index abd0774e..b2b65a4a 100644 --- a/modules/scene/src/vkcv/scene/Scene.cpp +++ b/modules/scene/src/vkcv/scene/Scene.cpp @@ -99,6 +99,36 @@ namespace vkcv::scene { } } + size_t Scene::getNodeCount() const { + size_t count = 0; + + for (const auto& node : m_nodes) { + count += node.getNodeCount(); + } + + return count; + } + + size_t Scene::getMeshCount() const { + size_t count = 0; + + for (const auto& node : m_nodes) { + count += node.getMeshCount(); + } + + return count; + } + + size_t Scene::getMeshPartCount() const { + size_t count = 0; + + for (const auto& node : m_nodes) { + count += node.getMeshPartCount(); + } + + return count; + } + size_t Scene::getMaterialCount() const { return m_materials.size(); } @@ -150,11 +180,12 @@ namespace vkcv::scene { m_core->recordEndDebugLabel(cmdStream); } - AccelerationStructureHandle Scene::createAccelerationStructure() const { + AccelerationStructureHandle Scene::createAccelerationStructure( + const ProcessGeometryFunction &process) const { std::vector<AccelerationStructureHandle> accelerationStructures; for (auto& node : m_nodes) { - node.appendAccelerationStructures(*m_core, accelerationStructures); + node.appendAccelerationStructures(*m_core, accelerationStructures, process); } return m_core->createAccelerationStructure(accelerationStructures); diff --git a/projects/rt_ambient_occlusion/CMakeLists.txt b/projects/rt_ambient_occlusion/CMakeLists.txt index 6ed4c40c..ce4a2fce 100644 --- a/projects/rt_ambient_occlusion/CMakeLists.txt +++ b/projects/rt_ambient_occlusion/CMakeLists.txt @@ -14,7 +14,6 @@ target_include_directories(rt_ambient_occlusion SYSTEM BEFORE PRIVATE ${vkcv_includes} ${vkcv_asset_loader_include} ${vkcv_camera_include} - ${vkcv_geometry_include} ${vkcv_scene_include} ${vkcv_shader_compiler_include} ${vkcv_scene_include}) @@ -24,7 +23,6 @@ target_link_libraries(rt_ambient_occlusion vkcv ${vkcv_libraries} vkcv_asset_loader ${vkcv_asset_loader_libraries} vkcv_camera - vkcv_geometry vkcv_scene vkcv_shader_compiler vkcv_scene) diff --git a/projects/rt_ambient_occlusion/resources/Sponza/Sponza.bin b/projects/rt_ambient_occlusion/resources/Sponza/Sponza.bin new file mode 100644 index 00000000..cfedd26c --- /dev/null +++ b/projects/rt_ambient_occlusion/resources/Sponza/Sponza.bin @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:4b809f7a17687dc99e6f41ca1ea32c06eded8779bf34d16f1f565d750b0ffd68 +size 6347696 diff --git a/projects/rt_ambient_occlusion/resources/Sponza/Sponza.gltf b/projects/rt_ambient_occlusion/resources/Sponza/Sponza.gltf new file mode 100644 index 00000000..a220d7fe --- /dev/null +++ b/projects/rt_ambient_occlusion/resources/Sponza/Sponza.gltf @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:36d0bfcec05a3a66f11bcd22eb47f2cbb7a47f53552bb1f8132b4e10b5231ec9 +size 705584 diff --git a/projects/rt_ambient_occlusion/resources/shaders/ambientOcclusion.rchit b/projects/rt_ambient_occlusion/resources/shaders/ambientOcclusion.rchit index 9bc4f664..9c8a2403 100644 --- a/projects/rt_ambient_occlusion/resources/shaders/ambientOcclusion.rchit +++ b/projects/rt_ambient_occlusion/resources/shaders/ambientOcclusion.rchit @@ -1,54 +1,81 @@ #version 460 #extension GL_EXT_ray_tracing : require +#extension GL_EXT_nonuniform_qualifier : enable #extension GL_EXT_scalar_block_layout : require #extension GL_EXT_shader_16bit_storage : require +#extension GL_EXT_shader_explicit_arithmetic_types_int64 : require +#extension GL_EXT_buffer_reference2 : require + hitAttributeEXT vec2 attributes; layout(location = 0) rayPayloadInEXT Payload { float hitSky; vec3 worldPosition; vec3 worldNormal; - uvec4 hit; } payload; -layout(binding = 2, set = 0, scalar) buffer rtVertices -{ - float vertices[]; +layout(buffer_reference, scalar) buffer Vertices { + float v[]; +}; + +layout(buffer_reference, scalar) buffer Indices { + uint16_t i[]; + //uint i[]; +}; + +struct ObjDesc { + uint64_t vertexAddress; + uint64_t indexAddress; + uint vertexStride; + uint pad0; + uint pad1; + uint pad2; + mat4 transform; +}; + +layout(binding = 2, set = 0, scalar) buffer rtObjects { + ObjDesc objects[]; }; -layout(binding = 3, set = 0, scalar) buffer rtIndices -{ - uint16_t indices[]; +layout(binding = 3, set = 0, scalar) buffer rtInstanceCount { + int instanceCount; }; void main() { - payload.worldPosition = vec3(1.0, 0.0, 0.5); + int instanceIndex = gl_InstanceID + gl_GeometryIndexEXT * instanceCount; - payload.hit = uvec4( - gl_PrimitiveID, - gl_InstanceID, - gl_InstanceCustomIndexEXT, - gl_GeometryIndexEXT - ); + if (instanceIndex >= objects.length()) { + payload.hitSky = 1.0f; + return; + } + + ObjDesc obj = objects[nonuniformEXT(instanceIndex)]; + Indices indices = Indices(obj.indexAddress); + Vertices vertices = Vertices(obj.vertexAddress); - ivec3 indicesVec = ivec3(indices[3 * gl_PrimitiveID + 0], indices[3 * gl_PrimitiveID + 1], indices[3 * gl_PrimitiveID + 2]); + const uint stride = obj.vertexStride; + + ivec3 indicesVec = ivec3( + indices.i[3 * gl_PrimitiveID + 0], + indices.i[3 * gl_PrimitiveID + 1], + indices.i[3 * gl_PrimitiveID + 2] + ); // current triangle - const vec3 v0 = vec3(vertices[3 * indicesVec.x + 0],vertices[3 * indicesVec.x + 1],vertices[3 * indicesVec.x + 2]); - const vec3 v1 = vec3(vertices[3 * indicesVec.y + 0],vertices[3 * indicesVec.y + 1],vertices[3 * indicesVec.y + 2]); - const vec3 v2 = vec3(vertices[3 * indicesVec.z + 0],vertices[3 * indicesVec.z + 1],vertices[3 * indicesVec.z + 2]); + const vec3 v0 = vec3(vertices.v[stride * indicesVec.x + 0], vertices.v[stride * indicesVec.x + 1], vertices.v[stride * indicesVec.x + 2]); + const vec3 v1 = vec3(vertices.v[stride * indicesVec.y + 0], vertices.v[stride * indicesVec.y + 1], vertices.v[stride * indicesVec.y + 2]); + const vec3 v2 = vec3(vertices.v[stride * indicesVec.z + 0], vertices.v[stride * indicesVec.z + 1], vertices.v[stride * indicesVec.z + 2]); // use barycentric coordinates to compute intersection const vec3 barycentrics = vec3(1.0 - attributes.x - attributes.y, attributes.xy); const vec3 objectPosition = v0 * barycentrics.x + v1 * barycentrics.y + v2 * barycentrics.z; - payload.worldPosition = gl_ObjectToWorldEXT * vec4(objectPosition, 1.0); + payload.worldPosition = vec3(gl_ObjectToWorldEXT * obj.transform * vec4(objectPosition, 1)); const vec3 objectNormal = cross(v1 - v0, v2 - v0); + const vec3 worldNormal = normalize(vec3(objectNormal * gl_WorldToObjectEXT * obj.transform)); - payload.worldNormal = normalize((objectNormal * gl_WorldToObjectEXT).xyz); - payload.worldNormal = faceforward(payload.worldNormal, gl_WorldRayDirectionEXT, payload.worldNormal); - + payload.worldNormal = worldNormal; payload.hitSky = 0.0f; } diff --git a/projects/rt_ambient_occlusion/resources/shaders/ambientOcclusion.rgen b/projects/rt_ambient_occlusion/resources/shaders/ambientOcclusion.rgen index 41061e0e..f0646e77 100644 --- a/projects/rt_ambient_occlusion/resources/shaders/ambientOcclusion.rgen +++ b/projects/rt_ambient_occlusion/resources/shaders/ambientOcclusion.rgen @@ -8,7 +8,6 @@ layout(location = 0) rayPayloadEXT Payload { float hitSky; vec3 worldPosition; vec3 worldNormal; - uvec4 hit; } payload; layout(binding = 0, set = 0, rgba16) uniform image2D outImg; // the output image -> maybe use 16 bit values? @@ -50,7 +49,7 @@ vec2 random(){ * @param[in,out] pos The position of intersection * @param[in,out] norm The normal at the position of intersection */ -void TraceCameraRay(out bool hitSky, out vec3 pos, out vec3 norm, out uvec4 hit){ +void TraceCameraRay(out bool hitSky, out vec3 pos, out vec3 norm) { // Use a camera model to generate a ray for this pixel. vec2 uv = gl_LaunchIDEXT.xy + vec2(random()); // random breaks up aliasing uv /= vec2(gl_LaunchSizeEXT.xy); @@ -77,10 +76,9 @@ void TraceCameraRay(out bool hitSky, out vec3 pos, out vec3 norm, out uvec4 hit) 0); // Location of payload // Read the values from the payload: - hitSky = (payload.hitSky > 0.0); + hitSky = (payload.hitSky > 0.0f); pos = payload.worldPosition; norm = payload.worldNormal; - hit = payload.hit; } /** @@ -88,8 +86,8 @@ void TraceCameraRay(out bool hitSky, out vec3 pos, out vec3 norm, out uvec4 hit) * @param[in] orig The point of origin of the shadow ray. * @param[in] dir The direction of the shadow ray. */ -float CastShadowRay(vec3 orig, vec3 dir){ - payload.hitSky = 0.0f; // Assume ray is occluded +float CastShadowRay(vec3 orig, vec3 dir) { + payload.hitSky = 0.0f; traceRayEXT(tlas, // Acceleration structure gl_RayFlagsOpaqueEXT | gl_RayFlagsSkipClosestHitShaderEXT | gl_RayFlagsTerminateOnFirstHitEXT, // Ray flags, here saying "ignore any hit shaders and closest hit shaders, and terminate the ray on the first found intersection" 0xFF, // 8-bit instance mask, here saying "trace against all instances" @@ -109,7 +107,8 @@ vec3 sampleCosineDistribution(vec2 xi){ return vec3( sqrt(xi.x) * cos(phi), sqrt(1 - xi.x), - sqrt(xi.x) * sin(phi)); + sqrt(xi.x) * sin(phi) + ); } struct Basis{ @@ -129,44 +128,39 @@ Basis buildBasisAroundNormal(vec3 N){ vec3 sampleTangentToWorldSpace(vec3 tangentSpaceSample, vec3 N){ Basis tangentBasis = buildBasisAroundNormal(N); - return + return ( tangentBasis.right * tangentSpaceSample.x + tangentBasis.up * tangentSpaceSample.y + - tangentBasis.forward * tangentSpaceSample.z; + tangentBasis.forward * tangentSpaceSample.z + ); } void main(){ - uint rayCount = 64; // the amount of rays to be casted + uint rayCount = 16; // the amount of rays to be casted initRandom(gl_LaunchIDEXT.xy); uvec2 pixel = gl_LaunchIDEXT.xy; bool pixelIsSky; // Does the pixel show the sky (not an object)? vec3 pos, norm; // AO rays from where? - uvec4 hit; - TraceCameraRay(pixelIsSky, pos, norm, hit); - - if(pixelIsSky){ + TraceCameraRay(pixelIsSky, pos, norm); + + if (pixelIsSky){ // Don't compute ambient occlusion for the sky imageStore(outImg, ivec2(pixel), vec4(0.8,0.8,0.8,1.0)); return; } - imageStore(outImg, ivec2(pixel), vec4(vec3( - 0,//float(hit.x) / 0xFFFF, - 0,//float(hit.y) / 381, - hit.z > 0 || hit.w > 0? 1 : 0 - ), 1)); -/* // Compute ambient occlusion - float aoValue = 0.0; + float aoValue = 0.0f; for(uint i = 0; i < rayCount; i++){ vec3 sampleTangentSpace = sampleCosineDistribution(random()); vec3 sampleWorldSpace = sampleTangentToWorldSpace(sampleTangentSpace, norm); - aoValue += CastShadowRay(pos, sampleWorldSpace); + + aoValue += CastShadowRay(pos, sampleWorldSpace); } + aoValue /= rayCount; imageStore(outImg, ivec2(pixel), vec4(vec3(aoValue), 1)); -*/ } diff --git a/projects/rt_ambient_occlusion/resources/shaders/ambientOcclusion.rmiss b/projects/rt_ambient_occlusion/resources/shaders/ambientOcclusion.rmiss index 5c97ae90..c107dbd0 100644 --- a/projects/rt_ambient_occlusion/resources/shaders/ambientOcclusion.rmiss +++ b/projects/rt_ambient_occlusion/resources/shaders/ambientOcclusion.rmiss @@ -5,7 +5,6 @@ layout(location = 0) rayPayloadInEXT Payload { float hitSky; vec3 worldPosition; vec3 worldNormal; - uvec4 hit; } payload; void main() { diff --git a/projects/rt_ambient_occlusion/src/main.cpp b/projects/rt_ambient_occlusion/src/main.cpp index c668ce40..4e587f2e 100644 --- a/projects/rt_ambient_occlusion/src/main.cpp +++ b/projects/rt_ambient_occlusion/src/main.cpp @@ -1,6 +1,5 @@ #include <vkcv/Core.hpp> #include <vkcv/camera/CameraManager.hpp> -#include <vkcv/geometry/Teapot.hpp> #include <vkcv/shader/GLSLCompiler.hpp> #include <vkcv/scene/Scene.hpp> @@ -8,6 +7,16 @@ * Note: This project is based on the following tutorial https://github.com/Apress/Ray-Tracing-Gems-II/tree/main/Chapter_16. */ +struct ObjDesc { + uint64_t vertexAddress; + uint64_t indexAddress; + uint32_t vertexStride; + uint32_t pad0; + uint32_t pad1; + uint32_t pad2; + glm::mat4 transform; +}; + int main(int argc, const char** argv) { const std::string applicationName = "Ray Tracing: Ambient Occlusion"; @@ -42,6 +51,12 @@ int main(int argc, const char** argv) { } ); + features.requireFeature( + [](vk::PhysicalDeviceFeatures &features) { + features.setShaderInt64(true); + } + ); + vkcv::Core core = vkcv::Core::create( applicationName, VK_MAKE_VERSION(0, 0, 1), @@ -53,15 +68,11 @@ int main(int argc, const char** argv) { vkcv::scene::Scene scene = vkcv::scene::Scene::load( core, - "../first_scene/assets/Sponza/Sponza.gltf", + "resources/Sponza/Sponza.gltf", { vkcv::asset::PrimitiveType::POSITION } ); - - vkcv::geometry::Teapot teapot (glm::vec3(0.0f), 1.0f); - vkcv::VertexData vertexData = teapot.generateVertexData(core); - vkcv::GeometryData geometryData = teapot.extractGeometryData(core, vertexData); vkcv::camera::CameraManager cameraManager(core.getWindow(windowHandle)); auto camHandle = cameraManager.addCamera(vkcv::camera::ControllerType::TRACKBALL); @@ -96,16 +107,54 @@ int main(int argc, const char** argv) { descriptorSetHandles.push_back(shaderDescriptorSet); descriptorSetLayoutHandles.push_back(shaderDescriptorSetLayout); - vkcv::AccelerationStructureHandle blas = core.createAccelerationStructure({ geometryData }); - vkcv::AccelerationStructureHandle tlas = core.createAccelerationStructure({ blas }); + const uint32_t instanceCount = scene.getMeshCount(); + const uint32_t geometryCount = scene.getMeshPartCount(); + + std::vector<ObjDesc> objDescList; + objDescList.resize(instanceCount * static_cast<size_t>( + std::ceil(static_cast<float>(geometryCount) / instanceCount) + )); + + vkcv::AccelerationStructureHandle scene_tlas = scene.createAccelerationStructure( + [&core, &objDescList, instanceCount]( + size_t instanceIndex, + size_t geometryIndex, + const vkcv::GeometryData &geometry, + const glm::mat4 &transform + ) { + ObjDesc obj {}; + + obj.vertexAddress = core.getBufferDeviceAddress( + geometry.getVertexBufferBinding().m_buffer + ); + + obj.indexAddress = core.getBufferDeviceAddress( + geometry.getIndexBuffer() + ); + + obj.vertexStride = geometry.getVertexStride() / sizeof(float); + obj.transform = transform; + + objDescList[geometryIndex * instanceCount + instanceIndex] = obj; + } + ); + + auto objDescBuffer = vkcv::buffer<ObjDesc>( + core, + vkcv::BufferType::STORAGE, + objDescList.size() + ); + + objDescBuffer.fill(objDescList); - vkcv::AccelerationStructureHandle scene_tlas = scene.createAccelerationStructure(); + auto instanceCountBuffer = vkcv::buffer<uint32_t>(core, vkcv::BufferType::STORAGE, 1); + instanceCountBuffer.fill(&instanceCount); { vkcv::DescriptorWrites writes; writes.writeAcceleration(1, { scene_tlas }); - writes.writeStorageBuffer(2, geometryData.getVertexBufferBinding().m_buffer); - writes.writeStorageBuffer(3, geometryData.getIndexBuffer()); + writes.writeStorageBuffer(2, objDescBuffer.getHandle()); + writes.writeStorageBuffer(3, instanceCountBuffer.getHandle()); core.writeDescriptorSet(descriptorSetHandles[0], writes); } diff --git a/src/vkcv/AccelerationStructureManager.cpp b/src/vkcv/AccelerationStructureManager.cpp index 5a31fbd0..8c51a9ad 100644 --- a/src/vkcv/AccelerationStructureManager.cpp +++ b/src/vkcv/AccelerationStructureManager.cpp @@ -119,7 +119,7 @@ namespace vkcv { Core& core, BufferManager& bufferManager, std::vector<vk::AccelerationStructureBuildGeometryInfoKHR> &geometryInfos, - const std::vector<std::vector<vk::AccelerationStructureBuildRangeInfoKHR>> &rangeInfos, + const std::vector<vk::AccelerationStructureBuildRangeInfoKHR> &rangeInfos, size_t accelerationStructureSize, size_t scratchBufferSize, vk::AccelerationStructureTypeKHR accelerationStructureType) { @@ -190,7 +190,7 @@ namespace vkcv { pRangeInfos.resize(rangeInfos.size()); for (size_t i = 0; i < rangeInfos.size(); i++) { - pRangeInfos[i] = rangeInfos[i].data(); + pRangeInfos[i] = &(rangeInfos[i]); } auto cmdStream = core.createCommandStream(vkcv::QueueType::Compute); @@ -239,7 +239,7 @@ namespace vkcv { const BufferHandle &transformBuffer) { std::vector<vk::AccelerationStructureGeometryKHR> geometries; std::vector<vk::AccelerationStructureBuildGeometryInfoKHR> geometryInfos; - std::vector<std::vector<vk::AccelerationStructureBuildRangeInfoKHR>> rangeInfos; + std::vector<vk::AccelerationStructureBuildRangeInfoKHR> rangeInfos; if (geometryData.empty()) { return {}; @@ -267,6 +267,11 @@ namespace vkcv { const auto &dynamicDispatch = getCore().getContext().getDispatchLoaderDynamic(); geometries.reserve(geometryData.size()); + rangeInfos.reserve(geometryData.size()); + + std::vector<uint32_t> maxPrimitiveCount; + + maxPrimitiveCount.reserve(geometryData.size()); for (const GeometryData &data : geometryData) { const auto vertexBufferAddress = bufferManager.getBufferDeviceAddress( @@ -300,46 +305,44 @@ namespace vkcv { ); geometries.push_back(asGeometry); + + const vk::AccelerationStructureBuildRangeInfoKHR asBuildRangeInfo ( + static_cast<uint32_t>(data.getCount() / 3), + 0, + 0, + 0 + ); + + rangeInfos.push_back(asBuildRangeInfo); + maxPrimitiveCount.push_back(asBuildRangeInfo.primitiveCount); } - 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]) + static_cast<uint32_t>(geometries.size()), + geometries.data() ); 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); } + vk::AccelerationStructureBuildSizesInfoKHR asBuildSizesInfo; + getCore().getContext().getDevice().getAccelerationStructureBuildSizesKHR( + vk::AccelerationStructureBuildTypeKHR::eDevice, + geometryInfos.data(), + maxPrimitiveCount.data(), + &(asBuildSizesInfo), + dynamicDispatch + ); + + accelerationStructureSize += asBuildSizesInfo.accelerationStructureSize; + scratchBufferSize = std::max(scratchBufferSize, asBuildSizesInfo.buildScratchSize); + const auto entry = buildAccelerationStructure( getCore(), bufferManager, @@ -485,7 +488,7 @@ namespace vkcv { getCore(), bufferManager, asBuildGeometryInfos, - { { asBuildRangeInfo } }, + { asBuildRangeInfo }, asBuildSizesInfo.accelerationStructureSize, asBuildSizesInfo.buildScratchSize, vk::AccelerationStructureTypeKHR::eTopLevel -- GitLab