diff --git a/DXR-Project.sdf b/DXR-Project.sdf
new file mode 100644
index 0000000..81000cb
Binary files /dev/null and b/DXR-Project.sdf differ
diff --git a/DXR-Project.suo b/DXR-Project.suo
new file mode 100644
index 0000000..1295b3c
Binary files /dev/null and b/DXR-Project.suo differ
diff --git a/Libraries/D3D12RaytracingFallback/src/FallbackLayer.vcxproj.filters b/Libraries/D3D12RaytracingFallback/src/FallbackLayer.vcxproj.filters
index cc2db39..b2678ea 100644
--- a/Libraries/D3D12RaytracingFallback/src/FallbackLayer.vcxproj.filters
+++ b/Libraries/D3D12RaytracingFallback/src/FallbackLayer.vcxproj.filters
@@ -201,6 +201,12 @@
+
+
+
+
+
+
diff --git a/README.md b/README.md
index b0189d0..e268d78 100644
--- a/README.md
+++ b/README.md
@@ -1,11 +1,86 @@
**University of Pennsylvania, CIS 565: GPU Programming and Architecture,
Project 5 - DirectX Procedural Raytracing**
-* (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)
+* Saket Karve
+ * [LinkedIn](https://www.linkedin.com/in/saket-karve-43930511b/), [twitter](), etc.
+* Tested on: Windows 10, Intel(R) Core(TM) i7-6700 CPU @ 3.40GHz 16GB, NVIDIA Titan V (SIGLAB)
-### (TODO: Your README)
+### Highlights
-Include screenshots, analysis, etc. (Remember, this is public, so don't put
-anything here that you don't want to share with the world.)
+
+
+### Contents
+
+- Ray Tracing
+- Outputs
+- Performance Analysis
+- Bloopers
+
+### Ray Tracing
+
+ray tracing is a process similar to path tracing, except that it is deterministic (no more probabilities!) and that we only do a single pass over the entire scene (no more multiple iterations). This image summarizes what goes on in ray tracing:
+
+
+
+
+
+Specifically, the DXR execution pipeline mimics all the interactions depicted above. This diagram summarizes the DXR execution pipeline:
+
+
+
+
+
+This does not prevent us from calling `TraceRay()` multiple times. In fact, any self-respecting raytracing project will allow multiple (~3) `TraceRay()` calls. The common denominator between ray and path tracing is the depth of the ray. In this project, we use a *minimum depth of 3* to allow tracing the following:
+
+1. a **primary (radiance) ray** generated from the camera
+2. a **shadow ray** just in case the ray hits a geometry on its way to the light source
+3. a **reflection** ray in case the material of the object is reflective
+
+Therefore, the lifecycle of a single ray can be thought of as follows:
+
+1. generate a ray, see if it hits something
+2. if it hits something, then attempt to *light/color* it
+ * attempting to color that hit point is equivalent to **tracing that ray towards the light source**.
+ * if that ray hits *another* object on its way to the light, then the region is effectively shadowed
+ * if not, then we successfully colored that point
+3. if at any point we hit a reflective material, then trace another ray in the reflected direction and repeat the process
+
+### Outputs
+
+After completing all parts of the assignment, following output was observed.
+
+
+
+Adding a fourth sphere to the metaball produced this output.
+
+
+
+Enabling lighting animation.
+
+
+
+I tried using Sigmoid function to produce the blur effect for long distance objects. Following output was produced when a suffucient offset was used.
+
+
+
+### Performance Analysis
+
+The performance of the render was tested for different values of Recursion depth. Performance is measured in terms of frames per second of the render.
+
+
+
+It can be seen from the figure that the performance decreases with increasing depth. This is because for every render, the ray is traced more number of times. However, after a certain depth, the performance more or less remains same since the ray will most probably bounce into a light source (radiance ray) or become a shadow ray.
+
+### Bloopers
+
+Incorrect conversion to normalized device coordinates. Produced an inverted image
+
+
+
+Forgot to change the function producing blur effect for AABB and changed it only for triangles.
+
+
+
+Sigmoid function for blur effect without any offset generated an image with a smoke/fog like effect
+
+
diff --git a/images/Q3.PNG b/images/Q3.PNG
new file mode 100644
index 0000000..18036e0
Binary files /dev/null and b/images/Q3.PNG differ
diff --git a/images/four_spheres.gif b/images/four_spheres.gif
new file mode 100644
index 0000000..d1195b4
Binary files /dev/null and b/images/four_spheres.gif differ
diff --git a/images/incorrect_ndc.JPG b/images/incorrect_ndc.JPG
new file mode 100644
index 0000000..1cce7a7
Binary files /dev/null and b/images/incorrect_ndc.JPG differ
diff --git a/images/lerp_didnot_change_for_AABB.JPG b/images/lerp_didnot_change_for_AABB.JPG
new file mode 100644
index 0000000..269be68
Binary files /dev/null and b/images/lerp_didnot_change_for_AABB.JPG differ
diff --git a/images/performance.PNG b/images/performance.PNG
new file mode 100644
index 0000000..64675b6
Binary files /dev/null and b/images/performance.PNG differ
diff --git a/images/sigmoid.JPG b/images/sigmoid.JPG
new file mode 100644
index 0000000..4830f1e
Binary files /dev/null and b/images/sigmoid.JPG differ
diff --git a/images/sigmoid50.JPG b/images/sigmoid50.JPG
new file mode 100644
index 0000000..cd02100
Binary files /dev/null and b/images/sigmoid50.JPG differ
diff --git a/images/three_spheres.gif b/images/three_spheres.gif
new file mode 100644
index 0000000..1f3c29c
Binary files /dev/null and b/images/three_spheres.gif differ
diff --git a/images/three_spheres1.gif b/images/three_spheres1.gif
new file mode 100644
index 0000000..cd5ac19
Binary files /dev/null and b/images/three_spheres1.gif differ
diff --git a/images/three_spheres_camera_still.JPG b/images/three_spheres_camera_still.JPG
new file mode 100644
index 0000000..cd23efe
Binary files /dev/null and b/images/three_spheres_camera_still.JPG differ
diff --git a/images/three_spheres_light.gif b/images/three_spheres_light.gif
new file mode 100644
index 0000000..56afe07
Binary files /dev/null and b/images/three_spheres_light.gif differ
diff --git a/images/three_spheres_light_still.JPG b/images/three_spheres_light_still.JPG
new file mode 100644
index 0000000..a13474f
Binary files /dev/null and b/images/three_spheres_light_still.JPG differ
diff --git a/images/three_spheres_still.JPG b/images/three_spheres_still.JPG
new file mode 100644
index 0000000..1f1613a
Binary files /dev/null and b/images/three_spheres_still.JPG differ
diff --git a/src/D3D12RaytracingProceduralGeometry/AnalyticPrimitives.hlsli b/src/D3D12RaytracingProceduralGeometry/AnalyticPrimitives.hlsli
index c6ccebb..b508df1 100644
--- a/src/D3D12RaytracingProceduralGeometry/AnalyticPrimitives.hlsli
+++ b/src/D3D12RaytracingProceduralGeometry/AnalyticPrimitives.hlsli
@@ -103,7 +103,7 @@ float3 CalculateNormalForARaySphereHit(in Ray ray, in float thit, float3 center)
}
// Test if a ray with RayFlags and segment intersects a hollow sphere.
-bool RaySphereIntersectionTest(in Ray ray, out float thit, out float tmax, in ProceduralPrimitiveAttributes attr, in float3 center = float3(0, 0, 0), in float radius = 1)
+bool RaySphereIntersectionTest(in Ray ray, out float thit, out float tmax, out ProceduralPrimitiveAttributes attr, in float3 center = float3(0, 0, 0), in float radius = 1)
{
float t0, t1; // solutions for t if the ray intersects
@@ -166,18 +166,27 @@ bool RaySolidSphereIntersectionTest(in Ray ray, out float thit, out float tmax,
bool RayMultipleSpheresIntersectionTest(in Ray ray, out float thit, out ProceduralPrimitiveAttributes attr)
{
// Define the spheres in local space (within the aabb)
- float3 center = float3(-0.2, 0, -0.2);
- float radius = 0.7f;
+ float3 centers[3] = { float3(-0.2, 0, -0.2), float3(-0.5, 0.5, -0.5), float3(0.2, 0, 0.2) };
+ float radii[3] = { 0.7f, 0.3f, 0.5f };
thit = RayTCurrent();
float tmax;
- if (RaySphereIntersectionTest(ray, thit, tmax, attr, center, radius))
- {
- return true;
+ float curr_thit = thit;
+ ProceduralPrimitiveAttributes curr_attr;
+ bool hit = false;
+ for (int i = 0; i < 3; i++) {
+ if (RaySphereIntersectionTest(ray, curr_thit, tmax, curr_attr, centers[i], radii[i]))
+ {
+ if (curr_thit < thit) {
+ thit = curr_thit;
+ attr = curr_attr;
+ }
+ hit = true;
+ }
}
-
- return false;
+ return hit;
+
}
#endif // ANALYTICPRIMITIVES_H
\ No newline at end of file
diff --git a/src/D3D12RaytracingProceduralGeometry/D3D12RaytracingProceduralGeometry.vcxproj b/src/D3D12RaytracingProceduralGeometry/D3D12RaytracingProceduralGeometry.vcxproj
index 4a8b9ab..5fb1399 100644
--- a/src/D3D12RaytracingProceduralGeometry/D3D12RaytracingProceduralGeometry.vcxproj
+++ b/src/D3D12RaytracingProceduralGeometry/D3D12RaytracingProceduralGeometry.vcxproj
@@ -15,7 +15,7 @@
Win32ProjD3D12RaytracingD3D12RaytracingProceduralGeometry
- 10.0.17763.0
+ 10.0.18362.0
@@ -76,8 +76,9 @@
Windowstrue
- d3d12.lib;dxgi.lib;dxguid.lib;kernel32.lib;user32.lib;gdi32.lib;winspool.lib;comdlg32.lib;advapi32.lib;shell32.lib;ole32.lib;oleaut32.lib;uuid.lib;odbc32.lib;odbccp32.lib;%(AdditionalDependencies)
+ d3d12.lib;dxgi.lib;dxguid.lib;kernel32.lib;user32.lib;gdi32.lib;winspool.lib;comdlg32.lib;advapi32.lib;shell32.lib;ole32.lib;oleaut32.lib;uuid.lib;odbc32.lib;odbccp32.lib;C:\Program Files (x86)\Microsoft Visual Studio\2017\Community\VC\Tools\MSVC\14.16.27023\atlmfc\lib\x64\atls.lib;%(AdditionalDependencies)d3d12.dll
+ C:\Program Files (x86)\Microsoft Visual Studio\2017\Community\VC\Tools\MSVC\14.16.27023\atlmfc\lib\x64\;%(AdditionalLibraryDirectories)true
@@ -131,6 +132,7 @@ PrebuildCheck.bat
trued3d12.lib;dxgi.lib;kernel32.lib;user32.lib;gdi32.lib;winspool.lib;comdlg32.lib;advapi32.lib;shell32.lib;ole32.lib;oleaut32.lib;uuid.lib;odbc32.lib;odbccp32.lib;%(AdditionalDependencies)d3d12.dll
+ C:\Program Files (x86)\Microsoft Visual Studio\2017\Community\VC\Tools\MSVC\14.16.27023\atlmfc\lib\x64\;%(AdditionalLibraryDirectories)true
diff --git a/src/D3D12RaytracingProceduralGeometry/DXR-AccelerationStructure.cpp b/src/D3D12RaytracingProceduralGeometry/DXR-AccelerationStructure.cpp
index 905341d..00270af 100644
--- a/src/D3D12RaytracingProceduralGeometry/DXR-AccelerationStructure.cpp
+++ b/src/D3D12RaytracingProceduralGeometry/DXR-AccelerationStructure.cpp
@@ -31,9 +31,15 @@ void DXProceduralProject::BuildGeometryDescsForBottomLevelAS(arrayGetDesc().Width)
// * We filled in the format of the buffers to avoid confusion.
auto& geometryDesc = geometryDescs[BottomLevelASType::Triangle][0];
- geometryDesc = {};
+ geometryDesc = {};
+ geometryDesc.Flags = geometryFlags;
+ geometryDesc.Type = D3D12_RAYTRACING_GEOMETRY_TYPE_TRIANGLES;
geometryDesc.Triangles.IndexFormat = DXGI_FORMAT_R16_UINT;
geometryDesc.Triangles.VertexFormat = DXGI_FORMAT_R32G32B32_FLOAT;
+ geometryDesc.Triangles.IndexCount = m_indexBuffer.resource->GetDesc().Width / sizeof(Index);
+ geometryDesc.Triangles.VertexCount = m_vertexBuffer.resource->GetDesc().Width / sizeof(Vertex);
+ geometryDesc.Triangles.IndexBuffer = m_indexBuffer.resource->GetGPUVirtualAddress();
+ geometryDesc.Triangles.VertexBuffer = {m_vertexBuffer.resource->GetGPUVirtualAddress(), 2 * sizeof(XMFLOAT3)};
}
{
@@ -51,7 +57,10 @@ void DXProceduralProject::BuildGeometryDescsForBottomLevelAS(arrayGetGPUVirtualAddress() + primitiveType * sizeof(D3D12_RAYTRACING_AABB);
+ }
}
}
@@ -70,7 +79,11 @@ 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.Type = D3D12_RAYTRACING_ACCELERATION_STRUCTURE_TYPE_BOTTOM_LEVEL;
+ bottomLevelInputs.Flags = buildFlags;
+ bottomLevelInputs.NumDescs = geometryDescs.size();
+ bottomLevelInputs.DescsLayout = D3D12_ELEMENTS_LAYOUT_ARRAY;
+ bottomLevelInputs.pGeometryDescs = geometryDescs.data();
// Query the driver for resource requirements to build an acceleration structure. We've done this for you.
D3D12_RAYTRACING_ACCELERATION_STRUCTURE_PREBUILD_INFO bottomLevelPrebuildInfo = {};
@@ -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,12 @@ 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{};
+ return AccelerationStructureBuffers{
+ scratch,
+ bottomLevelAS,
+ nullptr,
+ bottomLevelPrebuildInfo.ResultDataMaxSizeInBytes
+ };
}
// TODO-2.6: Build the instance descriptor for each bottom-level AS you built before.
@@ -181,7 +200,19 @@ void DXProceduralProject::BuildBottomLevelASInstanceDescs(BLASPtrType *bottomLev
// 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];
+
+ const XMVECTOR vBasePosition = XMLoadFloat3(&XMFLOAT3(0.0f, c_aabbWidth * 0.5f , 0.0f));
+ XMMATRIX mTranslation = XMMatrixTranslationFromVector(vBasePosition);
+ XMMATRIX mTransform = mTranslation;
+
+ // 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 +235,12 @@ 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.Type = D3D12_RAYTRACING_ACCELERATION_STRUCTURE_TYPE_TOP_LEVEL;
+ topLevelInputs.Flags = buildFlags;
+ topLevelInputs.NumDescs = BottomLevelASType::Count;
+ topLevelInputs.DescsLayout = D3D12_ELEMENTS_LAYOUT_ARRAY;
+ //CHECK AGAIN
+ //topLevelInputs.InstanceDescs = bottomLevelAS;
D3D12_RAYTRACING_ACCELERATION_STRUCTURE_PREBUILD_INFO topLevelPrebuildInfo = {};
if (m_raytracingAPI == RaytracingAPI::FallbackLayer)
@@ -218,7 +254,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"ScratchResource");
// Allocate space for the top-level AS.
{
@@ -233,7 +269,7 @@ AccelerationStructureBuffers DXProceduralProject::BuildTopLevelAS(AccelerationSt
}
// TODO-2.6: Allocate a UAV buffer for the actual top-level AS.
-
+ AllocateUAVBuffer(device, topLevelPrebuildInfo.ResultDataMaxSizeInBytes, &topLevelAS, initialResourceState, L"TopLevelAccelerationStructure");
}
// Note on Emulated GPU pointers (AKA Wrapped pointers) requirement in Fallback Layer:
@@ -261,6 +297,7 @@ 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 +310,7 @@ 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 +322,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 +343,12 @@ 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,11 +364,14 @@ 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(auto bottomLevelASCount = 0; bottomLevelASCount < BottomLevelASType::Count; bottomLevelASCount++){
+ bottomLevelAS[bottomLevelASCount] = BuildBottomLevelAS(geometryDescs[bottomLevelASCount]);
+ }
// Batch all resource barriers for bottom-level AS builds.
@@ -337,8 +384,7 @@ void DXProceduralProject::BuildAccelerationStructures()
commandList->ResourceBarrier(BottomLevelASType::Count, resourceBarriers);
// TODO-2.6: Build top-level AS. Hint, you already made a function that does this.
- AccelerationStructureBuffers topLevelAS;
-
+ AccelerationStructureBuffers topLevelAS = BuildTopLevelAS(bottomLevelAS);
// Kick off acceleration structure construction.
m_deviceResources->ExecuteCommandList();
@@ -349,5 +395,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(auto bottomLevelASCount = 0; bottomLevelASCount < BottomLevelASType::Count; bottomLevelASCount++){
+ m_bottomLevelAS[bottomLevelASCount] = bottomLevelAS[bottomLevelASCount].accelerationStructure;
+ }
+ //CHECK AGAIN
+ 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..0362994 100644
--- a/src/D3D12RaytracingProceduralGeometry/DXR-DoRaytracing.cpp
+++ b/src/D3D12RaytracingProceduralGeometry/DXR-DoRaytracing.cpp
@@ -22,7 +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->SetComputeRootShaderResourceView(GlobalRootSignature::Slot::AABBattributeBuffer, m_aabbPrimitiveAttributeBuffer.GpuVirtualAddress(frameIndex));
// Bind the descriptor heaps.
if (m_raytracingAPI == RaytracingAPI::FallbackLayer)
@@ -49,10 +50,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 +61,13 @@ 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 = { m_hitGroupShaderTable->GetGPUVirtualAddress(), m_hitGroupShaderTable->GetDesc().Width, m_hitGroupShaderTableStrideInBytes };
// TODO-2.8: now fill in dispatchDesc->MissShaderTable
-
+ dispatchDesc->MissShaderTable = { m_missShaderTable->GetGPUVirtualAddress(), m_missShaderTable->GetDesc().Width, m_missShaderTableStrideInBytes };
// TODO-2.8: now fill in dispatchDesc->RayGenerationShaderRecord
-
+ dispatchDesc->RayGenerationShaderRecord = { m_rayGenShaderTable->GetGPUVirtualAddress(), 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..0fa5433 100644
--- a/src/D3D12RaytracingProceduralGeometry/DXR-DynamicBuffers.cpp
+++ b/src/D3D12RaytracingProceduralGeometry/DXR-DynamicBuffers.cpp
@@ -111,6 +111,11 @@ 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 num_elements = m_aabbs.size();
+ auto frameCount = m_deviceResources->GetBackBufferCount();
+
+ m_aabbPrimitiveAttributeBuffer.Create(device, num_elements, frameCount, L"Scene Structured Buffer");
}
@@ -164,6 +169,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.
+ XMMATRIX transform = XMMatrixMultiply(mScale, mRotation);
+ XMMATRIX final_transform = XMMatrixMultiply(transform, mTranslation);
+ XMMATRIX final_inverse_transform = XMMatrixInverse(nullptr, final_transform);
+ m_aabbPrimitiveAttributeBuffer[primitiveIndex].localSpaceToBottomLevelAS = final_transform;
+ m_aabbPrimitiveAttributeBuffer[primitiveIndex].bottomLevelASToLocalSpace = final_inverse_transform;
};
UINT offset = 0;
diff --git a/src/D3D12RaytracingProceduralGeometry/DXR-Geometry.cpp b/src/D3D12RaytracingProceduralGeometry/DXR-Geometry.cpp
index 9d93504..aecf053 100644
--- a/src/D3D12RaytracingProceduralGeometry/DXR-Geometry.cpp
+++ b/src/D3D12RaytracingProceduralGeometry/DXR-Geometry.cpp
@@ -86,7 +86,14 @@ void DXProceduralProject::BuildProceduralGeometryAABBs()
// This should take into account the basePosition and the stride defined above.
auto InitializeAABB = [&](auto& offsetIndex, auto& size)
{
- D3D12_RAYTRACING_AABB aabb{};
+ D3D12_RAYTRACING_AABB aabb{
+ basePosition.x + offsetIndex.x * stride.x,
+ basePosition.y + offsetIndex.y * stride.y,
+ basePosition.z + offsetIndex.z * stride.z,
+ basePosition.x + offsetIndex.x * stride.x + size.x,
+ basePosition.y + offsetIndex.y * stride.y + size.y,
+ basePosition.z + offsetIndex.z * stride.z + size.z,
+ };
return aabb;
};
m_aabbs.resize(IntersectionShaderType::TotalPrimitiveCount);
@@ -110,12 +117,14 @@ 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();
}
\ No newline at end of file
diff --git a/src/D3D12RaytracingProceduralGeometry/DXR-HitGroup.cpp b/src/D3D12RaytracingProceduralGeometry/DXR-HitGroup.cpp
index 33899bd..ef15c01 100644
--- a/src/D3D12RaytracingProceduralGeometry/DXR-HitGroup.cpp
+++ b/src/D3D12RaytracingProceduralGeometry/DXR-HitGroup.cpp
@@ -29,7 +29,23 @@ 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::AABB]);
+ }
+ //Set Intersection shader for hitgroup
+ hitGroup->SetIntersectionShaderImport(c_intersectionShaderNames[primitiveType]);
+ // We tell the hitgroup that it should export into the correct shader hit group name, with the correct type
+ hitGroup->SetHitGroupExport(c_hitGroupNames_AABBGeometry[primitiveType][rayType]);
+ hitGroup->SetHitGroupType(D3D12_HIT_GROUP_TYPE_PROCEDURAL_PRIMITIVE);
+ }
+ }
}
}
@@ -55,5 +71,16 @@ void DXProceduralProject::CreateLocalRootSignatureSubobjects(CD3D12_STATE_OBJECT
// 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::AABB].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..77bbaf3 100644
--- a/src/D3D12RaytracingProceduralGeometry/DXR-RootSignature.cpp
+++ b/src/D3D12RaytracingProceduralGeometry/DXR-RootSignature.cpp
@@ -21,7 +21,7 @@ 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.
@@ -38,8 +38,15 @@ void DXProceduralProject::CreateRootSignatures()
// u registers --> UAV
// t registers --> SRV
// b registers --> CBV
+
CD3DX12_ROOT_PARAMETER rootParameters[GlobalRootSignature::Slot::Count];
+ rootParameters[GlobalRootSignature::Slot::OutputView].InitAsDescriptorTable(1, &ranges[0]);
+ rootParameters[GlobalRootSignature::Slot::VertexBuffers].InitAsDescriptorTable(1, &ranges[1]);
+ rootParameters[GlobalRootSignature::Slot::AccelerationStructure].InitAsShaderResourceView(0);
+ rootParameters[GlobalRootSignature::Slot::SceneConstant].InitAsConstantBufferView(0);
+ 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);
SerializeAndCreateRaytracingRootSignature(globalRootSignatureDesc, &m_raytracingGlobalRootSignature);
@@ -67,7 +74,14 @@ 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(PrimitiveInstanceConstantBuffer), 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..019cb1e 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++)
@@ -43,6 +45,13 @@ 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];
+ }
+ }
};
@@ -95,7 +104,21 @@ 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");
+
+ for (UINT i = 0; i < RayType::Count; i++) {
+ // Push back the shader record, which does not need any root signatures.
+ missShaderTable.push_back(ShaderRecord(missShaderIDs[i], 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.
diff --git a/src/D3D12RaytracingProceduralGeometry/Debug/D3D12RaytracingProceduralGeometry.vcxprojResolveAssemblyReference.cache b/src/D3D12RaytracingProceduralGeometry/Debug/D3D12RaytracingProceduralGeometry.vcxprojResolveAssemblyReference.cache
new file mode 100644
index 0000000..1a52c1a
Binary files /dev/null and b/src/D3D12RaytracingProceduralGeometry/Debug/D3D12RaytracingProceduralGeometry.vcxprojResolveAssemblyReference.cache differ
diff --git a/src/D3D12RaytracingProceduralGeometry/Main.cpp b/src/D3D12RaytracingProceduralGeometry/Main.cpp
index 7f70bc6..6bbb443 100644
--- a/src/D3D12RaytracingProceduralGeometry/Main.cpp
+++ b/src/D3D12RaytracingProceduralGeometry/Main.cpp
@@ -16,7 +16,7 @@
#include "stdafx.h"
#include "DXProceduralProject.h"
-#define CPU_CODE_COMPLETE 0
+#define CPU_CODE_COMPLETE 1
_Use_decl_annotations_
int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE, LPSTR, int nCmdShow)
diff --git a/src/D3D12RaytracingProceduralGeometry/Raytracing.hlsl b/src/D3D12RaytracingProceduralGeometry/Raytracing.hlsl
index d066933..c6d1861 100644
--- a/src/D3D12RaytracingProceduralGeometry/Raytracing.hlsl
+++ b/src/D3D12RaytracingProceduralGeometry/Raytracing.hlsl
@@ -41,7 +41,7 @@ ConstantBuffer l_aabbCB: register(b2); // other
// Remember to clamp the dot product term!
float CalculateDiffuseCoefficient(in float3 incidentLightRay, in float3 normal)
{
- return 0.0f;
+ return saturate(dot(incidentLightRay, normal));
}
// TODO-3.6: Phong lighting specular component.
@@ -51,7 +51,10 @@ float CalculateDiffuseCoefficient(in float3 incidentLightRay, in float3 normal)
// Remember to normalize the reflected ray, and to clamp the dot product term
float4 CalculateSpecularCoefficient(in float3 incidentLightRay, in float3 normal, in float specularPower)
{
- return float4(0.0f, 0.0f, 0.0f, 0.0f);
+ float3 reflectedRay = normalize(reflect(-incidentLightRay, normal));
+ float3 reverseRayDirection = normalize(-WorldRayDirection());
+ float4 specularComponent = pow(saturate(dot(reflectedRay, reverseRayDirection)), specularPower);
+ return specularComponent;
}
// TODO-3.6: Phong lighting model = ambient + diffuse + specular components.
@@ -75,8 +78,27 @@ float4 CalculatePhongLighting(in float4 albedo, in float3 normal, in bool isInSh
float4 ambientColorMax = g_sceneCB.lightAmbientColor;
float a = 1 - saturate(dot(normal, float3(0, -1, 0)));
ambientColor = albedo * lerp(ambientColorMin, ambientColorMax, a);
+ float shadowCoefficient = 1.0f;
+ if (isInShadow) {
+ shadowCoefficient = InShadowRadiance;
+ }
- return ambientColor;
+ float3 hitPosition = HitWorldPosition();
+ float3 lightPosition = g_sceneCB.lightPosition;
+
+ float3 incidentLightRay = normalize(lightPosition - hitPosition);
+ float lambertianCoefficient = CalculateDiffuseCoefficient(incidentLightRay, normal);
+ float4 diffuseColor = shadowCoefficient * lambertianCoefficient * g_sceneCB.lightDiffuseColor * albedo; //albedo = Intensity!!??
+
+ float4 specularColor = float4(0.0f, 0.0f, 0.0f, 0.0f);
+ if (!isInShadow) {
+ float4 lightSpecularColor = float4(1.0f, 1.0f, 1.0f, 1.0f);
+ float4 specularCoefficient = CalculateSpecularCoefficient(incidentLightRay, normal, specularPower);
+ specularColor = specularCoefficient * lightSpecularColor;
+ }
+
+
+ return ambientColor + specularColor + diffuseColor;
}
//***************************************************************************
@@ -135,7 +157,36 @@ float4 TraceRadianceRay(in Ray ray, in UINT currentRayRecursionDepth)
// Hint 2: remember what the ShadowRay payload looks like. See RaytracingHlslCompat.h
bool TraceShadowRayAndReportIfHit(in Ray ray, in UINT currentRayRecursionDepth)
{
- return false;
+ if (currentRayRecursionDepth >= MAX_RAY_RECURSION_DEPTH)
+ {
+ return false;
+ }
+
+ // Set the ray's extents.
+ RayDesc rayDesc;
+ rayDesc.Origin = ray.origin;
+ rayDesc.Direction = ray.direction;
+ // Set TMin to a zero value to avoid aliasing artifacts along contact areas.
+ // Note: make sure to enable face culling so as to avoid surface face fighting.
+ rayDesc.TMin = 0;
+ rayDesc.TMax = 10000;
+
+ ShadowRayPayload shadowRayPayload = { true };
+
+
+ TraceRay(g_scene,
+ RAY_FLAG_CULL_BACK_FACING_TRIANGLES
+ | RAY_FLAG_ACCEPT_FIRST_HIT_AND_END_SEARCH
+ | RAY_FLAG_FORCE_OPAQUE // ~skip any hit shaders
+ | RAY_FLAG_SKIP_CLOSEST_HIT_SHADER,
+ TraceRayParameters::InstanceMask,
+ TraceRayParameters::HitGroup::Offset[RayType::Shadow],
+ TraceRayParameters::HitGroup::GeometryStride,
+ TraceRayParameters::MissShader::Offset[RayType::Shadow],
+ rayDesc, shadowRayPayload);
+
+ return shadowRayPayload.hit;
+ //return false;
}
//***************************************************************************
@@ -149,9 +200,11 @@ bool TraceShadowRayAndReportIfHit(in Ray ray, in UINT currentRayRecursionDepth)
[shader("raygeneration")]
void MyRaygenShader()
{
-
+ uint2 index = (uint2)DispatchRaysIndex().xy;
+ Ray ray = GenerateCameraRay(index, g_sceneCB.cameraPosition, g_sceneCB.projectionToWorld);
+ float4 color = TraceRadianceRay(ray, 0);
// Write the color to the render target
- g_renderTarget[DispatchRaysIndex().xy] = float4(0.0f, 0.0f, 0.0f, 0.0f);
+ g_renderTarget[DispatchRaysIndex().xy] = color;
}
//***************************************************************************
@@ -209,7 +262,9 @@ void MyClosestHitShader_Triangle(inout RayPayload rayPayload, in BuiltInTriangle
// Hint 1: look at the intrinsic function RayTCurrent() that returns how "far away" your ray is.
// Hint 2: use the built-in function lerp() to linearly interpolate between the computed color and the Background color.
// When t is big, we want the background color to be more pronounced.
-
+ float t = RayTCurrent();
+ color = lerp(color, BackgroundColor, 1 - exp(-0.000001*pow(t, 3.0f)));
+ //color = lerp(color, BackgroundColor, (1 / (1 + exp(-(t - 50)))));
rayPayload.color = color;
}
@@ -227,7 +282,34 @@ void MyClosestHitShader_Triangle(inout RayPayload rayPayload, in BuiltInTriangle
[shader("closesthit")]
void MyClosestHitShader_AABB(inout RayPayload rayPayload, in ProceduralPrimitiveAttributes attr)
{
+ // This is the intersection point on the triangle.
+ float3 hitPosition = HitWorldPosition();
+
+ // Trace a ray from the hit position towards the single light source we have. If on our way to the light we hit something, then we have a shadow!
+ Ray shadowRay = { hitPosition, normalize(g_sceneCB.lightPosition.xyz - hitPosition) };
+ bool shadowRayHit = TraceShadowRayAndReportIfHit(shadowRay, rayPayload.recursionDepth);
+
+ // Reflected component ray.
+ float4 reflectedColor = float4(0, 0, 0, 0);
+ if (l_materialCB.reflectanceCoef > 0.001)
+ {
+ // Trace a reflection ray from the intersection points using Snell's law. The reflect() HLSL built-in function does this for you!
+ // See https://docs.microsoft.com/en-us/windows/win32/direct3dhlsl/dx-graphics-hlsl-intrinsic-functions
+ Ray reflectionRay = { hitPosition, reflect(WorldRayDirection(), attr.normal) };
+ float4 reflectionColor = TraceRadianceRay(reflectionRay, rayPayload.recursionDepth);
+ float3 fresnelR = FresnelReflectanceSchlick(WorldRayDirection(), attr.normal, l_materialCB.albedo.xyz);
+ reflectedColor = l_materialCB.reflectanceCoef * float4(fresnelR, 1) * reflectionColor;
+ }
+
+ // Calculate final color.
+ float4 phongColor = CalculatePhongLighting(l_materialCB.albedo, attr.normal, shadowRayHit, l_materialCB.diffuseCoef, l_materialCB.specularCoef, l_materialCB.specularPower);
+ float4 color = (phongColor + reflectedColor);
+
+ float t = RayTCurrent();
+ color = lerp(color, BackgroundColor, 1 - exp(-0.000001*pow(t, 3.0f)));
+ //color = lerp(color, BackgroundColor, (1 / (1 + exp(-(t - 10)))));
+ rayPayload.color = color;
}
//***************************************************************************
@@ -240,14 +322,14 @@ void MyClosestHitShader_AABB(inout RayPayload rayPayload, in ProceduralPrimitive
[shader("miss")]
void MyMissShader(inout RayPayload rayPayload)
{
-
+ rayPayload.color = BackgroundColor;
}
// TODO-3.3: Complete the Shadow ray miss shader. Is this ray a shadow ray if it hit nothing?
[shader("miss")]
void MyMissShader_ShadowRay(inout ShadowRayPayload rayPayload)
{
-
+ rayPayload.hit = false;
}
//***************************************************************************
@@ -299,6 +381,24 @@ void MyIntersectionShader_AnalyticPrimitive()
[shader("intersection")]
void MyIntersectionShader_VolumetricPrimitive()
{
+ Ray localRay = GetRayInAABBPrimitiveLocalSpace();
+ VolumetricPrimitive::Enum primitiveType = (VolumetricPrimitive::Enum) l_aabbCB.primitiveType;
+ // The point of the intersection shader is to:
+ // (1) find out what is the t at which the ray hits the procedural
+ // (2) pass on some attributes used by the closest hit shader to do some shading (e.g: normal vector)
+ float thit;
+ ProceduralPrimitiveAttributes attr;
+ if (RayVolumetricGeometryIntersectionTest(localRay, primitiveType, thit, attr, g_sceneCB.elapsedTime))
+ {
+ PrimitiveInstancePerFrameBuffer aabbAttribute = g_AABBPrimitiveAttributes[l_aabbCB.instanceIndex];
+
+ // Make sure the normals are stored in BLAS space and not the local space
+ attr.normal = mul(attr.normal, (float3x3) aabbAttribute.localSpaceToBottomLevelAS);
+ attr.normal = normalize(mul((float3x3) ObjectToWorld3x4(), attr.normal));
+
+ // thit is invariant to the space transformation
+ ReportHit(thit, /*hitKind*/ 0, attr);
+ }
}
#endif // RAYTRACING_HLSL
\ No newline at end of file
diff --git a/src/D3D12RaytracingProceduralGeometry/RaytracingHlslCompat.h b/src/D3D12RaytracingProceduralGeometry/RaytracingHlslCompat.h
index 6e10f0d..4b4d664 100644
--- a/src/D3D12RaytracingProceduralGeometry/RaytracingHlslCompat.h
+++ b/src/D3D12RaytracingProceduralGeometry/RaytracingHlslCompat.h
@@ -28,7 +28,7 @@ typedef UINT16 Index;
#define N_FRACTAL_ITERATIONS 5 // = <1,...>
-#define MAX_RAY_RECURSION_DEPTH 3 // ~ primary rays + reflections + shadow rays from reflected geometry.
+#define MAX_RAY_RECURSION_DEPTH 10 // ~ primary rays + reflections + shadow rays from reflected geometry.
/**************** Scene *****************/
static const XMFLOAT4 ChromiumReflectance = XMFLOAT4(0.549f, 0.556f, 0.554f, 1.0f);
diff --git a/src/D3D12RaytracingProceduralGeometry/RaytracingShaderHelper.hlsli b/src/D3D12RaytracingProceduralGeometry/RaytracingShaderHelper.hlsli
index 94bf5cc..f15a5a5 100644
--- a/src/D3D12RaytracingProceduralGeometry/RaytracingShaderHelper.hlsli
+++ b/src/D3D12RaytracingProceduralGeometry/RaytracingShaderHelper.hlsli
@@ -68,7 +68,14 @@ bool is_a_valid_hit(in Ray ray, in float thit, in float3 hitSurfaceNormal)
// (3) Call the hlsl built-in function smoothstep() on this interpolant to smooth it out so it doesn't change abruptly.
float CalculateAnimationInterpolant(in float elapsedTime, in float cycleDuration)
{
- return smoothstep(0, 1, 0);
+ float how_far = fmod(elapsedTime, cycleDuration) / cycleDuration;
+ if (how_far <= 0.5) {
+ how_far = 2.0f * how_far;
+ }
+ else {
+ how_far = 1.0f - (2.0f * (how_far - 0.5f));
+ }
+ return smoothstep(0, 1, how_far);
}
// Load three 2-byte indices from a ByteAddressBuffer.
@@ -129,11 +136,18 @@ float3 HitAttribute(float3 vertexAttribute[3], float2 barycentrics)
// as long as the direction of the ray is correct then the depth does not matter.
inline Ray GenerateCameraRay(uint2 index, in float3 cameraPosition, in float4x4 projectionToWorld)
{
+ uint3 dimensions = DispatchRaysDimensions();
+ float4 normalized_device_coordinates = { 2.0f * ((index.x /(1.0f * dimensions.x)) - 0.5f), 2.0f * (0.5f - (index.y /(1.0f * dimensions.y))), 1.0f, 1.0f };
+ normalized_device_coordinates = normalize(normalized_device_coordinates);
+ //float4 normalized_device_coordinates = { (2.0f * (index.x - dimensions.x / 2.0f)) / dimensions.x, (2.0f * (index.y - dimensions.y / 2.0f)) / dimensions.y, 1.0f, 1.0f };
+
+ float4 world_coordinates = mul(normalized_device_coordinates, 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;
+ ray.direction = normalize(float3(world_coordinates.x, world_coordinates.y, world_coordinates.z));
- return ray;
+ return ray;
}
// TODO-3.6: Fresnel reflectance - schlick approximation.
@@ -141,7 +155,8 @@ inline Ray GenerateCameraRay(uint2 index, in float3 cameraPosition, in float4x4
// f0 is usually the albedo of the material assuming the outside environment is air.
float3 FresnelReflectanceSchlick(in float3 I, in float3 N, in float3 f0)
{
- return f0;
+ float cosi = saturate(dot(-I, N));
+ return (f0 + (1 - f0) * pow(1 - cosi, 5));
}
#endif // RAYTRACINGSHADERHELPER_H
\ No newline at end of file
diff --git a/src/D3D12RaytracingProceduralGeometry/VolumetricPrimitives.hlsli b/src/D3D12RaytracingProceduralGeometry/VolumetricPrimitives.hlsli
index 31a9444..02992b4 100644
--- a/src/D3D12RaytracingProceduralGeometry/VolumetricPrimitives.hlsli
+++ b/src/D3D12RaytracingProceduralGeometry/VolumetricPrimitives.hlsli
@@ -15,14 +15,20 @@ struct Metaball
// TODO-3.4.2: Calculate a magnitude of an influence from a Metaball charge.
// This function should return a metaball potential, which is a float in range [0,1].
-// 1) If the point is at the center, the potential is maximum = 1.
-// 2) If it is at the radius or beyond, the potential is 0.
+// 1) If the point is at the center, the potential is maximum = 1.f
+// 2) it is at the radius or beyond, the potential is 0.ff
// 3) In between (i.e the distance from the center is between 0 and radius), consider using the a
// quintic polynomial field function of the form 6x^5 - 15x^4 + 10x^3, such that x is the ratio
// of the distance from the center to the radius.
float CalculateMetaballPotential(in float3 position, in Metaball blob)
{
- return 0.0f;
+ float dist = distance(position, blob.center);
+ if (dist >= blob.radius) {
+ return 0.0f;
+ }
+ float ratio = dist / blob.radius;
+ float potential = 6 * pow(1 - ratio, 5) - 15 * pow(1 - ratio, 4) + 10 * pow(1 - ratio, 3);
+ return potential;
}
// LOOKAT-1.9.4: Calculates field potential from all active metaballs. This is just the sum of all potentials.
@@ -62,11 +68,11 @@ void InitializeAnimatedMetaballs(out Metaball blobs[N_METABALLS], in float elaps
{
{ float3(-0.3, -0.3, -0.4),float3(0.3,-0.3,-0.0) }, // begin center --> end center
{ float3(0.0, -0.2, 0.5), float3(0.0, 0.4, 0.5) },
- { float3(0.4,0.4, 0.4), float3(-0.4, 0.2, -0.4) }
+ { float3(0.4,0.4, 0.4), float3(-0.4, 0.2, -0.4) },
};
// Metaball field radii of max influence
- float radii[N_METABALLS] = { 0.45, 0.55, 0.45 };
+ float radii[N_METABALLS] = { 0.6, 0.8, 0.7 };
// Calculate animated metaball center positions.
float tAnimate = CalculateAnimationInterpolant(elapsedTime, cycleDuration);
@@ -82,7 +88,18 @@ void InitializeAnimatedMetaballs(out Metaball blobs[N_METABALLS], in float elaps
void TestMetaballsIntersection(in Ray ray, out float tmin, out float tmax, inout Metaball blobs[N_METABALLS])
{
tmin = INFINITY;
- tmax = -INFINITY;
+ tmax = -INFINITY;
+
+ for (UINT i = 0; i < N_METABALLS; i++) {
+ float curr_thit, curr_tmax;
+ if (RaySolidSphereIntersectionTest(ray, curr_thit, curr_tmax, blobs[i].center, blobs[i].radius)) {
+ tmin = min(tmin, curr_thit);
+ tmax = max(tmax, curr_tmax);
+ }
+ }
+ // Since it's a solid sphere, clip intersection points to ray extents.
+ tmin = max(tmin, RayTMin());
+ tmax = min(tmax, RayTCurrent());
}
// TODO-3.4.2: Test if a ray with RayFlags and segment intersects metaball field.
@@ -100,9 +117,30 @@ void TestMetaballsIntersection(in Ray ray, out float tmin, out float tmax, inout
// If this condition fails, keep raymarching!
bool RayMetaballsIntersectionTest(in Ray ray, out float thit, out ProceduralPrimitiveAttributes attr, in float elapsedTime)
{
- thit = 0.0f;
- attr.normal = float3(0.0f, 0.0f, 0.0f);
- return false;
+ Metaball blobs[N_METABALLS];
+ InitializeAnimatedMetaballs(blobs, elapsedTime, 14.0f);
+
+ float tmin, tmax;
+ TestMetaballsIntersection(ray, tmin, tmax, blobs);
+
+ UINT MAXIMUM_STEPS = 128;
+ float t = tmin;
+ float step = (tmax - tmin) / MAXIMUM_STEPS;
+ float threshold = 0.9f;
+ while (t < tmax) {
+ float3 pos = ray.origin + t * ray.direction;
+ float total_potential = CalculateMetaballsPotential(pos, blobs);
+ if (total_potential > threshold) {
+ float3 normal = CalculateMetaballsNormal(pos, blobs);
+ if (is_a_valid_hit(ray, t, normal)) {
+ thit = t;
+ attr.normal = normal;
+ return true;
+ }
+ }
+ t += step;
+ }
+ return false;
}
#endif // VOLUMETRICPRIMITIVESLIBRARY_H
\ No newline at end of file
diff --git a/src/D3D12RaytracingProceduralGeometry/util/DeviceResources.cpp b/src/D3D12RaytracingProceduralGeometry/util/DeviceResources.cpp
index 1ca04bb..21cd49b 100644
--- a/src/D3D12RaytracingProceduralGeometry/util/DeviceResources.cpp
+++ b/src/D3D12RaytracingProceduralGeometry/util/DeviceResources.cpp
@@ -509,6 +509,7 @@ void DeviceResources::Present(D3D12_RESOURCE_STATES beforeState)
// Recommended to always use tearing if supported when using a sync interval of 0.
// Note this will fail if in true 'fullscreen' mode.
hr = m_swapChain->Present(0, DXGI_PRESENT_ALLOW_TEARING);
+ //hr = m_swapChain->Present(1, 0);
}
else
{