diff --git a/Editor/RendererWindow.cpp b/Editor/RendererWindow.cpp
index 252087fae..9f0d5d1c1 100644
--- a/Editor/RendererWindow.cpp
+++ b/Editor/RendererWindow.cpp
@@ -453,6 +453,15 @@ RendererWindow::RendererWindow(wiGUI* gui, RenderPath3D* path) : GUI(gui)
debugForceFieldsCheckBox->SetCheck(wiRenderer::GetToDrawDebugForceFields());
rendererWindow->AddWidget(debugForceFieldsCheckBox);
+ debugRaytraceBVHCheckBox = new wiCheckBox("Raytrace BVH visualizer: ");
+ debugRaytraceBVHCheckBox->SetTooltip("Visualize scene BVH if raytracing is enabled");
+ debugRaytraceBVHCheckBox->SetPos(XMFLOAT2(x, y += step));
+ debugRaytraceBVHCheckBox->OnClick([](wiEventArgs args) {
+ wiRenderer::SetRaytraceDebugBVHVisualizerEnabled(args.bValue);
+ });
+ debugRaytraceBVHCheckBox->SetCheck(wiRenderer::GetRaytraceDebugBVHVisualizerEnabled());
+ rendererWindow->AddWidget(debugRaytraceBVHCheckBox);
+
envProbesCheckBox = new wiCheckBox("Env probe visualizer: ");
envProbesCheckBox->SetTooltip("Toggle visualization of environment probes as reflective spheres");
envProbesCheckBox->SetPos(XMFLOAT2(x, y += step));
diff --git a/Editor/RendererWindow.h b/Editor/RendererWindow.h
index 72ebf3acc..4262bef63 100644
--- a/Editor/RendererWindow.h
+++ b/Editor/RendererWindow.h
@@ -46,6 +46,7 @@ public:
wiCheckBox* boneLinesCheckBox;
wiCheckBox* debugEmittersCheckBox;
wiCheckBox* debugForceFieldsCheckBox;
+ wiCheckBox* debugRaytraceBVHCheckBox;
wiCheckBox* wireFrameCheckBox;
wiCheckBox* advancedLightCullingCheckBox;
wiCheckBox* debugLightCullingCheckBox;
diff --git a/WickedEngine/RenderPath3D_PathTracing.cpp b/WickedEngine/RenderPath3D_PathTracing.cpp
index 4ee522f2e..4fa3051f6 100644
--- a/WickedEngine/RenderPath3D_PathTracing.cpp
+++ b/WickedEngine/RenderPath3D_PathTracing.cpp
@@ -135,28 +135,35 @@ void RenderPath3D_PathTracing::RenderFrameSetUp(GRAPHICSTHREAD threadID)
void RenderPath3D_PathTracing::RenderScene(GRAPHICSTHREAD threadID)
{
- wiProfiler::BeginRange("Traced Scene", wiProfiler::DOMAIN_GPU, threadID);
+ if (wiRenderer::GetRaytraceDebugBVHVisualizerEnabled())
+ {
+ rtAccumulation.SetAndClear(threadID, 0, 0, 0, 1);
+ wiRenderer::DrawTracedSceneBVH(threadID);
+ }
+ else
+ {
+ wiProfiler::BeginRange("Traced Scene", wiProfiler::DOMAIN_GPU, threadID);
- wiRenderer::UpdateCameraCB(wiRenderer::GetCamera(), threadID);
+ wiRenderer::UpdateCameraCB(wiRenderer::GetCamera(), threadID);
- wiRenderer::DrawTracedScene(wiRenderer::GetCamera(), traceResult.get(), threadID);
+ wiRenderer::DrawTracedScene(wiRenderer::GetCamera(), traceResult.get(), threadID);
- wiImageParams fx((float)wiRenderer::GetDevice()->GetScreenWidth(), (float)wiRenderer::GetDevice()->GetScreenHeight());
- fx.enableHDR();
+ wiImageParams fx((float)wiRenderer::GetDevice()->GetScreenWidth(), (float)wiRenderer::GetDevice()->GetScreenHeight());
+ fx.enableHDR();
- // Accumulate with moving averaged blending:
- fx.opacity = 1.0f / (sam + 1.0f);
- fx.blendFlag = BLENDMODE_ALPHA;
+ // Accumulate with moving averaged blending:
+ fx.opacity = 1.0f / (sam + 1.0f);
+ fx.blendFlag = BLENDMODE_ALPHA;
- rtAccumulation.Set(threadID);
- wiImage::Draw(traceResult.get(), fx, threadID);
+ rtAccumulation.Set(threadID);
+ wiImage::Draw(traceResult.get(), fx, threadID);
-
- wiProfiler::EndRange(threadID); // Traced Scene
+ wiProfiler::EndRange(threadID); // Traced Scene
+ }
}
void RenderPath3D_PathTracing::Compose()
diff --git a/WickedEngine/ShaderInterop_TracedRendering.h b/WickedEngine/ShaderInterop_TracedRendering.h
index 6bc381067..f569820f7 100644
--- a/WickedEngine/ShaderInterop_TracedRendering.h
+++ b/WickedEngine/ShaderInterop_TracedRendering.h
@@ -18,11 +18,11 @@ CBUFFER(TracedRenderingCB, CBSLOT_RENDERER_TRACED)
struct TracedRenderingStoredRay
{
- uint pixelID;
float3 origin;
+ uint pixelID;
uint3 direction_energy;
uint primitiveID;
- float2 bary;
+ uint bary;
};
struct TracedRenderingMaterial
diff --git a/WickedEngine/WickedEngine_SHADERS.vcxproj b/WickedEngine/WickedEngine_SHADERS.vcxproj
index 48ff97cdb..3aac676b4 100644
--- a/WickedEngine/WickedEngine_SHADERS.vcxproj
+++ b/WickedEngine/WickedEngine_SHADERS.vcxproj
@@ -677,6 +677,10 @@
Compute
5.0
+
+ Pixel
+ 5.0
+
Compute
5.0
@@ -685,6 +689,10 @@
Compute
5.0
+
+ Vertex
+ 5.0
+
Pixel
diff --git a/WickedEngine/WickedEngine_SHADERS.vcxproj.filters b/WickedEngine/WickedEngine_SHADERS.vcxproj.filters
index 9ab451eae..f16c8bc8c 100644
--- a/WickedEngine/WickedEngine_SHADERS.vcxproj.filters
+++ b/WickedEngine/WickedEngine_SHADERS.vcxproj.filters
@@ -861,6 +861,12 @@
PS
+
+ PS
+
+
+ VS
+
diff --git a/WickedEngine/raySceneIntersectHF.hlsli b/WickedEngine/raySceneIntersectHF.hlsli
index 42a883abc..b2a0b88fe 100644
--- a/WickedEngine/raySceneIntersectHF.hlsli
+++ b/WickedEngine/raySceneIntersectHF.hlsli
@@ -207,6 +207,74 @@ inline bool TraceSceneANY(Ray ray, float maxDistance)
return shadow;
}
+// Returns number of BVH nodes that were hit:
+// returns 0xFFFFFFFF when there was a stack overflow
+// returns (0xFFFFFFFF - 1) when the exit condition was reached
+inline uint TraceBVH(Ray ray)
+{
+ uint hit_counter = 0;
+
+ // Emulated stack for tree traversal:
+ uint stack[RAYTRACE_STACKSIZE];
+ uint stackpos = 0;
+
+ const uint clusterCount = clusterCounterBuffer.Load(0);
+ const uint leafNodeOffset = clusterCount - 1;
+
+ // push root node
+ stack[stackpos] = 0;
+ stackpos++;
+
+ uint exit_condition = 0;
+ do {
+#ifdef RAYTRACE_EXIT
+ if (exit_condition > RAYTRACE_EXIT)
+ return (0xFFFFFFFF - 1);
+ exit_condition++;
+#endif // RAYTRACE_EXIT
+
+ // pop untraversed node
+ stackpos--;
+ const uint nodeIndex = stack[stackpos];
+
+ BVHNode node = bvhNodeBuffer[nodeIndex];
+ BVHAABB box = bvhAABBBuffer[nodeIndex];
+
+ if (IntersectBox(ray, box))
+ {
+ hit_counter++;
+
+ if (nodeIndex >= clusterCount - 1)
+ {
+ // Leaf node
+ }
+ else
+ {
+ // Internal node
+ if (stackpos < RAYTRACE_STACKSIZE - 1)
+ {
+ // push left child
+ stack[stackpos] = node.LeftChildIndex;
+ stackpos++;
+ // push right child
+ stack[stackpos] = node.RightChildIndex;
+ stackpos++;
+ }
+ else
+ {
+ // stack overflow, terminate
+ return 0xFFFFFFFF;
+ }
+ }
+
+ }
+
+ } while (stackpos > 0);
+
+
+ return hit_counter;
+}
+
// This will modify ray to continue the trace
// Also fill the final params of rayHit, such as normal, uv, materialIndex
// seed should be > 0
diff --git a/WickedEngine/raytrace_debugbvhPS.hlsl b/WickedEngine/raytrace_debugbvhPS.hlsl
new file mode 100644
index 000000000..16bae0d6c
--- /dev/null
+++ b/WickedEngine/raytrace_debugbvhPS.hlsl
@@ -0,0 +1,39 @@
+#define RAYTRACE_EXIT 256
+#include "globals.hlsli"
+#include "ShaderInterop_TracedRendering.h"
+#include "ShaderInterop_BVH.h"
+#include "tracedRenderingHF.hlsli"
+#include "raySceneIntersectHF.hlsli"
+
+float4 main(float4 pos : SV_POSITION, float2 clipspace : TEXCOORD) : SV_Target
+{
+ Ray ray = CreateCameraRay(clipspace);
+
+ uint hitCount = TraceBVH(ray);
+
+ if (hitCount == 0xFFFFFFFF)
+ {
+ return float4(1, 0, 1, 1); // error: stack overflow (purple)
+ }
+ if (hitCount == (0xFFFFFFFF - 1))
+ {
+ return float4(1, 1, 1, 1); // error: exit condition reached (white)
+ }
+
+ const float3 mapTex[] = {
+ float3(0,0,0),
+ float3(0,0,1),
+ float3(0,1,1),
+ float3(0,1,0),
+ float3(1,1,0),
+ float3(1,0,0),
+ };
+ const uint mapTexLen = 5;
+ const uint maxHeat = 100;
+ float l = saturate((float)hitCount / maxHeat) * mapTexLen;
+ float3 a = mapTex[floor(l)];
+ float3 b = mapTex[ceil(l)];
+ float4 heatmap = float4(lerp(a, b, l - floor(l)), 0.8f);
+
+ return heatmap;
+}
\ No newline at end of file
diff --git a/WickedEngine/raytrace_screenVS.hlsl b/WickedEngine/raytrace_screenVS.hlsl
new file mode 100644
index 000000000..88e430d84
--- /dev/null
+++ b/WickedEngine/raytrace_screenVS.hlsl
@@ -0,0 +1,18 @@
+#include "fullScreenTriangleHF.hlsli"
+
+struct VSOut
+{
+ float4 pos : SV_POSITION;
+ float2 clipspace : TEXCOORD;
+};
+
+VSOut main(uint vI : SV_VERTEXID)
+{
+ VSOut Out;
+
+ FullScreenTriangle(vI, Out.pos);
+
+ Out.clipspace = Out.pos.xy;
+
+ return Out;
+}
diff --git a/WickedEngine/tracedRenderingHF.hlsli b/WickedEngine/tracedRenderingHF.hlsli
index f3975fab4..ee73e31ac 100644
--- a/WickedEngine/tracedRenderingHF.hlsli
+++ b/WickedEngine/tracedRenderingHF.hlsli
@@ -48,11 +48,11 @@ inline TracedRenderingStoredRay CreateStoredRay(in Ray ray, in uint pixelID)
{
TracedRenderingStoredRay storedray;
- storedray.pixelID = pixelID;
storedray.origin = ray.origin;
+ storedray.pixelID = pixelID;
storedray.direction_energy = f32tof16(ray.direction) | (f32tof16(ray.energy) << 16);
storedray.primitiveID = ray.primitiveID;
- storedray.bary = ray.bary;
+ storedray.bary = f32tof16(ray.bary.x) | (f32tof16(ray.bary.y) << 16);
return storedray;
}
@@ -64,7 +64,8 @@ inline void LoadRay(in TracedRenderingStoredRay storedray, out Ray ray, out uint
ray.direction = asfloat(f16tof32(storedray.direction_energy));
ray.energy = asfloat(f16tof32(storedray.direction_energy >> 16));
ray.primitiveID = storedray.primitiveID;
- ray.bary = storedray.bary;
+ ray.bary.x = f16tof32(storedray.bary);
+ ray.bary.y = f16tof32(storedray.bary >> 16);
ray.Update();
}
@@ -80,9 +81,9 @@ inline Ray CreateRay(float3 origin, float3 direction)
return ray;
}
-inline Ray CreateCameraRay(float2 uv)
+inline Ray CreateCameraRay(float2 clipspace)
{
- float4 unprojected = mul(float4(uv, 0.0f, 1.0f), g_xFrame_MainCamera_InvVP);
+ float4 unprojected = mul(float4(clipspace, 0.0f, 1.0f), g_xFrame_MainCamera_InvVP);
unprojected.xyz /= unprojected.w;
const float3 origin = g_xFrame_MainCamera_CamPos;
diff --git a/WickedEngine/wiEnums.h b/WickedEngine/wiEnums.h
index 2cdf93e49..723a4a24c 100644
--- a/WickedEngine/wiEnums.h
+++ b/WickedEngine/wiEnums.h
@@ -142,6 +142,7 @@ enum VSTYPES
VSTYPE_FORCEFIELDVISUALIZER_POINT,
VSTYPE_FORCEFIELDVISUALIZER_PLANE,
VSTYPE_RENDERLIGHTMAP,
+ VSTYPE_RAYTRACE_SCREEN,
VSTYPE_LAST
};
// pixel shaders
@@ -232,6 +233,7 @@ enum PSTYPES
PSTYPE_FORCEFIELDVISUALIZER,
PSTYPE_RENDERLIGHTMAP_INDIRECT,
PSTYPE_RENDERLIGHTMAP_DIRECT,
+ PSTYPE_RAYTRACE_DEBUGBVH,
PSTYPE_LAST
};
// geometry shaders
diff --git a/WickedEngine/wiRenderer.cpp b/WickedEngine/wiRenderer.cpp
index 7b0d321c0..b53cd4beb 100644
--- a/WickedEngine/wiRenderer.cpp
+++ b/WickedEngine/wiRenderer.cpp
@@ -115,6 +115,7 @@ bool occlusionCulling = false;
bool temporalAA = false;
bool temporalAADEBUG = false;
uint32_t lightmapBakeBounceCount = 4;
+bool raytraceDebugVisualizer = false;
struct VoxelizedSceneData
{
@@ -1136,6 +1137,7 @@ enum DEBUGRENDERING
DEBUGRENDERING_VOXEL,
DEBUGRENDERING_FORCEFIELD_POINT,
DEBUGRENDERING_FORCEFIELD_PLANE,
+ DEBUGRENDERING_RAYTRACE_BVH,
DEBUGRENDERING_COUNT
};
GraphicsPSO* PSO_debug[DEBUGRENDERING_COUNT] = {};
@@ -1967,6 +1969,7 @@ void LoadShaders()
vertexShaders[VSTYPE_VOXEL] = static_cast(wiResourceManager::GetShaderManager().add(SHADERPATH + "voxelVS.cso", wiResourceManager::VERTEXSHADER));
vertexShaders[VSTYPE_FORCEFIELDVISUALIZER_POINT] = static_cast(wiResourceManager::GetShaderManager().add(SHADERPATH + "forceFieldPointVisualizerVS.cso", wiResourceManager::VERTEXSHADER));
vertexShaders[VSTYPE_FORCEFIELDVISUALIZER_PLANE] = static_cast(wiResourceManager::GetShaderManager().add(SHADERPATH + "forceFieldPlaneVisualizerVS.cso", wiResourceManager::VERTEXSHADER));
+ vertexShaders[VSTYPE_RAYTRACE_SCREEN] = static_cast(wiResourceManager::GetShaderManager().add(SHADERPATH + "raytrace_screenVS.cso", wiResourceManager::VERTEXSHADER));
pixelShaders[PSTYPE_OBJECT_DEFERRED] = static_cast(wiResourceManager::GetShaderManager().add(SHADERPATH + "objectPS_deferred.cso", wiResourceManager::PIXELSHADER));
@@ -2052,6 +2055,7 @@ void LoadShaders()
pixelShaders[PSTYPE_FORCEFIELDVISUALIZER] = static_cast(wiResourceManager::GetShaderManager().add(SHADERPATH + "forceFieldVisualizerPS.cso", wiResourceManager::PIXELSHADER));
pixelShaders[PSTYPE_RENDERLIGHTMAP_INDIRECT] = static_cast(wiResourceManager::GetShaderManager().add(SHADERPATH + "renderlightmapPS_indirect.cso", wiResourceManager::PIXELSHADER));
pixelShaders[PSTYPE_RENDERLIGHTMAP_DIRECT] = static_cast(wiResourceManager::GetShaderManager().add(SHADERPATH + "renderlightmapPS_direct.cso", wiResourceManager::PIXELSHADER));
+ pixelShaders[PSTYPE_RAYTRACE_DEBUGBVH] = static_cast(wiResourceManager::GetShaderManager().add(SHADERPATH + "raytrace_debugbvhPS.cso", wiResourceManager::PIXELSHADER));
geometryShaders[GSTYPE_ENVMAP] = static_cast(wiResourceManager::GetShaderManager().add(SHADERPATH + "envMapGS.cso", wiResourceManager::GEOMETRYSHADER));
geometryShaders[GSTYPE_ENVMAP_SKY] = static_cast(wiResourceManager::GetShaderManager().add(SHADERPATH + "envMap_skyGS.cso", wiResourceManager::GEOMETRYSHADER));
@@ -2743,6 +2747,10 @@ void LoadShaders()
{
GraphicsPSODesc desc;
+ desc.numRTs = 1;
+ desc.RTFormats[0] = RTFormat_hdr;
+ desc.DSFormat = DSFormat_full;
+
switch (debug)
{
case DEBUGRENDERING_ENVPROBE:
@@ -2814,12 +2822,17 @@ void LoadShaders()
desc.bs = blendStates[BSTYPE_TRANSPARENT];
desc.pt = TRIANGLESTRIP;
break;
+ case DEBUGRENDERING_RAYTRACE_BVH:
+ desc.vs = vertexShaders[VSTYPE_RAYTRACE_SCREEN];
+ desc.ps = pixelShaders[PSTYPE_RAYTRACE_DEBUGBVH];
+ desc.dss = depthStencils[DSSTYPE_XRAY];
+ desc.rs = rasterizers[RSTYPE_DOUBLESIDED];
+ desc.bs = blendStates[BSTYPE_TRANSPARENT];
+ desc.pt = TRIANGLELIST;
+ desc.DSFormat = FORMAT_UNKNOWN;
+ break;
}
- desc.numRTs = 1;
- desc.RTFormats[0] = RTFormat_hdr;
- desc.DSFormat = DSFormat_full;
-
RECREATE(PSO_debug[debug]);
HRESULT hr = device->CreateGraphicsPSO(&desc, PSO_debug[debug]);
assert(SUCCEEDED(hr));
@@ -5785,6 +5798,11 @@ void DrawDebugWorld(const CameraComponent& camera, GRAPHICSTHREAD threadID)
device->EventEnd(threadID);
}
+ if (GetRaytraceDebugBVHVisualizerEnabled())
+ {
+ DrawTracedSceneBVH(threadID);
+ }
+
device->EventEnd(threadID);
}
@@ -7501,6 +7519,16 @@ void DrawTracedScene(const CameraComponent& camera, Texture2D* result, GRAPHICST
device->EventEnd(threadID); // DrawTracedScene
}
+void DrawTracedSceneBVH(GRAPHICSTHREAD threadID)
+{
+ GraphicsDevice* device = GetDevice();
+
+ device->EventBegin("DebugRaytraceBVH", threadID);
+ device->BindGraphicsPSO(PSO_debug[DEBUGRENDERING_RAYTRACE_BVH], threadID);
+ sceneBVH.Bind(PS, threadID);
+ device->Draw(3, 0, threadID);
+ device->EventEnd(threadID);
+}
void GenerateClouds(Texture2D* dst, UINT refinementCount, float randomness, GRAPHICSTHREAD threadID)
{
@@ -8618,5 +8646,13 @@ uint32_t GetLightmapBakeBounceCount()
{
return lightmapBakeBounceCount;
}
+void SetRaytraceDebugBVHVisualizerEnabled(bool value)
+{
+ raytraceDebugVisualizer = value;
+}
+bool GetRaytraceDebugBVHVisualizerEnabled()
+{
+ return raytraceDebugVisualizer;
+}
}
diff --git a/WickedEngine/wiRenderer.h b/WickedEngine/wiRenderer.h
index 6fc542fc2..c14e931d2 100644
--- a/WickedEngine/wiRenderer.h
+++ b/WickedEngine/wiRenderer.h
@@ -136,6 +136,8 @@ namespace wiRenderer
void BuildSceneBVH(GRAPHICSTHREAD threadID);
// Render the scene with ray tracing only
void DrawTracedScene(const wiSceneSystem::CameraComponent& camera, wiGraphicsTypes::Texture2D* result, GRAPHICSTHREAD threadID);
+ // Render the scene BVH with ray tracing
+ void DrawTracedSceneBVH(GRAPHICSTHREAD threadID);
// Render occluders against a depth buffer
void OcclusionCulling_Render(GRAPHICSTHREAD threadID);
@@ -267,6 +269,8 @@ namespace wiRenderer
void InvalidateBVH(); // invalidates scene bvh so if something wants to use it, it will recompute and validate it
void SetLightmapBakeBounceCount(uint32_t bounces);
uint32_t GetLightmapBakeBounceCount();
+ void SetRaytraceDebugBVHVisualizerEnabled(bool value);
+ bool GetRaytraceDebugBVHVisualizerEnabled();
wiGraphicsTypes::Texture2D* GetGlobalLightmap();
diff --git a/WickedEngine/wiVersion.cpp b/WickedEngine/wiVersion.cpp
index 0fa1fabc8..286770480 100644
--- a/WickedEngine/wiVersion.cpp
+++ b/WickedEngine/wiVersion.cpp
@@ -9,7 +9,7 @@ namespace wiVersion
// minor features, major updates
const int minor = 24;
// minor bug fixes, alterations, refactors, updates
- const int revision = 41;
+ const int revision = 42;
long GetVersion()