diff --git a/.README.md.un~ b/.README.md.un~ new file mode 100644 index 0000000..374459e Binary files /dev/null and b/.README.md.un~ differ diff --git a/README.md b/README.md index b0189d0..79cdde2 100644 --- a/README.md +++ b/README.md @@ -1,11 +1,21 @@ -**University of Pennsylvania, CIS 565: GPU Programming and Architecture, -Project 5 - DirectX Procedural Raytracing** +Davis Polito +* [https://github.com/davispolito/Project0-Getting-Started/blob/master]() +* Tested on: +Windows 10, i7-8750H @ 2.20GHz 16GB, GTX 1060 -* (TODO) YOUR NAME HERE - * (TODO) [LinkedIn](), [personal website](), [twitter](), etc. -* Tested on: (TODO) Windows 22, i7-2222 @ 2.22GHz 22GB, GTX 222 222MB (Moore 2222 Lab) +## Conceptual Questions + 1. How would you convert pixels into rays? + We need to first transfer from the 4x4 *view matrix* to the *image plane matrix* by multiplying by the *camera projection matrix* and normalized via persepctive divide. This takes us to screen space by discarding the z component. From here we normalize to our specific screen. We then floor the screen space to pixel space assuming we know pixel width. Assuming Z = x we can invert all these matrices including the perspective divide stage. This is how we get the final ray equation. + 2. How would one render procedural geometry? + We simply turn its geometric function into an intersection function such that when the ray enters the object the function returns in an explicitly defined way. If the *(x,y,z)* of the ray solves the equation the point is rendered and the ray casted against its normal. + + 3. Draw the Accelleration structures for this scene. -### (TODO: Your README) + TOP LEVEL + Instance | Instance | Instanceo -Include screenshots, analysis, etc. (Remember, this is public, so don't put -anything here that you don't want to share with the world.) +GEOM - MODEL - AABB +*BLAS* *BLAS* *BLAS* +Plane Var -> Plane 1 Person T - > model 1, t Spheres -> [] instacnes +Plane var -> Plane 2 Person laying -> model 1 Boxes -> [] instances +Plane var -> Plane 3 diff --git a/README.md~ b/README.md~ new file mode 100644 index 0000000..79cdde2 --- /dev/null +++ b/README.md~ @@ -0,0 +1,21 @@ +Davis Polito +* [https://github.com/davispolito/Project0-Getting-Started/blob/master]() +* Tested on: +Windows 10, i7-8750H @ 2.20GHz 16GB, GTX 1060 + +## Conceptual Questions + 1. How would you convert pixels into rays? + We need to first transfer from the 4x4 *view matrix* to the *image plane matrix* by multiplying by the *camera projection matrix* and normalized via persepctive divide. This takes us to screen space by discarding the z component. From here we normalize to our specific screen. We then floor the screen space to pixel space assuming we know pixel width. Assuming Z = x we can invert all these matrices including the perspective divide stage. This is how we get the final ray equation. + 2. How would one render procedural geometry? + We simply turn its geometric function into an intersection function such that when the ray enters the object the function returns in an explicitly defined way. If the *(x,y,z)* of the ray solves the equation the point is rendered and the ray casted against its normal. + + 3. Draw the Accelleration structures for this scene. + + TOP LEVEL + Instance | Instance | Instanceo + +GEOM - MODEL - AABB +*BLAS* *BLAS* *BLAS* +Plane Var -> Plane 1 Person T - > model 1, t Spheres -> [] instacnes +Plane var -> Plane 2 Person laying -> model 1 Boxes -> [] instances +Plane var -> Plane 3 diff --git a/src/D3D12RaytracingProceduralGeometry/DXR-AccelerationStructure.cpp b/src/D3D12RaytracingProceduralGeometry/DXR-AccelerationStructure.cpp index 905341d..f2a4b83 100644 --- a/src/D3D12RaytracingProceduralGeometry/DXR-AccelerationStructure.cpp +++ b/src/D3D12RaytracingProceduralGeometry/DXR-AccelerationStructure.cpp @@ -32,8 +32,15 @@ void DXProceduralProject::BuildGeometryDescsForBottomLevelAS(arrayGetGPUVirtualAddress(); + geometryDesc.Triangles.IndexCount = m_indexBuffer.resource->GetDesc().Width / sizeof(Index); geometryDesc.Triangles.VertexFormat = DXGI_FORMAT_R32G32B32_FLOAT; + geometryDesc.Triangles.VertexBuffer.StrideInBytes = sizeof(Vertex); + geometryDesc.Triangles.VertexBuffer.StartAddress = m_vertexBuffer.resource->GetGPUVirtualAddress(); + geometryDesc.Triangles.VertexCount = m_vertexBuffer.resource->GetDesc().Width / sizeof(Vertex); + } { @@ -51,7 +58,9 @@ void DXProceduralProject::BuildGeometryDescsForBottomLevelAS(arrayGetGPUVirtualAddress() + primitiveType * sizeof(D3D12_RAYTRACING_AABB); + } } } @@ -70,6 +79,10 @@ AccelerationStructureBuffers DXProceduralProject::BuildBottomLevelAS(const vecto // Again, these tell the AS where the actual geometry data is and how it is laid out. // TODO-2.6: fill the bottom-level inputs. Consider using D3D12_ELEMENTS_LAYOUT_ARRAY as the DescsLayout. D3D12_BUILD_RAYTRACING_ACCELERATION_STRUCTURE_INPUTS &bottomLevelInputs = bottomLevelBuildDesc.Inputs; + bottomLevelInputs.DescsLayout = D3D12_ELEMENTS_LAYOUT_ARRAY; + bottomLevelInputs.Flags = buildFlags; + bottomLevelInputs.Type = D3D12_RAYTRACING_ACCELERATION_STRUCTURE_TYPE_BOTTOM_LEVEL; + bottomLevelInputs.pGeometryDescs = geometryDescs.data(); // Query the driver for resource requirements to build an acceleration structure. We've done this for you. @@ -110,7 +123,8 @@ AccelerationStructureBuffers DXProceduralProject::BuildBottomLevelAS(const vecto // TODO-2.6: Now that you have the scratch and actual bottom-level AS desc, pass their GPU addresses to the bottomLevelBuildDesc. // Consider reading about D3D12_BUILD_RAYTRACING_ACCELERATION_STRUCTURE_DESC. // This should be as easy as passing the GPU addresses to the struct using GetGPUVirtualAddress() calls. - + bottomLevelBuildDesc.ScratchAccelerationStructureData = scratch->GetGPUVirtualAddress(); + bottomLevelBuildDesc.DestAccelerationStructureData = bottomLevelAS->GetGPUVirtualAddress(); // Fill up the command list with a command that tells the GPU how to build the bottom-level AS. if (m_raytracingAPI == RaytracingAPI::FallbackLayer) @@ -129,7 +143,8 @@ AccelerationStructureBuffers DXProceduralProject::BuildBottomLevelAS(const vecto // the AccelerationStructureBuffers struct so the top-level AS can use it! // Don't forget that this is the return value. // Consider looking into the AccelerationStructureBuffers struct in DXR-Structs.h - return AccelerationStructureBuffers{}; + AccelerationStructureBuffers buff = AccelerationStructureBuffers{scratch, bottomLevelAS, nullptr, bottomLevelPrebuildInfo.ResultDataMaxSizeInBytes}; + return buff; } // TODO-2.6: Build the instance descriptor for each bottom-level AS you built before. @@ -179,9 +194,23 @@ void DXProceduralProject::BuildBottomLevelASInstanceDescs(BLASPtrType *bottomLev // * Make sure to set InstanceContributionToHitGroupIndex to beyond the shader records for the triangle AABB. // For triangles, we have 1 shader record for radiance rays, and another for shadow rays. // Where do you think procedural shader records would start then? Hint: right after. - // * Make each instance hover above the ground by ~ half its width { + auto& instanceDesc = instanceDescs[BottomLevelASType::AABB]; + instanceDesc = {}; + instanceDesc.InstanceMask = 1; + instanceDesc.InstanceContributionToHitGroupIndex = 2; + instanceDesc.AccelerationStructure = bottomLevelASaddresses[BottomLevelASType::AABB]; + + // * Make each instance hover above the ground by ~ half its width + const XMVECTOR vBasePosition = c_aabbWidth * XMLoadFloat3(&XMFLOAT3(0.0f, 0.5f, 0.0f)); + + + XMMATRIX mScale = XMMatrixScaling(c_aabbWidth, c_aabbWidth, c_aabbWidth); + XMMATRIX mTransform = mScale * XMMatrixTranslationFromVector(vBasePosition); + + // Store the transform in the instanceDesc. + XMStoreFloat3x4(reinterpret_cast(instanceDesc.Transform), mTransform); } // Upload all these instances to the GPU, and make sure the resouce is set to instanceDescsResource. @@ -204,7 +233,10 @@ AccelerationStructureBuffers DXProceduralProject::BuildTopLevelAS(AccelerationSt // TODO-2.6: fill in the topLevelInputs, read about D3D12_BUILD_RAYTRACING_ACCELERATION_STRUCTURE_INPUTS. // Consider using D3D12_ELEMENTS_LAYOUT_ARRAY as a DescsLayout since we are using an array of bottom-level AS. D3D12_BUILD_RAYTRACING_ACCELERATION_STRUCTURE_INPUTS &topLevelInputs = topLevelBuildDesc.Inputs; - + topLevelInputs.Flags = buildFlags; + topLevelInputs.DescsLayout = D3D12_ELEMENTS_LAYOUT_ARRAY; + topLevelInputs.Type = D3D12_RAYTRACING_ACCELERATION_STRUCTURE_TYPE_TOP_LEVEL; + topLevelInputs.NumDescs = 2; D3D12_RAYTRACING_ACCELERATION_STRUCTURE_PREBUILD_INFO topLevelPrebuildInfo = {}; if (m_raytracingAPI == RaytracingAPI::FallbackLayer) @@ -218,7 +250,7 @@ AccelerationStructureBuffers DXProceduralProject::BuildTopLevelAS(AccelerationSt ThrowIfFalse(topLevelPrebuildInfo.ResultDataMaxSizeInBytes > 0); // TODO-2.6: Allocate a UAV buffer for the scracth/temporary top-level AS data. - + AllocateUAVBuffer(device, topLevelPrebuildInfo.ScratchDataSizeInBytes, &scratch, D3D12_RESOURCE_STATE_UNORDERED_ACCESS, L"UAV Buffer Scratch"); // Allocate space for the top-level AS. { @@ -233,7 +265,8 @@ AccelerationStructureBuffers DXProceduralProject::BuildTopLevelAS(AccelerationSt } // TODO-2.6: Allocate a UAV buffer for the actual top-level AS. - + AllocateUAVBuffer(device, topLevelPrebuildInfo.ResultDataMaxSizeInBytes, &topLevelAS, initialResourceState, L"top-level AS UAV Buffer"); + } // Note on Emulated GPU pointers (AKA Wrapped pointers) requirement in Fallback Layer: @@ -261,7 +294,8 @@ AccelerationStructureBuffers DXProceduralProject::BuildTopLevelAS(AccelerationSt }; // TODO-2.6: Call the fallback-templated version of BuildBottomLevelASInstanceDescs() you completed above. - + BuildBottomLevelASInstanceDescs(bottomLevelASaddresses, &instanceDescsResource); + } else // DirectX Raytracing { @@ -273,7 +307,8 @@ AccelerationStructureBuffers DXProceduralProject::BuildTopLevelAS(AccelerationSt }; // TODO-2.6: Call the DXR-templated version of BuildBottomLevelASInstanceDescs() you completed above. - + BuildBottomLevelASInstanceDescs(bottomLevelASaddresses, &instanceDescsResource); + } // Create a wrapped pointer to the acceleration structure. @@ -285,7 +320,9 @@ AccelerationStructureBuffers DXProceduralProject::BuildTopLevelAS(AccelerationSt // TODO-2.6: fill in the topLevelBuildDesc. Read about D3D12_BUILD_RAYTRACING_ACCELERATION_STRUCTURE_DESC. // This should be as easy as passing the GPU addresses to the struct using GetGPUVirtualAddress() calls. - + topLevelInputs.InstanceDescs = instanceDescsResource->GetGPUVirtualAddress(); + topLevelBuildDesc.ScratchAccelerationStructureData = scratch->GetGPUVirtualAddress(); + topLevelBuildDesc.DestAccelerationStructureData = topLevelAS->GetGPUVirtualAddress(); // Build acceleration structure. if (m_raytracingAPI == RaytracingAPI::FallbackLayer) @@ -304,7 +341,7 @@ AccelerationStructureBuffers DXProceduralProject::BuildTopLevelAS(AccelerationSt // Very similar to how you did this in BuildBottomLevelAS() except now you have to worry about topLevelASBuffers.instanceDesc. // Consider looking into the AccelerationStructureBuffers struct in DXR-Structs.h. // Make sure to return the topLevelASBuffers before you exit the function. - return AccelerationStructureBuffers{}; + return AccelerationStructureBuffers{scratch, topLevelAS, instanceDescsResource, topLevelPrebuildInfo.ResultDataMaxSizeInBytes}; } // TODO-2.6: This will wrap building the Acceleration Structure! This is what we will call when building our scene. @@ -320,12 +357,15 @@ void DXProceduralProject::BuildAccelerationStructures() // TODO-2.6: Build the geometry descriptors. Hint: you filled in a function that does this. array, BottomLevelASType::Count> geometryDescs; + BuildGeometryDescsForBottomLevelAS(geometryDescs); // TODO-2.6: For each bottom-level object (triangle, procedural), build a bottom-level AS. // Hint: you filled in a function that does this. AccelerationStructureBuffers bottomLevelAS[BottomLevelASType::Count]; - + for (int i = 0; i < BottomLevelASType::Count; i++) { + bottomLevelAS[i] = BuildBottomLevelAS(geometryDescs[i]); + } // Batch all resource barriers for bottom-level AS builds. // This will Notifies the driver that it needs to synchronize multiple accesses to resources. @@ -338,6 +378,7 @@ void DXProceduralProject::BuildAccelerationStructures() // TODO-2.6: Build top-level AS. Hint, you already made a function that does this. AccelerationStructureBuffers topLevelAS; + topLevelAS = BuildTopLevelAS(bottomLevelAS); // Kick off acceleration structure construction. @@ -349,5 +390,10 @@ void DXProceduralProject::BuildAccelerationStructures() // TODO-2.6: Store the AS buffers. The rest of the buffers will be released once we exit the function. // Do this for both the bottom-level and the top-level AS. Consider re-reading the DXProceduralProject class // to find what member variables should be set. + for (UINT i = 0; i < BottomLevelASType::Count; i++) + { + m_bottomLevelAS[i] = bottomLevelAS[i].accelerationStructure; + } + m_topLevelAS = topLevelAS.accelerationStructure; } \ No newline at end of file diff --git a/src/D3D12RaytracingProceduralGeometry/DXR-DoRaytracing.cpp b/src/D3D12RaytracingProceduralGeometry/DXR-DoRaytracing.cpp index 03a8c58..0f2d119 100644 --- a/src/D3D12RaytracingProceduralGeometry/DXR-DoRaytracing.cpp +++ b/src/D3D12RaytracingProceduralGeometry/DXR-DoRaytracing.cpp @@ -22,6 +22,8 @@ void DXProceduralProject::DoRaytracing() commandList->SetComputeRootConstantBufferView(GlobalRootSignature::Slot::SceneConstant, m_sceneCB.GpuVirtualAddress(frameIndex)); // TODO-2.8: do a very similar operation for the m_aabbPrimitiveAttributeBuffer + m_aabbPrimitiveAttributeBuffer.CopyStagingToGpu(frameIndex); + commandList->SetComputeRootConstantBufferView(GlobalRootSignature::Slot::AABBattributeBuffer, m_aabbPrimitiveAttributeBuffer.GpuVirtualAddress(frameIndex)); // Bind the descriptor heaps. @@ -49,10 +51,10 @@ void DXProceduralProject::DoRaytracing() // This should be done by telling the commandList to SetComputeRoot*(). You just have to figure out what * is. // Example: in the case of GlobalRootSignature::Slot::SceneConstant above, we used SetComputeRootConstantBufferView() // Hint: look at CreateRootSignatures() in DXR-Pipeline.cpp. - + commandList->SetComputeRootDescriptorTable(GlobalRootSignature::Slot::VertexBuffers, m_indexBuffer.gpuDescriptorHandle); // TODO-2.8: Bind the OutputView (basically m_raytracingOutputResourceUAVGpuDescriptor). Very similar to the Index/Vertex buffer. - + commandList->SetComputeRootDescriptorTable(GlobalRootSignature::Slot::OutputView, m_raytracingOutputResourceUAVGpuDescriptor); // This will define a `DispatchRays` function that takes in a command list, a pipeline state, and a descriptor // This will set the hooks using the shader tables built before and call DispatchRays on the command list @@ -60,13 +62,22 @@ void DXProceduralProject::DoRaytracing() { // You will fill in a D3D12_DISPATCH_RAYS_DESC (which is dispatchDesc). // TODO-2.8: fill in dispatchDesc->HitGroupTable. Look up the struct D3D12_GPU_VIRTUAL_ADDRESS_RANGE_AND_STRIDE - + + dispatchDesc->HitGroupTable.StartAddress = m_hitGroupShaderTable->GetGPUVirtualAddress(); + dispatchDesc->HitGroupTable.StrideInBytes = m_hitGroupShaderTableStrideInBytes; + dispatchDesc->HitGroupTable.SizeInBytes = m_hitGroupShaderTable->GetDesc().Width; // TODO-2.8: now fill in dispatchDesc->MissShaderTable - + + dispatchDesc->MissShaderTable.StartAddress = m_missShaderTable->GetGPUVirtualAddress(); + dispatchDesc->MissShaderTable.StrideInBytes = m_missShaderTableStrideInBytes; + dispatchDesc->MissShaderTable.SizeInBytes = m_missShaderTable->GetDesc().Width; // TODO-2.8: now fill in dispatchDesc->RayGenerationShaderRecord - + + dispatchDesc->RayGenerationShaderRecord.StartAddress = m_rayGenShaderTable->GetGPUVirtualAddress(); + dispatchDesc->RayGenerationShaderRecord.SizeInBytes = m_rayGenShaderTable->GetDesc().Width; + // We do this for you. This will define how many threads will be dispatched. Basically like a blockDims in CUDA! dispatchDesc->Width = m_width; diff --git a/src/D3D12RaytracingProceduralGeometry/DXR-DynamicBuffers.cpp b/src/D3D12RaytracingProceduralGeometry/DXR-DynamicBuffers.cpp index e3ff63c..296d424 100644 --- a/src/D3D12RaytracingProceduralGeometry/DXR-DynamicBuffers.cpp +++ b/src/D3D12RaytracingProceduralGeometry/DXR-DynamicBuffers.cpp @@ -111,7 +111,10 @@ void DXProceduralProject::CreateConstantBuffers() // structured buffers are for structs that have dynamic data (e.g lights in a scene, or AABBs in this case) void DXProceduralProject::CreateAABBPrimitiveAttributesBuffers() { - + auto device = m_deviceResources->GetD3DDevice(); + auto aabbs = m_aabbs.size(); + + m_aabbPrimitiveAttributeBuffer.Create(device, aabbs, 1, L"Structured AABB Buffer"); } // LOOKAT-2.1: Update camera matrices stored in m_sceneCB. @@ -164,6 +167,11 @@ void DXProceduralProject::UpdateAABBPrimitiveAttributes(float animationTime) // You can infer what the bottom level AS space to local space transform should be. // The intersection shader tests in this project work with local space, but the geometries are provided in bottom level // AS space. So this data will be used to convert back and forth from these spaces. + auto t = XMMatrixMultiply(XMMatrixMultiply(mScale, mRotation), mTranslation); + m_aabbPrimitiveAttributeBuffer[primitiveIndex].localSpaceToBottomLevelAS = t; + auto inv = XMMatrixInverse(nullptr, t); + m_aabbPrimitiveAttributeBuffer[primitiveIndex].bottomLevelASToLocalSpace = inv; + }; UINT offset = 0; diff --git a/src/D3D12RaytracingProceduralGeometry/DXR-Geometry.cpp b/src/D3D12RaytracingProceduralGeometry/DXR-Geometry.cpp index 9d93504..a9bd485 100644 --- a/src/D3D12RaytracingProceduralGeometry/DXR-Geometry.cpp +++ b/src/D3D12RaytracingProceduralGeometry/DXR-Geometry.cpp @@ -87,6 +87,12 @@ void DXProceduralProject::BuildProceduralGeometryAABBs() auto InitializeAABB = [&](auto& offsetIndex, auto& size) { D3D12_RAYTRACING_AABB aabb{}; + aabb.MinX = basePosition.x + stride.x * offsetIndex.x; + aabb.MaxX = aabb.MinX + size.x; + aabb.MinY = basePosition.y + stride.y * offsetIndex.y; + aabb.MaxY = aabb.MinY + size.y; + aabb.MinX = basePosition.x + stride.z* offsetIndex.z; + aabb.MaxX = aabb.MinZ + size.z; return aabb; }; m_aabbs.resize(IntersectionShaderType::TotalPrimitiveCount); @@ -110,6 +116,7 @@ void DXProceduralProject::BuildProceduralGeometryAABBs() // TODO-2.5: Allocate an upload buffer for this AABB data. // The base data lives in m_aabbs.data() (the stuff you filled in!), but the allocationg should be pointed // towards m_aabbBuffer.resource (the actual D3D12 resource that will hold all of our AABB data as a contiguous buffer). + AllocateUploadBuffer(device, m_aabbs.data(), m_aabbs.size() * sizeof(m_aabbs[0]), &m_aabbBuffer.resource); } } @@ -117,5 +124,7 @@ void DXProceduralProject::BuildProceduralGeometryAABBs() // TODO-2.5: Build geometry used in the project. As easy as calling both functions above :) void DXProceduralProject::BuildGeometry() { + BuildPlaneGeometry(); + BuildProceduralGeometryAABBs(); } \ No newline at end of file diff --git a/src/D3D12RaytracingProceduralGeometry/DXR-HitGroup.cpp b/src/D3D12RaytracingProceduralGeometry/DXR-HitGroup.cpp index 33899bd..32e2500 100644 --- a/src/D3D12RaytracingProceduralGeometry/DXR-HitGroup.cpp +++ b/src/D3D12RaytracingProceduralGeometry/DXR-HitGroup.cpp @@ -29,7 +29,24 @@ void DXProceduralProject::CreateHitGroupSubobjects(CD3D12_STATE_OBJECT_DESC* ray // TODO-2.3: AABB geometry hit groups. Very similar to triangles, except now you have to *also* loop over the primitive types. { + for (UINT rayType = 0; rayType < RayType::Count; rayType++) + { + for (UINT primitiveType = 0; primitiveType < IntersectionShaderType::Count; primitiveType++) { + auto hitGroup = raytracingPipeline->CreateSubobject(); + if (rayType == RayType::Radiance) + { + // We import the closest hit shader name + hitGroup->SetClosestHitShaderImport(c_closestHitShaderNames[GeometryType::Triangle]); + } + // We tell the hitgroup that it should export into the correct shader hit group name, with the correct type + hitGroup->SetHitGroupExport(c_hitGroupNames_TriangleGeometry[rayType]); + hitGroup->SetHitGroupType(D3D12_HIT_GROUP_TYPE_TRIANGLES); + + //Needs intersection shader since not a triangle + hitGroup->SetIntersectionShaderImport(c_intersectionShaderNames[GeometryType::AABB]); + } + } } } @@ -54,6 +71,19 @@ void DXProceduralProject::CreateLocalRootSignatureSubobjects(CD3D12_STATE_OBJECT // TODO-2.3: AABB geometry hitgroup/local root signature association. // Very similar to triangles, except now one for each primitive type. { + + + auto localRootSignature = raytracingPipeline->CreateSubobject(); + + // This is the triangle local root signature you already filled in before. + localRootSignature->SetRootSignature(m_raytracingLocalRootSignature[LocalRootSignature::Type::Triangle].Get()); + + // Shader association + auto rootSignatureAssociation = raytracingPipeline->CreateSubobject(); + rootSignatureAssociation->SetSubobjectToAssociate(*localRootSignature); + for (UINT primitiveType = 0; primitiveType < IntersectionShaderType::Count; primitiveType++) { + rootSignatureAssociation->AddExports(c_hitGroupNames_AABBGeometry[primitiveType]); + } } } \ No newline at end of file diff --git a/src/D3D12RaytracingProceduralGeometry/DXR-RootSignature.cpp b/src/D3D12RaytracingProceduralGeometry/DXR-RootSignature.cpp index 2dff8b5..bc385bc 100644 --- a/src/D3D12RaytracingProceduralGeometry/DXR-RootSignature.cpp +++ b/src/D3D12RaytracingProceduralGeometry/DXR-RootSignature.cpp @@ -21,17 +21,10 @@ void DXProceduralProject::CreateRootSignatures() // TODO-2.2: In range index 1 (the second range), initialize 2 SRV resources at register 1: indices and vertices of triangle data. // This will effectively put the indices at register 1, and the vertices at register 2. - + ranges[1].Init(D3D12_DESCRIPTOR_RANGE_TYPE_SRV, 2, 1); // TODO-2.2: Initialize all the parameters of the GlobalRootSignature in their appropriate slots. // * See GlobalRootSignature in RaytracingSceneDefines.h to understand what they are. - // - The OutputView should correspond to the UAV range descriptor above (descriptor table), bound to register 0 of the UAV registers. - // - The Index/Vertex Buffer should correspond to the SRV range (descriptor table) above, bound to registers 1 and 2 of the SRV registers. - // Note that since we initialize these as a range of size 2, then you should bind the entire range to register 1. - // This will automatically fill in registers 1 and 2. - // - The AccelerationStructure should be init as SRV bound to register 0 of the SRV registers. - // - The SceneConstant should be init as a ConstantBufferView (CBV) bound to register 0 of the CBV registers. - // - The AABBAttributeBuffer should be init as SRV bound to register 3 of the SRV registers. // - Look up InitAsDescriptorTable(), InitAsShaderResourceView(), and InitAsConstantBuffer() in the DirectX documentation // to understand what to do. // - If you're ever unsure if the register mapping is correct, look at the top of Raytracing.hlsl. @@ -39,6 +32,24 @@ void DXProceduralProject::CreateRootSignatures() // t registers --> SRV // b registers --> CBV CD3DX12_ROOT_PARAMETER rootParameters[GlobalRootSignature::Slot::Count]; + // - The OutputView should correspond to the UAV range descriptor above (descriptor table), bound to register 0 of the UAV registers. + rootParameters[GlobalRootSignature::Slot::OutputView].InitAsDescriptorTable(1, &(ranges[0])); + // - The Index/Vertex Buffer should correspond to the SRV range (descriptor table) above, bound to registers 1 and 2 of the SRV registers. + // Note that since we initialize these as a range of size 2, then you should bind the entire range to register 1. + // This will automatically fill in registers 1 and 2. + rootParameters[GlobalRootSignature::Slot::VertexBuffers].InitAsDescriptorTable(1, &(ranges[1])); + // - The AccelerationStructure should be init as SRV bound to register 0 of the SRV (Shader Resource View) registers. + rootParameters[GlobalRootSignature::Slot::AccelerationStructure].InitAsShaderResourceView(0); + // - The SceneConstant should be init as a ConstantBufferView (CBV) bound to register 0 of the CBV registers. + rootParameters[GlobalRootSignature::Slot::SceneConstant].InitAsConstantBufferView(0); + // - The AABBAttributeBuffer should be init as SRV bound to register 3 of the SRV registers. + rootParameters[GlobalRootSignature::Slot::AABBattributeBuffer].InitAsShaderResourceView(3); + + + + + + // Finally, we bundle up all the descriptors you filled up and tell the device to create this global root signature! CD3DX12_ROOT_SIGNATURE_DESC globalRootSignatureDesc(ARRAYSIZE(rootParameters), rootParameters); @@ -67,6 +78,16 @@ void DXProceduralProject::CreateRootSignatures() // to register 1, this overlap is allowed since we are talking about *local* root signatures // --> the values they hold will depend on the shader function the local signature is bound to! { + namespace RootSignatureSlots = LocalRootSignature::AABB::Slot; + CD3DX12_ROOT_PARAMETER rootParameters[RootSignatureSlots::Count]; + rootParameters[RootSignatureSlots::MaterialConstant].InitAsConstants(SizeOfInUint32(PrimitiveConstantBuffer), 1); + rootParameters[RootSignatureSlots::GeometryIndex].InitAsConstants(SizeOfInUint32(PrimitiveConstantBuffer), 2); + + CD3DX12_ROOT_SIGNATURE_DESC localRootSignatureDesc(ARRAYSIZE(rootParameters), rootParameters); + + localRootSignatureDesc.Flags = D3D12_ROOT_SIGNATURE_FLAG_LOCAL_ROOT_SIGNATURE; + SerializeAndCreateRaytracingRootSignature(localRootSignatureDesc, &m_raytracingLocalRootSignature[LocalRootSignature::Type::AABB]); + } } diff --git a/src/D3D12RaytracingProceduralGeometry/DXR-ShaderTable.cpp b/src/D3D12RaytracingProceduralGeometry/DXR-ShaderTable.cpp index 150e92d..79290ec 100644 --- a/src/D3D12RaytracingProceduralGeometry/DXR-ShaderTable.cpp +++ b/src/D3D12RaytracingProceduralGeometry/DXR-ShaderTable.cpp @@ -32,8 +32,10 @@ void DXProceduralProject::BuildShaderTables() // TODO-2.7: Miss shaders. // Similar to the raygen shader, but now we have 1 for each ray type (radiance, shadow) // Don't forget to update shaderIdToStringMap. - missShaderIDs[0] = nullptr; - missShaderIDs[1] = nullptr; + missShaderIDs[0] = stateObjectProperties->GetShaderIdentifier(c_missShaderNames[0]); + shaderIdToStringMap[missShaderIDs[0]] = c_missShaderNames[0]; + missShaderIDs[1] = stateObjectProperties->GetShaderIdentifier(c_missShaderNames[1]); + shaderIdToStringMap[missShaderIDs[1]] = c_missShaderNames[1]; // Hitgroup shaders for the Triangle. We have 2: one for radiance ray, and another for the shadow ray. for (UINT i = 0; i < RayType::Count; i++) @@ -44,6 +46,14 @@ void DXProceduralProject::BuildShaderTables() // TODO-2.7: Hitgroup shaders for the AABBs. We have 2 for each AABB. + for (UINT i = 0; i < IntersectionShaderType::Count; i++) + { + for (UINT j = 0; j < RayType::Count; j++) { + hitGroupShaderIDs_AABBGeometry[i][j] = stateObjectProperties->GetShaderIdentifier(c_hitGroupNames_AABBGeometry[i][j]); + shaderIdToStringMap[hitGroupShaderIDs_AABBGeometry[i][j]] = c_hitGroupNames_AABBGeometry[i][j]; + } + } + }; // Get shader identifiers using the lambda function defined above. @@ -95,9 +105,23 @@ void DXProceduralProject::BuildShaderTables() // TODO-2.7: Miss shader table. Very similar to the RayGen table except now we push_back() 2 shader records // 1 for the radiance ray, 1 for the shadow ray. Don't forget to call DebugPrint() on the table for your sanity! { + UINT numShaderRecords = 2; + UINT shaderRecordSize = shaderIDSize; // No root arguments + + // The RayGen shader table contains a single ShaderRecord: the one single raygen shader! + ShaderTable missShaderTable(device, numShaderRecords, shaderRecordSize, L"MissShaderTable"); + + // Push back the shader record, which does not need any root signatures. + missShaderTable.push_back(ShaderRecord(missShaderIDs[0], shaderRecordSize, nullptr, 0)); + missShaderTable.push_back(ShaderRecord(missShaderIDs[1], shaderRecordSize, nullptr, 0)); + // Save the uploaded resource (remember that the uploaded resource is created when we call Allocate() on a GpuUploadBuffer + missShaderTable.DebugPrint(shaderIdToStringMap); + m_missShaderTable = missShaderTable.GetResource(); + m_missShaderTableStrideInBytes = missShaderTable.GetShaderRecordSize(); } + // Hit group shader table. This one is slightly different given that a hit group requires its own custom root signature. // You defined the root signatures in DXR-Pipeline.cpp, and you can refresh your memory as to what these local root signatures // hold by looking at RaytracingSceneDefines.h. diff --git a/src/D3D12RaytracingProceduralGeometry/Raytracing.hlsl b/src/D3D12RaytracingProceduralGeometry/Raytracing.hlsl index d066933..a68bf4c 100644 --- a/src/D3D12RaytracingProceduralGeometry/Raytracing.hlsl +++ b/src/D3D12RaytracingProceduralGeometry/Raytracing.hlsl @@ -149,9 +149,9 @@ bool TraceShadowRayAndReportIfHit(in Ray ray, in UINT currentRayRecursionDepth) [shader("raygeneration")] void MyRaygenShader() { - - // Write the color to the render target - g_renderTarget[DispatchRaysIndex().xy] = float4(0.0f, 0.0f, 0.0f, 0.0f); + Ray ray = GenerateCameraRay(DispatchRaysIndex().xy, g_sceneCB.cameraPosition.xyz, g_sceneCB.projectionToWorld); + // Write the color to the render target + g_renderTarget[DispatchRaysIndex().xy] = TraceRadianceRay(ray, 0); } //*************************************************************************** diff --git a/src/D3D12RaytracingProceduralGeometry/RaytracingShaderHelper.hlsli b/src/D3D12RaytracingProceduralGeometry/RaytracingShaderHelper.hlsli index 94bf5cc..167192c 100644 --- a/src/D3D12RaytracingProceduralGeometry/RaytracingShaderHelper.hlsli +++ b/src/D3D12RaytracingProceduralGeometry/RaytracingShaderHelper.hlsli @@ -130,9 +130,13 @@ float3 HitAttribute(float3 vertexAttribute[3], float2 barycentrics) inline Ray GenerateCameraRay(uint2 index, in float3 cameraPosition, in float4x4 projectionToWorld) { Ray ray; - ray.origin = float3(0.0f, 0.0f, 0.0f); - ray.direction = normalize(float3(0.0f, 0.0f, 0.0f)); - + ray.origin = cameraPosition; + uint3 screen = DispatchRaysDimensions(); + float normal_x = (index.x + 0.5f / screen.x) * 2.0f - 1.0f; + float normal_y = 1.0f - ((index.y + 0.5f) / screen.y) * 2.0f; + float4 normal_coords = mul(float4(normal_x, normal_y, 1.0f, 1.0f), projectionToWorld); + normal_coords /= normal_coords.w; + ray.direction = normalize(normal_coords.xyz - ray.origin); return ray; }