diff --git a/include/util/AccelerationStructureBuilder.hpp b/include/util/AccelerationStructureBuilder.hpp index 89d0923..cea4a2b 100644 --- a/include/util/AccelerationStructureBuilder.hpp +++ b/include/util/AccelerationStructureBuilder.hpp @@ -34,7 +34,7 @@ class AccelerationStructureBuilder { private: size_t bestAccelerationStructureIndex(std::vector& asBoundingBoxes, const AABB& modelBounds, - const AABB& geometryBoundingBox); + const AABB& geometryBoundingBox, bool resizeBoundingBoxes = true); AccelerationStructureData createAccelerationStructure( const VkAccelerationStructureBuildGeometryInfoKHR& buildInfos, const std::vector& maxPrimitiveCounts, diff --git a/shaders/triangle.rchit b/shaders/triangle.rchit index a36a0b1..863d22b 100644 --- a/shaders/triangle.rchit +++ b/shaders/triangle.rchit @@ -188,7 +188,7 @@ void main() { return; } else { - payload.rayThroughput /= russianRouletteWeight; + payload.rayThroughput /= 1.0f - russianRouletteWeight; } traceRayEXT(tlasStructure, gl_RayFlagsNoneEXT, 0xFF, 0, 0, 0, hitPoint + 0.01f * objectHitNormal, 0, sampleDir, 999999999.0f, 0); diff --git a/src/main.cpp b/src/main.cpp index 4f17cb0..f10a0a6 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -19,9 +19,10 @@ int main(int argc, const char** argv) { } std::vector spheres = { - { .position = { -8.3395f, -0.76978f, -2.3374f, }, .radius = 0.5f, .color = { 0.8f, 0.6f, 0.6f, 500.0f } }, + /*{ .position = { -8.3395f, -0.76978f, -2.3374f, }, .radius = 0.5f, .color = { 0.8f, 0.6f, 0.6f, 500.0f } }, { .position = { 8.9656f, -0.76978f, -2.3374f }, .radius = 0.5f, .color = { 0.4f, 0.7f, 0.6f, 500.0f } }, - { .position = { -8.73348522f, -3.92734623f, -2.85059690f }, .radius = 0.5f, .color = { 0.8f, 0.5f, 0.4f, 500.0f } } + { .position = { -8.73348522f, -3.92734623f, -2.85059690f }, .radius = 0.5f, .color = { 0.8f, 0.5f, 0.4f, 500.0f } }*/ + { .position = { 0.3f, -1.76978f, -2.3374f }, .radius = 0.5f, .color = { 0.7f, 0.7f, 0.7f, 500.0f } } }; MemoryAllocator allocator = MemoryAllocator(device); diff --git a/src/util/AccelerationStructureBuilder.cpp b/src/util/AccelerationStructureBuilder.cpp index 7fd80fd..3035c9b 100644 --- a/src/util/AccelerationStructureBuilder.cpp +++ b/src/util/AccelerationStructureBuilder.cpp @@ -1,7 +1,7 @@ #include -#include -#include #include +#include +#include // assign geometry to whichever AS it intersects with the most, undef this in order to assign geometries to ASes based // on whichever generates less intersection area between all AABBS (is O(n^2) instead of O(n) with n=number of ASes @@ -82,10 +82,16 @@ AccelerationStructureBuilder::AccelerationStructureBuilder(RayTracingDevice& dev std::vector transformMatrices; transformMatrices.reserve(modelLoader.geometries().size()); + #ifdef AS_HEURISTIC_GEOMETRY_INTERSECTION + for (auto& geometry : modelLoader.geometries()) { + bestAccelerationStructureIndex(asAABBs, modelBounds, geometry.aabb); + } + #endif + size_t currentTransformBufferOffset = 0; size_t geometryIndex = 0; for (auto& geometry : modelLoader.geometries()) { - size_t asIndex = bestAccelerationStructureIndex(asAABBs, modelBounds, geometry.aabb); + size_t asIndex = bestAccelerationStructureIndex(asAABBs, modelBounds, geometry.aabb, false); asGeometryData[asIndex].geometries.push_back( { .sType = VK_STRUCTURE_TYPE_ACCELERATION_STRUCTURE_GEOMETRY_KHR, .geometryType = VK_GEOMETRY_TYPE_TRIANGLES_KHR, @@ -103,12 +109,13 @@ AccelerationStructureBuilder::AccelerationStructureBuilder(RayTracingDevice& dev currentTransformBufferOffset } } }, .flags = geometry.isAlphaTested ? 0U : VK_GEOMETRY_OPAQUE_BIT_KHR }); VkTransformMatrixKHR transformMatrix = { .matrix = { - { geometry.transformMatrix[0], geometry.transformMatrix[4], - geometry.transformMatrix[8], geometry.transformMatrix[12] }, - { geometry.transformMatrix[1], geometry.transformMatrix[5], - geometry.transformMatrix[9], geometry.transformMatrix[13] }, - { geometry.transformMatrix[2], geometry.transformMatrix[6], - geometry.transformMatrix[10], geometry.transformMatrix[14] } } }; + { geometry.transformMatrix[0], geometry.transformMatrix[1], + geometry.transformMatrix[2], geometry.transformMatrix[3] }, + { geometry.transformMatrix[4], geometry.transformMatrix[5], + geometry.transformMatrix[6], geometry.transformMatrix[7] }, + { geometry.transformMatrix[8], geometry.transformMatrix[9], + geometry.transformMatrix[10], geometry.transformMatrix[11] } + } }; asGeometryData[asIndex].rangeInfos.push_back( { .primitiveCount = static_cast(geometry.indexCount / 3) }); transformMatrices.push_back(transformMatrix); @@ -224,9 +231,8 @@ AccelerationStructureBuilder::AccelerationStructureBuilder(RayTracingDevice& dev uint32_t sphereCount = lightSpheres.size(); - sphereBLASData = - createAccelerationStructure(sphereBuildInfo, { 1 }, - accelerationStructureProperties.minAccelerationStructureScratchOffsetAlignment); + sphereBLASData = createAccelerationStructure( + sphereBuildInfo, { 1 }, accelerationStructureProperties.minAccelerationStructureScratchOffsetAlignment); sphereBuildInfo.dstAccelerationStructure = sphereBLASData.accelerationStructure; sphereBuildInfo.scratchData = { .deviceAddress = sphereBLASData.scratchBufferDeviceAddress }; @@ -244,8 +250,7 @@ AccelerationStructureBuilder::AccelerationStructureBuilder(RayTracingDevice& dev verifyResult(vkCreateBuffer(m_device.device(), &sphereDataBufferCreateInfo, nullptr, &m_lightDataBuffer)); sphereDataBufferCreateInfo.usage = VK_BUFFER_USAGE_TRANSFER_SRC_BIT; - verifyResult( - vkCreateBuffer(m_device.device(), &sphereDataBufferCreateInfo, nullptr, &lightDataStagingBuffer)); + verifyResult(vkCreateBuffer(m_device.device(), &sphereDataBufferCreateInfo, nullptr, &lightDataStagingBuffer)); setObjectName(m_device.device(), VK_OBJECT_TYPE_BUFFER, m_lightDataBuffer, "Light Data buffer"); setObjectName(m_device.device(), VK_OBJECT_TYPE_BUFFER, lightDataStagingBuffer, "Light Data staging buffer"); @@ -269,7 +274,8 @@ AccelerationStructureBuilder::AccelerationStructureBuilder(RayTracingDevice& dev verifyResult(vkCreateBuffer(m_device.device(), &geometryIndexBufferCreateInfo, nullptr, &m_geometryIndexBuffer)); geometryIndexBufferCreateInfo.usage = VK_BUFFER_USAGE_TRANSFER_SRC_BIT; VkBuffer geometryIndexStagingBuffer; - verifyResult(vkCreateBuffer(m_device.device(), &geometryIndexBufferCreateInfo, nullptr, &geometryIndexStagingBuffer)); + verifyResult( + vkCreateBuffer(m_device.device(), &geometryIndexBufferCreateInfo, nullptr, &geometryIndexStagingBuffer)); m_allocator.bindDeviceBuffer(m_geometryIndexBuffer, 0); void* mappedGeometryIndexBuffer = m_allocator.bindStagingBuffer(geometryIndexStagingBuffer, 0); @@ -353,7 +359,7 @@ AccelerationStructureBuilder::AccelerationStructureBuilder(RayTracingDevice& dev { 0.0f, 2 * sphere.radius, 0.0f, sphere.position[1] }, { 0.0f, 0.0f, 2 * sphere.radius, sphere.position[2] } } }, .instanceCustomIndex = 0U, - .mask = 0x01, //culled in ray gen + .mask = 0x01, // culled in ray gen .instanceShaderBindingTableRecordOffset = lightSphereSBTIndex, .accelerationStructureReference = compactedSphereAccelerationStructureData.accelerationStructureDeviceAddress }); @@ -377,13 +383,14 @@ AccelerationStructureBuilder::AccelerationStructureBuilder(RayTracingDevice& dev m_triangleBLASes.push_back(data.accelerationStructure); m_triangleASBackingBuffers.push_back(data.backingBuffer); - tlasInstances.push_back({ .transform = { .matrix = { { 1.0f, 0.0f, 0.0f, 1.0f }, - { 0.0f, -1.0f, 0.0f, 1.0f }, - { 0.0f, 0.0f, 1.0f, 1.0f } } }, - .instanceCustomIndex = static_cast(geometryIndexBufferOffsets[instanceIndex]), - .mask = 0xFF, - .instanceShaderBindingTableRecordOffset = triangleSBTIndex, - .accelerationStructureReference = data.accelerationStructureDeviceAddress }); + tlasInstances.push_back( + { .transform = { .matrix = { { 1.0f, 0.0f, 0.0f, 1.0f }, + { 0.0f, -1.0f, 0.0f, 1.0f }, + { 0.0f, 0.0f, 1.0f, 1.0f } } }, + .instanceCustomIndex = static_cast(geometryIndexBufferOffsets[instanceIndex]), + .mask = 0xFF, + .instanceShaderBindingTableRecordOffset = triangleSBTIndex, + .accelerationStructureReference = data.accelerationStructureDeviceAddress }); ++instanceIndex; } @@ -532,7 +539,8 @@ AccelerationStructureBuilder::~AccelerationStructureBuilder() { size_t AccelerationStructureBuilder::bestAccelerationStructureIndex(std::vector& asBoundingBoxes, const AABB& modelBounds, - const AABB& geometryBoundingBox) { + const AABB& geometryBoundingBox, + bool resizeBoundingBoxes) { size_t chosenIndex = -1U; float chosenIntersectionArea; @@ -551,7 +559,7 @@ size_t AccelerationStructureBuilder::bestAccelerationStructureIndex(std::vector< #ifdef AS_HEURISTIC_GEOMETRY_INTERSECTION float intersectionArea = geometryBoundingBox.intersectionArea(asBoundingBoxes[i]); - if (intersectionArea > chosenIntersectionArea) { + if (intersectionArea >= chosenIntersectionArea) { chosenIndex = i; chosenIntersectionArea = intersectionArea; } @@ -577,14 +585,44 @@ size_t AccelerationStructureBuilder::bestAccelerationStructureIndex(std::vector< #endif } -#ifndef AS_HEURISTIC_GEOMETRY_INTERSECTION // only useful when miminizing intersection area - asBoundingBoxes[chosenIndex].xmin = std::min(geometryBoundingBox.xmin, asBoundingBoxes[chosenIndex].xmin); - asBoundingBoxes[chosenIndex].ymin = std::min(geometryBoundingBox.ymin, asBoundingBoxes[chosenIndex].ymin); - asBoundingBoxes[chosenIndex].zmin = std::min(geometryBoundingBox.zmin, asBoundingBoxes[chosenIndex].zmin); - asBoundingBoxes[chosenIndex].xmax = std::max(geometryBoundingBox.xmax, asBoundingBoxes[chosenIndex].xmax); - asBoundingBoxes[chosenIndex].ymax = std::max(geometryBoundingBox.ymax, asBoundingBoxes[chosenIndex].ymax); - asBoundingBoxes[chosenIndex].zmax = std::max(geometryBoundingBox.zmax, asBoundingBoxes[chosenIndex].zmax); -#endif + if (resizeBoundingBoxes) { + if (chosenIntersectionArea <= 0.001f) + return chosenIndex; + asBoundingBoxes[chosenIndex].xmin = std::min(geometryBoundingBox.xmin, asBoundingBoxes[chosenIndex].xmin); + asBoundingBoxes[chosenIndex].ymin = std::min(geometryBoundingBox.ymin, asBoundingBoxes[chosenIndex].ymin); + asBoundingBoxes[chosenIndex].zmin = std::min(geometryBoundingBox.zmin, asBoundingBoxes[chosenIndex].zmin); + asBoundingBoxes[chosenIndex].xmax = std::max(geometryBoundingBox.xmax, asBoundingBoxes[chosenIndex].xmax); + asBoundingBoxes[chosenIndex].ymax = std::max(geometryBoundingBox.ymax, asBoundingBoxes[chosenIndex].ymax); + asBoundingBoxes[chosenIndex].zmax = std::max(geometryBoundingBox.zmax, asBoundingBoxes[chosenIndex].zmax); + + for (size_t i = 0; i < asBoundingBoxes.size(); ++i) { + if (i == chosenIndex) + continue; + if (asBoundingBoxes[i].xmax <= asBoundingBoxes[chosenIndex].xmax && + asBoundingBoxes[i].xmax < asBoundingBoxes[chosenIndex].xmin) { + asBoundingBoxes[i].xmax = asBoundingBoxes[chosenIndex].xmin; + } else if (asBoundingBoxes[i].xmin < asBoundingBoxes[chosenIndex].xmax && + asBoundingBoxes[i].xmin >= asBoundingBoxes[chosenIndex].xmin) { + asBoundingBoxes[i].xmin = asBoundingBoxes[chosenIndex].xmin; + } + + if (asBoundingBoxes[i].ymax <= asBoundingBoxes[chosenIndex].ymax && + asBoundingBoxes[i].ymax < asBoundingBoxes[chosenIndex].ymin) { + asBoundingBoxes[i].ymax = asBoundingBoxes[chosenIndex].ymin; + } else if (asBoundingBoxes[i].ymin < asBoundingBoxes[chosenIndex].ymax && + asBoundingBoxes[i].ymin >= asBoundingBoxes[chosenIndex].ymin) { + asBoundingBoxes[i].ymin = asBoundingBoxes[chosenIndex].ymin; + } + + if (asBoundingBoxes[i].zmax <= asBoundingBoxes[chosenIndex].zmax && + asBoundingBoxes[i].zmax < asBoundingBoxes[chosenIndex].zmin) { + asBoundingBoxes[i].zmax = asBoundingBoxes[chosenIndex].zmin; + } else if (asBoundingBoxes[i].zmin < asBoundingBoxes[chosenIndex].zmax && + asBoundingBoxes[i].zmin >= asBoundingBoxes[chosenIndex].zmin) { + asBoundingBoxes[i].zmin = asBoundingBoxes[chosenIndex].zmin; + } + } + } return chosenIndex; } diff --git a/src/util/ModelLoader.cpp b/src/util/ModelLoader.cpp index 47b7c04..aa7e3bc 100644 --- a/src/util/ModelLoader.cpp +++ b/src/util/ModelLoader.cpp @@ -27,20 +27,26 @@ float dot_vec3(const float vec1[3], const float vec2[3]) { // multiply 4x4 matrix with vec(x, y, z, 1) void multiply_mat4_vec3_w1(float vec[3], const float mat[16]) { float tmp[3]; - tmp[0] = dot_vec3(vec, mat); - tmp[1] = dot_vec3(vec, mat + 4); - tmp[2] = dot_vec3(vec, mat + 8); - tmp[0] += mat[3]; - tmp[0] += mat[7]; - tmp[0] += mat[11]; + float mat_row1[3] = { mat[0], mat[4], mat[8] }; + float mat_row2[3] = { mat[1], mat[5], mat[9] }; + float mat_row3[3] = { mat[2], mat[6], mat[10] }; + tmp[0] = dot_vec3(vec, mat_row1); + tmp[1] = dot_vec3(vec, mat_row2); + tmp[2] = dot_vec3(vec, mat_row3); + tmp[0] += mat[12]; + tmp[1] += mat[13]; + tmp[2] += mat[14]; std::memcpy(vec, tmp, 3 * sizeof(float)); } void multiply_mat4_vec3_w0(float vec[3], const float mat[16]) { float tmp[3]; - tmp[0] = dot_vec3(vec, mat); - tmp[1] = dot_vec3(vec, mat + 4); - tmp[2] = dot_vec3(vec, mat + 8); + float mat_row1[3] = { mat[0], mat[4], mat[8] }; + float mat_row2[3] = { mat[1], mat[5], mat[9] }; + float mat_row3[3] = { mat[2], mat[6], mat[10] }; + tmp[0] = dot_vec3(vec, mat_row1); + tmp[1] = dot_vec3(vec, mat_row2); + tmp[2] = dot_vec3(vec, mat_row3); std::memcpy(vec, tmp, 3 * sizeof(float)); } @@ -295,7 +301,11 @@ ModelLoader::ModelLoader(RayTracingDevice& device, MemoryAllocator& allocator, O m_allocator.bindDeviceBuffer(m_materialBuffer, 0); m_allocator.bindDeviceBuffer(m_geometryBuffer, 0); - stagingBufferCreateInfo.size = m_combinedImageSize; + if (m_combinedImageSize > 4_GiB) { + stagingBufferCreateInfo.size = m_maxImageSize; + } else { + stagingBufferCreateInfo.size = m_combinedImageSize; + } verifyResult(vkCreateBuffer(m_device.device(), &stagingBufferCreateInfo, nullptr, &m_imageStagingBuffer)); void* imageStagingBufferData = m_allocator.bindStagingBuffer(m_imageStagingBuffer, 0); @@ -445,6 +455,18 @@ ModelLoader::ModelLoader(RayTracingDevice& device, MemoryAllocator& allocator, O while (!blitImages.empty()) { vkCmdPipelineBarrier(commandBuffer, VK_PIPELINE_STAGE_TRANSFER_BIT, VK_PIPELINE_STAGE_TRANSFER_BIT, 0, 1, &transferBarrier, 0, nullptr, 0, nullptr); + + for (size_t i = 0; i < blitImages.size(); ++i) { + if (std::min(blitImages[i].width, blitImages[i].height) == 0) { + printf("Detected mip level with size 0, ..somehow? minIndex = %ull\n", mipIndex); + blitImages.erase(blitImages.begin() + i); + --i; + } else if (std::min(blitImages[i].width, blitImages[i].height) < 4) { + blitImages.erase(blitImages.begin() + i); + --i; + } + } + for (auto& image : blitImages) { int32_t mipHeight = image.height / 2; int32_t mipWidth = image.width / 2; @@ -467,17 +489,6 @@ ModelLoader::ModelLoader(RayTracingDevice& device, MemoryAllocator& allocator, O image.height = mipHeight; image.width = mipWidth; } - - for (size_t i = 0; i < blitImages.size(); ++i) { - if (std::min(blitImages[i].width, blitImages[i].height) == 0) { - printf("Detected mip level with size 0, ..somehow? minIndex = %ull\n", mipIndex); - blitImages.erase(blitImages.begin() + i); - --i; - } else if (std::min(blitImages[i].width, blitImages[i].height) < 4) { - blitImages.erase(blitImages.begin() + i); - --i; - } - } ++mipIndex; } @@ -613,6 +624,11 @@ void ModelLoader::addNode(cgltf_data* data, cgltf_node* node, float translation[ std::memcpy(localRotation, rotation, 4 * sizeof(float)); std::memcpy(localScale, scale, 3 * sizeof(float)); // resolve child transforms and make global + if (node->has_scale) { + for (size_t i = 0; i < 3; ++i) { + localScale[i] *= node->scale[i]; + } + } if (node->has_translation) { for (size_t i = 0; i < 3; ++i) { localTranslation[i] += node->translation[i]; @@ -630,27 +646,22 @@ void ModelLoader::addNode(cgltf_data* data, cgltf_node* node, float translation[ localRotation[3] = rotation[3] * node->rotation[3] + rotation[1] * node->rotation[1] + rotation[2] * node->rotation[2] + rotation[0] * node->rotation[0]; } - if (node->has_scale) { - for (size_t i = 0; i < 3; ++i) { - localScale[i] *= node->scale[i]; - } - } // clang-format off //https://www.euclideanspace.com/maths/geometry/rotations/conversions/quaternionToMatrix/index.htm //assumed column-major matrix layout float quatRotationMatrix[16] = { - localRotation[3], localRotation[2], -localRotation[1], -localRotation[0], - -localRotation[2], localRotation[3], localRotation[0], -localRotation[1], - localRotation[1], -localRotation[0], localRotation[3], -localRotation[2], - localRotation[0], localRotation[1], localRotation[2], localRotation[3], - }; - float quatRotationMatrixFactor[16] = { localRotation[3], localRotation[2], -localRotation[1], localRotation[0], -localRotation[2], localRotation[3], localRotation[0], localRotation[1], localRotation[1], -localRotation[0], localRotation[3], localRotation[2], -localRotation[0], -localRotation[1], -localRotation[2], localRotation[3], }; + float quatRotationMatrixFactor[16] = { + localRotation[3], localRotation[2], -localRotation[1], -localRotation[0], + -localRotation[2], localRotation[3], localRotation[0], -localRotation[1], + localRotation[1], -localRotation[0], localRotation[3], -localRotation[2], + localRotation[0], localRotation[1], localRotation[2], localRotation[3], + }; float transformMatrix[16] = { //only translation at first, becomes transform matrix through matrix multiplications 1.0f, 0.0f, 0.0f, localTranslation[0], @@ -671,21 +682,17 @@ void ModelLoader::addNode(cgltf_data* data, cgltf_node* node, float translation[ std::memcpy(noRotationTransformMatrix, transformMatrix, 16 * sizeof(float)); multiply_mat4(quatRotationMatrix, quatRotationMatrixFactor); - multiply_mat4(quatRotationMatrix, scaleMatrix); - multiply_mat4(quatRotationMatrix, transformMatrix); - - std::memcpy(transformMatrix, quatRotationMatrix, 16 * sizeof(float)); + multiply_mat4(transformMatrix, quatRotationMatrix); + multiply_mat4(transformMatrix, scaleMatrix); multiply_mat4(noRotationTransformMatrix, scaleMatrix); if (node->camera && node->camera->type == cgltf_camera_type_perspective) { - float baseDirection[3] = { 0.0f, 0.0f, 1.0f }; - rotate_quat(baseDirection, localRotation); - std::swap(baseDirection[0], baseDirection[1]); + float baseDirection[3] = { 0.0f, 0.0f, -1.0f }; + multiply_mat4_vec3_w0(baseDirection, quatRotationMatrix); - float baseRight[3] = { 0.0f, -1.0f, 0.0f }; - rotate_quat(baseRight, localRotation); - std::swap(baseRight[0], baseRight[1]); + float baseRight[3] = { 1.0f, 0.0f, 0.0f }; + multiply_mat4_vec3_w0(baseRight, quatRotationMatrix); m_camera = { .fov = node->camera->data.perspective.yfov, .znear = node->camera->data.perspective.znear }; @@ -935,8 +942,7 @@ void ModelLoader::copyNodeGeometries(cgltf_data* data, cgltf_node* node, size_t& static_cast(m_geometries[currentGeometryIndex].tangentOffset / (sizeof(float) * 4)), .indexOffset = static_cast(m_geometries[currentGeometryIndex].indexOffset / sizeof(uint32_t)), - .materialIndex = static_cast(m_geometries[currentGeometryIndex].materialIndex + - m_globalMaterialIndexOffset) }); + .materialIndex = static_cast(m_geometries[currentGeometryIndex].materialIndex) }); ++currentGeometryIndex; } } @@ -1031,7 +1037,7 @@ void ModelLoader::addImage(cgltf_data* data, cgltf_image* image, const std::stri imageData.size = imageData.width * imageData.height * 4; } m_combinedImageSize += imageData.size; - m_maxImageSize = std::max(m_maxImageSize, m_imageData.size()); + m_maxImageSize = std::max(m_maxImageSize, imageData.size); m_imageData.push_back(imageData); VkImageCreateInfo imageCreateInfo = {