Skip to content

Project 5: Davis Polito #41

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 1 commit into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Binary file added .README.md.un~
Binary file not shown.
26 changes: 18 additions & 8 deletions README.md
Original file line number Diff line number Diff line change
@@ -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
21 changes: 21 additions & 0 deletions README.md~
Original file line number Diff line number Diff line change
@@ -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
70 changes: 58 additions & 12 deletions src/D3D12RaytracingProceduralGeometry/DXR-AccelerationStructure.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -32,8 +32,15 @@ void DXProceduralProject::BuildGeometryDescsForBottomLevelAS(array<vector<D3D12_
// * We filled in the format of the buffers to avoid confusion.
auto& geometryDesc = geometryDescs[BottomLevelASType::Triangle][0];
geometryDesc = {};
geometryDesc.Flags = geometryFlags;
geometryDesc.Triangles.IndexFormat = DXGI_FORMAT_R16_UINT;
geometryDesc.Triangles.IndexBuffer = m_indexBuffer.resource->GetGPUVirtualAddress();
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);

}

{
Expand All @@ -51,7 +58,9 @@ void DXProceduralProject::BuildGeometryDescsForBottomLevelAS(array<vector<D3D12_
// Remember to use m_aabbBuffer to get the AABB geometry data you previously filled in.
// Note: Having separate geometries allows of separate shader record binding per geometry.
// In this project, this lets us specify custom hit groups per AABB geometry.

for (UINT primitiveType = 0; primitiveType < IntersectionShaderType::TotalPrimitiveCount; primitiveType++) {
geometryDescs[BottomLevelASType::AABB][primitiveType].AABBs.AABBs.StartAddress = m_aabbBuffer.resource->GetGPUVirtualAddress() + primitiveType * sizeof(D3D12_RAYTRACING_AABB);
}
}
}

Expand All @@ -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.
Expand Down Expand Up @@ -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)
Expand All @@ -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.
Expand Down Expand Up @@ -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<XMFLOAT3X4*>(instanceDesc.Transform), mTransform);
}

// Upload all these instances to the GPU, and make sure the resouce is set to instanceDescsResource.
Expand All @@ -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)
Expand All @@ -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.
{
Expand All @@ -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:
Expand Down Expand Up @@ -261,7 +294,8 @@ AccelerationStructureBuffers DXProceduralProject::BuildTopLevelAS(AccelerationSt
};

// TODO-2.6: Call the fallback-templated version of BuildBottomLevelASInstanceDescs() you completed above.

BuildBottomLevelASInstanceDescs<D3D12_RAYTRACING_FALLBACK_INSTANCE_DESC, WRAPPED_GPU_POINTER>(bottomLevelASaddresses, &instanceDescsResource);

}
else // DirectX Raytracing
{
Expand All @@ -273,7 +307,8 @@ AccelerationStructureBuffers DXProceduralProject::BuildTopLevelAS(AccelerationSt
};

// TODO-2.6: Call the DXR-templated version of BuildBottomLevelASInstanceDescs() you completed above.

BuildBottomLevelASInstanceDescs<D3D12_RAYTRACING_INSTANCE_DESC, D3D12_GPU_VIRTUAL_ADDRESS>(bottomLevelASaddresses, &instanceDescsResource);

}

// Create a wrapped pointer to the acceleration structure.
Expand All @@ -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)
Expand All @@ -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.
Expand All @@ -320,12 +357,15 @@ void DXProceduralProject::BuildAccelerationStructures()

// TODO-2.6: Build the geometry descriptors. Hint: you filled in a function that does this.
array<vector<D3D12_RAYTRACING_GEOMETRY_DESC>, 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.
Expand All @@ -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.
Expand All @@ -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;

}
21 changes: 16 additions & 5 deletions src/D3D12RaytracingProceduralGeometry/DXR-DoRaytracing.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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.
Expand Down Expand Up @@ -49,24 +51,33 @@ 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
auto DispatchRays = [&](auto* raytracingCommandList, auto* stateObject, auto* dispatchDesc)
{
// 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;
Expand Down
10 changes: 9 additions & 1 deletion src/D3D12RaytracingProceduralGeometry/DXR-DynamicBuffers.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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.
Expand Down Expand Up @@ -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;
Expand Down
9 changes: 9 additions & 0 deletions src/D3D12RaytracingProceduralGeometry/DXR-Geometry.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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);
Expand All @@ -110,12 +116,15 @@ 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);

}
}

// TODO-2.5: Build geometry used in the project. As easy as calling both functions above :)
void DXProceduralProject::BuildGeometry()
{
BuildPlaneGeometry();
BuildProceduralGeometryAABBs();

}
Loading