diff --git a/Editor/RendererWindow.cpp b/Editor/RendererWindow.cpp index f89ba7cc0..b2b78cde8 100644 --- a/Editor/RendererWindow.cpp +++ b/Editor/RendererWindow.cpp @@ -1,6 +1,7 @@ #include "stdafx.h" #include "RendererWindow.h" #include "Editor.h" +#include "shaders/ShaderInterop_DDGI.h" void RendererWindow::Create(EditorComponent* editor) { @@ -10,7 +11,7 @@ void RendererWindow::Create(EditorComponent* editor) wi::renderer::SetToDrawGridHelper(true); wi::renderer::SetToDrawDebugCameras(true); - SetSize(XMFLOAT2(580, 550)); + SetSize(XMFLOAT2(580, 600)); float x = 220, y = 5, step = 20, itemheight = 18; @@ -58,6 +59,16 @@ void RendererWindow::Create(EditorComponent* editor) }); AddWidget(&resolutionScaleSlider); + GIBoostSlider.Create(1, 10, 1.0f, 1000.0f, "GI Boost: "); + GIBoostSlider.SetTooltip("Adjust the strength of GI.\nNote that values other than 1.0 will cause mismatch with path tracing reference!"); + GIBoostSlider.SetSize(XMFLOAT2(100, itemheight)); + GIBoostSlider.SetPos(XMFLOAT2(x, y += step)); + GIBoostSlider.SetValue(wi::renderer::GetGIBoost()); + GIBoostSlider.OnSlide([editor](wi::gui::EventArgs args) { + wi::renderer::SetGIBoost(args.fValue); + }); + AddWidget(&GIBoostSlider); + surfelGICheckBox.Create("Surfel GI: "); surfelGICheckBox.SetTooltip("Surfel GI is a raytraced diffuse GI using raytracing and surface cache."); surfelGICheckBox.SetPos(XMFLOAT2(x, y += step)); @@ -84,15 +95,35 @@ void RendererWindow::Create(EditorComponent* editor) }); AddWidget(&surfelGIDebugComboBox); - surfelGIBoostSlider.Create(1, 10, 1.0f, 1000.0f, "Surfel GI Boost: "); - surfelGIBoostSlider.SetTooltip("Adjust the strength of surfel GI.\nNote that values other than 1.0 will cause mismatch with path tracing reference"); - surfelGIBoostSlider.SetSize(XMFLOAT2(100, itemheight)); - surfelGIBoostSlider.SetPos(XMFLOAT2(x, y += step)); - surfelGIBoostSlider.SetValue(wi::renderer::GetSurfelGIBoost()); - surfelGIBoostSlider.OnSlide([editor](wi::gui::EventArgs args) { - wi::renderer::SetSurfelGIBoost(args.fValue); + ddgiCheckBox.Create("DDGI: "); + ddgiCheckBox.SetTooltip("Toggle Dynamic Diffuse Global Illumination (DDGI)."); + ddgiCheckBox.SetPos(XMFLOAT2(x, y += step)); + ddgiCheckBox.SetSize(XMFLOAT2(itemheight, itemheight)); + ddgiCheckBox.OnClick([](wi::gui::EventArgs args) { + wi::renderer::SetDDGIEnabled(args.bValue); }); - AddWidget(&surfelGIBoostSlider); + ddgiCheckBox.SetCheck(wi::renderer::GetDDGIEnabled()); + AddWidget(&ddgiCheckBox); + + ddgiDebugCheckBox.Create("DEBUG: "); + ddgiDebugCheckBox.SetTooltip("Toggle DDGI probe visualization."); + ddgiDebugCheckBox.SetPos(XMFLOAT2(x + 122, y)); + ddgiDebugCheckBox.SetSize(XMFLOAT2(itemheight, itemheight)); + ddgiDebugCheckBox.OnClick([](wi::gui::EventArgs args) { + wi::renderer::SetDDGIDebugEnabled(args.bValue); + }); + ddgiDebugCheckBox.SetCheck(wi::renderer::GetDDGIDebugEnabled()); + AddWidget(&ddgiDebugCheckBox); + + ddgiRayCountSlider.Create(32, DDGI_MAX_RAYCOUNT, 64, DDGI_MAX_RAYCOUNT - 32, "DDGI RayCount: "); + ddgiRayCountSlider.SetTooltip("Adjust the ray count per DDGI probe."); + ddgiRayCountSlider.SetSize(XMFLOAT2(100, itemheight)); + ddgiRayCountSlider.SetPos(XMFLOAT2(x, y += step)); + ddgiRayCountSlider.SetValue((float)wi::renderer::GetDDGIRayCount()); + ddgiRayCountSlider.OnSlide([&](wi::gui::EventArgs args) { + wi::renderer::SetDDGIRayCount((uint32_t)args.iValue); + }); + AddWidget(&ddgiRayCountSlider); voxelRadianceCheckBox.Create("Voxel GI: "); voxelRadianceCheckBox.SetTooltip("Toggle voxel Global Illumination computation."); diff --git a/Editor/RendererWindow.h b/Editor/RendererWindow.h index 8bbae82bb..460c2b2c5 100644 --- a/Editor/RendererWindow.h +++ b/Editor/RendererWindow.h @@ -27,9 +27,12 @@ public: wi::gui::ComboBox swapchainComboBox; wi::gui::CheckBox occlusionCullingCheckBox; wi::gui::Slider resolutionScaleSlider; + wi::gui::Slider GIBoostSlider; wi::gui::CheckBox surfelGICheckBox; wi::gui::ComboBox surfelGIDebugComboBox; - wi::gui::Slider surfelGIBoostSlider; + wi::gui::CheckBox ddgiCheckBox; + wi::gui::CheckBox ddgiDebugCheckBox; + wi::gui::Slider ddgiRayCountSlider; wi::gui::CheckBox voxelRadianceCheckBox; wi::gui::CheckBox voxelRadianceDebugCheckBox; wi::gui::CheckBox voxelRadianceSecondaryBounceCheckBox; diff --git a/WickedEngine/offlineshadercompiler.cpp b/WickedEngine/offlineshadercompiler.cpp index d27b5b4bb..7384eda21 100644 --- a/WickedEngine/offlineshadercompiler.cpp +++ b/WickedEngine/offlineshadercompiler.cpp @@ -234,6 +234,10 @@ int main(int argc, char* argv[]) "surfel_binningCS.hlsl", "surfel_raytraceCS_rtapi.hlsl", "surfel_raytraceCS.hlsl", + "ddgi_raytraceCS.hlsl", + "ddgi_raytraceCS_rtapi.hlsl", + "ddgi_updateCS.hlsl", + "ddgi_updateCS_depth.hlsl", }; shaders[static_cast(ShaderStage::PS)] = { @@ -309,6 +313,7 @@ int main(int argc, char* argv[]) "captureImpostorPS_normal.hlsl" , "captureImpostorPS_surface.hlsl" , "captureImpostorPS_albedo.hlsl" , + "ddgi_debugPS.hlsl" , }; shaders[static_cast(ShaderStage::VS)] = { @@ -357,6 +362,7 @@ int main(int argc, char* argv[]) "cubeShadowVS_transparent.hlsl" , "cubeShadowVS_transparent_emulation.hlsl" , "occludeeVS.hlsl", + "ddgi_debugVS.hlsl", }; shaders[static_cast(ShaderStage::GS)] = { @@ -400,6 +406,7 @@ int main(int argc, char* argv[]) minshadermodels["rtshadowCS.hlsl"] = ShaderModel::SM_6_5; minshadermodels["rtaoCS.hlsl"] = ShaderModel::SM_6_5; minshadermodels["surfel_raytraceCS_rtapi.hlsl"] = ShaderModel::SM_6_5; + minshadermodels["ddgi_raytraceCS_rtapi.hlsl"] = ShaderModel::SM_6_5; minshadermodels["rtreflectionCS.hlsl"] = ShaderModel::SM_6_5; wi::jobsystem::context ctx; diff --git a/WickedEngine/shaders/ShaderInterop_DDGI.h b/WickedEngine/shaders/ShaderInterop_DDGI.h new file mode 100644 index 000000000..0f634da29 --- /dev/null +++ b/WickedEngine/shaders/ShaderInterop_DDGI.h @@ -0,0 +1,365 @@ +#ifndef WI_SHADERINTEROP_DDGI_H +#define WI_SHADERINTEROP_DDGI_H +#include "ShaderInterop.h" +#include "ShaderInterop_Renderer.h" + +static const uint3 DDGI_GRID_DIMENSIONS = uint3(32, 8, 32); // The scene extents will be subdivided into a grid of this resolution, each grid cell will have one probe +static const uint DDGI_PROBE_COUNT = DDGI_GRID_DIMENSIONS.x * DDGI_GRID_DIMENSIONS.y * DDGI_GRID_DIMENSIONS.z; +static const uint DDGI_MAX_RAYCOUNT = 512; // affects global ray buffer size +static const uint DDGI_COLOR_RESOLUTION = 8; // this should not be modified, border update code is fixed +static const uint DDGI_COLOR_TEXELS = 1 + DDGI_COLOR_RESOLUTION + 1; // with border +static const uint DDGI_DEPTH_RESOLUTION = 16; // this should not be modified, border update code is fixed +static const uint DDGI_DEPTH_TEXELS = 1 + DDGI_DEPTH_RESOLUTION + 1; // with border +static const uint DDGI_COLOR_TEXTURE_WIDTH = DDGI_COLOR_TEXELS * DDGI_GRID_DIMENSIONS.x * DDGI_GRID_DIMENSIONS.y; +static const uint DDGI_COLOR_TEXTURE_HEIGHT = DDGI_COLOR_TEXELS * DDGI_GRID_DIMENSIONS.z; +static const uint DDGI_DEPTH_TEXTURE_WIDTH = DDGI_DEPTH_TEXELS * DDGI_GRID_DIMENSIONS.x * DDGI_GRID_DIMENSIONS.y; +static const uint DDGI_DEPTH_TEXTURE_HEIGHT = DDGI_DEPTH_TEXELS * DDGI_GRID_DIMENSIONS.z; + +#define DDGI_LINEAR_BLENDING + +struct DDGIPushConstants +{ + uint instanceInclusionMask; + uint frameIndex; + uint rayCount; +}; + +struct DDGIRayData +{ + float3 direction; + float depth; + float4 radiance; +}; +struct DDGIRayDataPacked +{ + uint4 data; + +#ifndef __cplusplus + inline void store(DDGIRayData rayData) + { + data.xy = pack_half4(float4(rayData.direction, rayData.depth)); + data.zw = pack_half4(rayData.radiance); + } + inline DDGIRayData load() + { + DDGIRayData rayData; + float4 unpk = unpack_half4(data.xy); + rayData.direction = unpk.xyz; + rayData.depth = unpk.w; + rayData.radiance = unpack_half4(data.zw); + return rayData; + } +#endif // __cplusplus +}; + +#ifndef __cplusplus + +inline float3 ddgi_cellsize() +{ + return GetScene().ddgi.cell_size; +} +inline float ddgi_max_distance() +{ + return GetScene().ddgi.max_distance; +} +inline uint3 ddgi_base_probe_coord(float3 P) +{ + float3 normalized_pos = (P - GetScene().ddgi.grid_min) * GetScene().ddgi.grid_extents_rcp; + return floor(normalized_pos * (DDGI_GRID_DIMENSIONS - 1)); +} +inline uint3 ddgi_probe_coord(uint probeIndex) +{ + return unflatten3D(probeIndex, DDGI_GRID_DIMENSIONS); +} +inline uint ddgi_probe_index(uint3 probeCoord) +{ + return flatten3D(probeCoord, DDGI_GRID_DIMENSIONS); +} +inline float3 ddgi_probe_position(uint3 probeCoord) +{ + return GetScene().ddgi.grid_min + probeCoord * ddgi_cellsize(); +} +inline uint2 ddgi_probe_color_pixel(uint3 probeCoord) +{ + return probeCoord.xz * DDGI_COLOR_TEXELS + uint2(probeCoord.y * DDGI_GRID_DIMENSIONS.x * DDGI_COLOR_TEXELS, 0) + 1; +} +inline float2 ddgi_probe_color_uv(uint3 probeCoord, float3 direction) +{ + float2 pixel = ddgi_probe_color_pixel(probeCoord); + pixel += (encode_oct(normalize(direction)) * 0.5 + 0.5) * DDGI_COLOR_RESOLUTION; + return pixel / float2(DDGI_COLOR_TEXTURE_WIDTH, DDGI_COLOR_TEXTURE_HEIGHT); +} +inline uint2 ddgi_probe_depth_pixel(uint3 probeCoord) +{ + return probeCoord.xz * DDGI_DEPTH_TEXELS + uint2(probeCoord.y * DDGI_GRID_DIMENSIONS.x * DDGI_DEPTH_TEXELS, 0) + 1; +} +inline float2 ddgi_probe_depth_uv(uint3 probeCoord, float3 direction) +{ + float2 pixel = ddgi_probe_depth_pixel(probeCoord); + pixel += (encode_oct(normalize(direction)) * 0.5 + 0.5) * DDGI_DEPTH_RESOLUTION; + return pixel / float2(DDGI_DEPTH_TEXTURE_WIDTH, DDGI_DEPTH_TEXTURE_HEIGHT); +} + + +// Based on: https://github.com/diharaw/hybrid-rendering/blob/master/src/shaders/gi/gi_common.glsl +float3 ddgi_sample_irradiance(float3 P, float3 N) +{ + uint3 base_grid_coord = ddgi_base_probe_coord(P); + float3 base_probe_pos = ddgi_probe_position(base_grid_coord); + + float3 sum_irradiance = 0; + float sum_weight = 0; + + // alpha is how far from the floor(currentVertex) position. on [0, 1] for each axis. + float3 alpha = clamp((P - base_probe_pos) / ddgi_cellsize(), 0, 1); + + // Iterate over adjacent probe cage + for (uint i = 0; i < 8; ++i) + { + // Compute the offset grid coord and clamp to the probe grid boundary + // Offset = 0 or 1 along each axis + uint3 offset = uint3(i, i >> 1, i >> 2) & 1; + uint3 probe_grid_coord = clamp(base_grid_coord + offset, 0, DDGI_GRID_DIMENSIONS - 1); + //int p = ddgi_probe_index(probe_grid_coord); + + // Make cosine falloff in tangent plane with respect to the angle from the surface to the probe so that we never + // test a probe that is *behind* the surface. + // It doesn't have to be cosine, but that is efficient to compute and we must clip to the tangent plane. + float3 probe_pos = ddgi_probe_position(probe_grid_coord); + + // Bias the position at which visibility is computed; this + // avoids performing a shadow test *at* a surface, which is a + // dangerous location because that is exactly the line between + // shadowed and unshadowed. If the normal bias is too small, + // there will be light and dark leaks. If it is too large, + // then samples can pass through thin occluders to the other + // side (this can only happen if there are MULTIPLE occluders + // near each other, a wall surface won't pass through itself.) + float3 probe_to_point = P - probe_pos + N * 0.001; + float3 dir = normalize(-probe_to_point); + + // Compute the trilinear weights based on the grid cell vertex to smoothly + // transition between probes. Avoid ever going entirely to zero because that + // will cause problems at the border probes. This isn't really a lerp. + // We're using 1-a when offset = 0 and a when offset = 1. + float3 trilinear = lerp(1.0 - alpha, alpha, offset); + float weight = 1.0; + + // Clamp all of the multiplies. We can't let the weight go to zero because then it would be + // possible for *all* weights to be equally low and get normalized + // up to 1/n. We want to distinguish between weights that are + // low because of different factors. + +#if 0 + // Smooth backface test + { + // Computed without the biasing applied to the "dir" variable. + // This test can cause reflection-map looking errors in the image + // (stuff looks shiny) if the transition is poor. + float3 true_direction_to_probe = normalize(probe_pos - P); + + // The naive soft backface weight would ignore a probe when + // it is behind the surface. That's good for walls. But for small details inside of a + // room, the normals on the details might rule out all of the probes that have mutual + // visibility to the point. So, we instead use a "wrap shading" test below inspired by + // NPR work. + // weight *= max(0.0001, dot(trueDirectionToProbe, wsN)); + + // The small offset at the end reduces the "going to zero" impact + // where this is really close to exactly opposite + weight *= sqr(max(0.0001, (dot(true_direction_to_probe, N) + 1.0) * 0.5)) + 0.2; + } +#else + weight *= saturate(dot(dir, N)); +#endif + + // Moment visibility test +#if 1 + [branch] + if(GetScene().ddgi.depth_texture >= 0) + { + //float2 tex_coord = texture_coord_from_direction(-dir, p, ddgi.depth_texture_width, ddgi.depth_texture_height, ddgi.depth_probe_side_length); + float2 tex_coord = ddgi_probe_depth_uv(probe_grid_coord, -dir); + + float dist_to_probe = length(probe_to_point); + + //float2 temp = textureLod(depth_texture, tex_coord, 0.0f).rg; + float2 temp = bindless_textures[GetScene().ddgi.depth_texture].SampleLevel(sampler_linear_clamp, tex_coord, 0).xy; + float mean = temp.x; + float variance = abs(sqr(temp.x) - temp.y); + + // http://www.punkuser.net/vsm/vsm_paper.pdf; equation 5 + // Need the max in the denominator because biasing can cause a negative displacement + float chebyshev_weight = variance / (variance + sqr(max(dist_to_probe - mean, 0.0))); + + // Increase contrast in the weight + chebyshev_weight = max(pow(chebyshev_weight, 3), 0.0); + + weight *= (dist_to_probe <= mean) ? 1.0 : chebyshev_weight; + } +#endif + + // Avoid zero weight + weight = max(0.000001, weight); + + float3 irradiance_dir = N; + + //float2 tex_coord = texture_coord_from_direction(normalize(irradiance_dir), p, ddgi.irradiance_texture_width, ddgi.irradiance_texture_height, ddgi.irradiance_probe_side_length); + float2 tex_coord = ddgi_probe_color_uv(probe_grid_coord, irradiance_dir); + + //float3 probe_irradiance = textureLod(irradiance_texture, tex_coord, 0.0f).rgb; + float3 probe_irradiance = bindless_textures[GetScene().ddgi.color_texture].SampleLevel(sampler_linear_clamp, tex_coord, 0).rgb; + + // A tiny bit of light is really visible due to log perception, so + // crush tiny weights but keep the curve continuous. This must be done + // before the trilinear weights, because those should be preserved. + const float crush_threshold = 0.2f; + if (weight < crush_threshold) + weight *= weight * weight * (1.0f / sqr(crush_threshold)); + + // Trilinear weights + weight *= trilinear.x * trilinear.y * trilinear.z; + + // Weight in a more-perceptual brightness space instead of radiance space. + // This softens the transitions between probes with respect to translation. + // It makes little difference most of the time, but when there are radical transitions + // between probes this helps soften the ramp. +#ifndef DDGI_LINEAR_BLENDING + probe_irradiance = sqrt(probe_irradiance); +#endif + + sum_irradiance += weight * probe_irradiance; + sum_weight += weight; + } + + if (sum_weight > 0) + { + float3 net_irradiance = sum_irradiance / sum_weight; + + // Go back to linear irradiance +#ifndef DDGI_LINEAR_BLENDING + net_irradiance = sqr(net_irradiance); +#endif + + //net_irradiance *= 0.85; // energy preservation + + return net_irradiance; + //return 0.5f * PI * net_irradiance; + } + + return 0; +} + +// Border offsets from: https://github.com/diharaw/hybrid-rendering/blob/master/src/shaders/gi/gi_border_update.glsl +static const uint4 DDGI_COLOR_BORDER_OFFSETS[36] = { + uint4(8, 1, 1, 0), + uint4(7, 1, 2, 0), + uint4(6, 1, 3, 0), + uint4(5, 1, 4, 0), + uint4(4, 1, 5, 0), + uint4(3, 1, 6, 0), + uint4(2, 1, 7, 0), + uint4(1, 1, 8, 0), + uint4(8, 8, 1, 9), + uint4(7, 8, 2, 9), + uint4(6, 8, 3, 9), + uint4(5, 8, 4, 9), + uint4(4, 8, 5, 9), + uint4(3, 8, 6, 9), + uint4(2, 8, 7, 9), + uint4(1, 8, 8, 9), + uint4(1, 8, 0, 1), + uint4(1, 7, 0, 2), + uint4(1, 6, 0, 3), + uint4(1, 5, 0, 4), + uint4(1, 4, 0, 5), + uint4(1, 3, 0, 6), + uint4(1, 2, 0, 7), + uint4(1, 1, 0, 8), + uint4(8, 8, 9, 1), + uint4(8, 7, 9, 2), + uint4(8, 6, 9, 3), + uint4(8, 5, 9, 4), + uint4(8, 4, 9, 5), + uint4(8, 3, 9, 6), + uint4(8, 2, 9, 7), + uint4(8, 1, 9, 8), + uint4(8, 8, 0, 0), + uint4(1, 8, 9, 0), + uint4(8, 1, 0, 9), + uint4(1, 1, 9, 9) +}; +static const uint4 DDGI_DEPTH_BORDER_OFFSETS[68] = { + uint4(16, 1, 1, 0), + uint4(15, 1, 2, 0), + uint4(14, 1, 3, 0), + uint4(13, 1, 4, 0), + uint4(12, 1, 5, 0), + uint4(11, 1, 6, 0), + uint4(10, 1, 7, 0), + uint4(9, 1, 8, 0), + uint4(8, 1, 9, 0), + uint4(7, 1, 10, 0), + uint4(6, 1, 11, 0), + uint4(5, 1, 12, 0), + uint4(4, 1, 13, 0), + uint4(3, 1, 14, 0), + uint4(2, 1, 15, 0), + uint4(1, 1, 16, 0), + uint4(16, 16, 1, 17), + uint4(15, 16, 2, 17), + uint4(14, 16, 3, 17), + uint4(13, 16, 4, 17), + uint4(12, 16, 5, 17), + uint4(11, 16, 6, 17), + uint4(10, 16, 7, 17), + uint4(9, 16, 8, 17), + uint4(8, 16, 9, 17), + uint4(7, 16, 10, 17), + uint4(6, 16, 11, 17), + uint4(5, 16, 12, 17), + uint4(4, 16, 13, 17), + uint4(3, 16, 14, 17), + uint4(2, 16, 15, 17), + uint4(1, 16, 16, 17), + uint4(1, 16, 0, 1), + uint4(1, 15, 0, 2), + uint4(1, 14, 0, 3), + uint4(1, 13, 0, 4), + uint4(1, 12, 0, 5), + uint4(1, 11, 0, 6), + uint4(1, 10, 0, 7), + uint4(1, 9, 0, 8), + uint4(1, 8, 0, 9), + uint4(1, 7, 0, 10), + uint4(1, 6, 0, 11), + uint4(1, 5, 0, 12), + uint4(1, 4, 0, 13), + uint4(1, 3, 0, 14), + uint4(1, 2, 0, 15), + uint4(1, 1, 0, 16), + uint4(16, 16, 17, 1), + uint4(16, 15, 17, 2), + uint4(16, 14, 17, 3), + uint4(16, 13, 17, 4), + uint4(16, 12, 17, 5), + uint4(16, 11, 17, 6), + uint4(16, 10, 17, 7), + uint4(16, 9, 17, 8), + uint4(16, 8, 17, 9), + uint4(16, 7, 17, 10), + uint4(16, 6, 17, 11), + uint4(16, 5, 17, 12), + uint4(16, 4, 17, 13), + uint4(16, 3, 17, 14), + uint4(16, 2, 17, 15), + uint4(16, 1, 17, 16), + uint4(16, 16, 0, 0), + uint4(1, 16, 17, 0), + uint4(16, 1, 0, 17), + uint4(1, 1, 17, 17) +}; + +#endif // __cplusplus + +#endif // WI_SHADERINTEROP_DDGI_H diff --git a/WickedEngine/shaders/ShaderInterop_Renderer.h b/WickedEngine/shaders/ShaderInterop_Renderer.h index c99562282..792796376 100644 --- a/WickedEngine/shaders/ShaderInterop_Renderer.h +++ b/WickedEngine/shaders/ShaderInterop_Renderer.h @@ -30,6 +30,22 @@ struct ShaderScene float padding6; ShaderWeather weather; + + struct DDGI + { + float3 grid_min; + int color_texture; + + float3 grid_extents; + int depth_texture; + + float3 cell_size; + float max_distance; + + float3 grid_extents_rcp; + float padding0; + }; + DDGI ddgi; }; static const uint SHADERMATERIAL_OPTION_BIT_USE_VERTEXCOLORS = 1 << 0; @@ -590,7 +606,7 @@ struct FrameCB int texture_voxelgi_index; int buffer_entityarray_index; int buffer_entitymatrixarray_index; - float surfelgi_boost; + float gi_boost; ShaderScene scene; }; diff --git a/WickedEngine/shaders/Shaders_SOURCE.vcxitems b/WickedEngine/shaders/Shaders_SOURCE.vcxitems index 75aed4a38..179eccd18 100644 --- a/WickedEngine/shaders/Shaders_SOURCE.vcxitems +++ b/WickedEngine/shaders/Shaders_SOURCE.vcxitems @@ -481,6 +481,28 @@ Vertex Vertex + + Pixel + + + Vertex + + + Compute + 4.0 + + + Compute + 4.0 + + + Compute + 4.0 + + + Compute + 4.0 + Vertex Vertex @@ -2809,6 +2831,7 @@ + diff --git a/WickedEngine/shaders/Shaders_SOURCE.vcxitems.filters b/WickedEngine/shaders/Shaders_SOURCE.vcxitems.filters index d2767b3a5..f9f2c6d1c 100644 --- a/WickedEngine/shaders/Shaders_SOURCE.vcxitems.filters +++ b/WickedEngine/shaders/Shaders_SOURCE.vcxitems.filters @@ -1004,6 +1004,24 @@ CS + + VS + + + PS + + + CS + + + CS + + + CS + + + CS + @@ -1048,5 +1066,8 @@ interop + + interop + \ No newline at end of file diff --git a/WickedEngine/shaders/brdf.hlsli b/WickedEngine/shaders/brdf.hlsli index 49aaac59a..b5c29957e 100644 --- a/WickedEngine/shaders/brdf.hlsli +++ b/WickedEngine/shaders/brdf.hlsli @@ -124,6 +124,13 @@ struct ClearcoatSurface float3 F; }; +enum +{ + SURFACE_FLAG_BACKFACE = 1u << 0u, + SURFACE_FLAG_RECEIVE_SHADOW = 1u << 1u, + SURFACE_FLAG_GI_APPLIED = 1u << 2u, +}; + struct Surface { // Fill these yourself: @@ -147,9 +154,8 @@ struct Surface float4 sss; // subsurface scattering color * amount float4 sss_inv; // 1 / (1 + sss) uint layerMask; // the engine-side layer mask - bool receiveshadow; float3 facenormal; // surface normal without normal map - bool is_frontface; + uint flags; // These will be computed when calling Update(): float roughnessBRDF; // roughness input for BRDF functions @@ -183,8 +189,8 @@ struct Surface sss = 0; sss_inv = 1; layerMask = ~0; - receiveshadow = true; facenormal = 0; + flags = 0; sheen.color = 0; sheen.roughness = 0; @@ -241,7 +247,10 @@ struct Surface f0 *= lerp(lerp(float3(0, 0, 0), float3(1, 1, 1), reflectance), baseColor.rgb, metalness); } - receiveshadow = material.IsReceiveShadow(); + if (material.IsReceiveShadow()) + { + flags |= SURFACE_FLAG_RECEIVE_SHADOW; + } } inline void update() @@ -279,7 +288,7 @@ struct Surface #endif // BRDF_CARTOON } - inline bool IsReceiveShadow() { return receiveshadow; } + inline bool IsReceiveShadow() { return flags & SURFACE_FLAG_RECEIVE_SHADOW; } ShaderMeshInstance inst; @@ -440,7 +449,7 @@ struct Surface N = mad(n0, w, mad(n1, u, n2 * v)); // n0 * w + n1 * u + n2 * v N = mul((float3x3)inst.transformInverseTranspose.GetMatrix(), N); N = normalize(N); - if (is_frontface == false && !is_hairparticle && !is_emittedparticle) + if ((flags & SURFACE_FLAG_BACKFACE) && !is_hairparticle && !is_emittedparticle) { N = -N; } diff --git a/WickedEngine/shaders/ddgi_debugPS.hlsl b/WickedEngine/shaders/ddgi_debugPS.hlsl new file mode 100644 index 000000000..82fa73e5a --- /dev/null +++ b/WickedEngine/shaders/ddgi_debugPS.hlsl @@ -0,0 +1,19 @@ +#include "globals.hlsli" +#include "ShaderInterop_DDGI.h" + +struct VSOut +{ + float4 pos : SV_Position; + float3 normal : NORMAL; + uint probeIndex : PROBEINDEX; +}; + +float4 main(VSOut input) : SV_Target +{ + Texture2D ddgiColorTexture = bindless_textures[GetScene().ddgi.color_texture]; + + uint3 probeCoord = ddgi_probe_coord(input.probeIndex); + float3 color = ddgiColorTexture.SampleLevel(sampler_linear_clamp, ddgi_probe_color_uv(probeCoord, input.normal), 0).rgb; + + return float4(color, 1); +} diff --git a/WickedEngine/shaders/ddgi_debugVS.hlsl b/WickedEngine/shaders/ddgi_debugVS.hlsl new file mode 100644 index 000000000..dc46fb7b4 --- /dev/null +++ b/WickedEngine/shaders/ddgi_debugVS.hlsl @@ -0,0 +1,26 @@ +#include "globals.hlsli" +#include "uvsphere.hlsli" +#include "ShaderInterop_DDGI.h" + +struct VSOut +{ + float4 pos : SV_Position; + float3 normal : NORMAL; + uint probeIndex : PROBEINDEX; +}; + +VSOut main(uint vertexID : SV_VertexID, uint instanceID : SV_InstanceID) +{ + VSOut o; + o.pos = UVSPHERE[vertexID]; + o.normal = o.pos.xyz; + o.pos.xyz *= ddgi_max_distance() * 0.05; + o.probeIndex = instanceID; + + const float3 probeCoord = ddgi_probe_coord(o.probeIndex); + const float3 probePosition = ddgi_probe_position(probeCoord); + + o.pos.xyz += probePosition; + o.pos = mul(GetCamera().view_projection, o.pos); + return o; +} diff --git a/WickedEngine/shaders/ddgi_raytraceCS.hlsl b/WickedEngine/shaders/ddgi_raytraceCS.hlsl new file mode 100644 index 000000000..3dff53472 --- /dev/null +++ b/WickedEngine/shaders/ddgi_raytraceCS.hlsl @@ -0,0 +1,283 @@ +#include "globals.hlsli" +#include "raytracingHF.hlsli" +#include "lightingHF.hlsli" +#include "ShaderInterop_DDGI.h" + +// This shader runs one probe per thread group and each thread will trace rays and write the trace result to a ray data buffer +// ray data buffer will be later integrated by ddgi_updateCS shader which updates the DDGI irradiance and depth textures + +PUSHCONSTANT(push, DDGIPushConstants); + +RWStructuredBuffer rayBuffer : register(u0); + +static const uint THREADCOUNT = 32; + +// spherical fibonacci: https://github.com/diharaw/hybrid-rendering/blob/master/src/shaders/gi/gi_ray_trace.rgen +#define madfrac(A, B) ((A) * (B)-floor((A) * (B))) +static const float PHI = sqrt(5) * 0.5 + 0.5; +float3 spherical_fibonacci(float i, float n) +{ + float phi = 2.0 * PI * madfrac(i, PHI - 1); + float cos_theta = 1.0 - (2.0 * i + 1.0) * (1.0 / n); + float sin_theta = sqrt(clamp(1.0 - cos_theta * cos_theta, 0.0f, 1.0f)); + return float3(cos(phi) * sin_theta, sin(phi) * sin_theta, cos_theta); +} + +[numthreads(THREADCOUNT, 1, 1)] +void main(uint3 DTid : SV_DispatchThreadID, uint3 Gid : SV_GroupID, uint groupIndex : SV_GroupIndex) +{ + const uint probeIndex = Gid.x; + const uint3 probeCoord = ddgi_probe_coord(probeIndex); + const float3 probePos = ddgi_probe_position(probeCoord); + + float seed = 0.123456; + float2 uv = float2(frac(GetFrame().frame_count.x / 4096.0), DTid.x); + + const float3x3 random_orientation = (float3x3)g_xTransform; + + for (uint rayIndex = groupIndex; rayIndex < push.rayCount; rayIndex += THREADCOUNT) + { + RayDesc ray; + ray.Origin = probePos; + ray.TMin = 0.0001; + ray.TMax = FLT_MAX; + ray.Direction = normalize(mul(random_orientation, spherical_fibonacci(rayIndex, push.rayCount))); + +#ifdef RTAPI + RayQuery< + RAY_FLAG_SKIP_PROCEDURAL_PRIMITIVES | + RAY_FLAG_FORCE_OPAQUE + > q; + q.TraceRayInline( + scene_acceleration_structure, // RaytracingAccelerationStructure AccelerationStructure + 0, // uint RayFlags + push.instanceInclusionMask, // uint InstanceInclusionMask + ray // RayDesc Ray + ); + q.Proceed(); + if (q.CommittedStatus() != COMMITTED_TRIANGLE_HIT) +#else + RayHit hit = TraceRay_Closest(ray, push.instanceInclusionMask, seed, uv); + + if (hit.distance >= FLT_MAX - 1) +#endif // RTAPI + + { + float3 envColor; + [branch] + if (IsStaticSky()) + { + // We have envmap information in a texture: + envColor = DEGAMMA_SKY(texture_globalenvmap.SampleLevel(sampler_linear_clamp, ray.Direction, 0).rgb); + } + else + { + envColor = GetDynamicSkyColor(ray.Direction, true, true, false, true); + } + + DDGIRayData rayData; + rayData.direction = ray.Direction; + rayData.depth = -1; + rayData.radiance = float4(envColor, 1); + rayBuffer[probeIndex * DDGI_MAX_RAYCOUNT + rayIndex].store(rayData); + } + else + { + + Surface surface; + + float hit_depth = 0; + float3 hit_result = 0; + +#ifdef RTAPI + + // ray origin updated for next bounce: + ray.Origin = q.WorldRayOrigin() + q.WorldRayDirection() * q.CommittedRayT(); + hit_depth = q.CommittedRayT(); + + PrimitiveID prim; + prim.primitiveIndex = q.CommittedPrimitiveIndex(); + prim.instanceIndex = q.CommittedInstanceID(); + prim.subsetIndex = q.CommittedGeometryIndex(); + + if (!q.CommittedTriangleFrontFace()) + { + surface.flags |= SURFACE_FLAG_BACKFACE; + } + + if (!surface.load(prim, q.CommittedTriangleBarycentrics())) + break; + +#else + + // ray origin updated for next bounce: + ray.Origin = ray.Origin + ray.Direction * hit.distance; + hit_depth = hit.distance; + + if (!surface.load(hit.primitiveID, hit.bary)) + break; + +#endif // RTAPI + + surface.P = ray.Origin; + surface.V = -ray.Direction; + surface.update(); + +#if 1 + // Light sampling: + [loop] + for (uint iterator = 0; iterator < GetFrame().lightarray_count; iterator++) + { + ShaderEntity light = load_entity(GetFrame().lightarray_offset + iterator); + + Lighting lighting; + lighting.create(0, 0, 0, 0); + + float3 L = 0; + float dist = 0; + float NdotL = 0; + + switch (light.GetType()) + { + case ENTITY_TYPE_DIRECTIONALLIGHT: + { + dist = FLT_MAX; + + L = light.GetDirection().xyz; + NdotL = saturate(dot(L, surface.N)); + + [branch] + if (NdotL > 0) + { + float3 lightColor = light.GetColor().rgb * light.GetEnergy(); + + [branch] + if (GetFrame().options & OPTION_BIT_REALISTIC_SKY) + { + lightColor *= GetAtmosphericLightTransmittance(GetWeather().atmosphere, surface.P, L, texture_transmittancelut); + } + + lighting.direct.diffuse = lightColor; + } + } + break; + case ENTITY_TYPE_POINTLIGHT: + { + L = light.position - surface.P; + const float dist2 = dot(L, L); + const float range2 = light.GetRange() * light.GetRange(); + + [branch] + if (dist2 < range2) + { + dist = sqrt(dist2); + L /= dist; + NdotL = saturate(dot(L, surface.N)); + + [branch] + if (NdotL > 0) + { + const float3 lightColor = light.GetColor().rgb * light.GetEnergy(); + + lighting.direct.diffuse = lightColor; + + const float range2 = light.GetRange() * light.GetRange(); + const float att = saturate(1.0 - (dist2 / range2)); + const float attenuation = att * att; + + lighting.direct.diffuse *= attenuation; + } + } + } + break; + case ENTITY_TYPE_SPOTLIGHT: + { + L = light.position - surface.P; + const float dist2 = dot(L, L); + const float range2 = light.GetRange() * light.GetRange(); + + [branch] + if (dist2 < range2) + { + dist = sqrt(dist2); + L /= dist; + NdotL = saturate(dot(L, surface.N)); + + [branch] + if (NdotL > 0) + { + const float SpotFactor = dot(L, light.GetDirection()); + const float spotCutOff = light.GetConeAngleCos(); + + [branch] + if (SpotFactor > spotCutOff) + { + const float3 lightColor = light.GetColor().rgb * light.GetEnergy(); + + lighting.direct.diffuse = lightColor; + + const float range2 = light.GetRange() * light.GetRange(); + const float att = saturate(1.0 - (dist2 / range2)); + float attenuation = att * att; + attenuation *= saturate((1.0 - (1.0 - SpotFactor) * 1.0 / (1.0 - spotCutOff))); + + lighting.direct.diffuse *= attenuation; + } + } + } + } + break; + } + + if (NdotL > 0 && dist > 0) + { + float3 shadow = NdotL; + + RayDesc newRay; + newRay.Origin = surface.P; +#if 1 + newRay.Direction = normalize(lerp(L, sample_hemisphere_cos(L, seed, uv), 0.025f)); +#else + newRay.Direction = L; +#endif + newRay.TMin = 0.001; + newRay.TMax = dist; +#ifdef RTAPI + q.TraceRayInline( + scene_acceleration_structure, // RaytracingAccelerationStructure AccelerationStructure + RAY_FLAG_ACCEPT_FIRST_HIT_AND_END_SEARCH, // uint RayFlags + 0xFF, // uint InstanceInclusionMask + newRay // RayDesc Ray + ); + q.Proceed(); + shadow = q.CommittedStatus() == COMMITTED_TRIANGLE_HIT ? 0 : shadow; +#else + shadow = TraceRay_Any(newRay, push.instanceInclusionMask, seed, uv) ? 0 : shadow; +#endif // RTAPI + if (any(shadow)) + { + hit_result += max(0, shadow * lighting.direct.diffuse / PI); + } + } + } + +#endif + + // Infinite bounces based on previous frame probe sampling: + if (push.frameIndex > 0) + { + hit_result += ddgi_sample_irradiance(surface.P, surface.facenormal); + } + + hit_result *= surface.albedo; + hit_result += max(0, surface.emissiveColor); + + DDGIRayData rayData; + rayData.direction = ray.Direction; + rayData.depth = hit_depth; + rayData.radiance = float4(hit_result, 1); + rayBuffer[probeIndex * DDGI_MAX_RAYCOUNT + rayIndex].store(rayData); + } + + } +} diff --git a/WickedEngine/shaders/ddgi_raytraceCS_rtapi.hlsl b/WickedEngine/shaders/ddgi_raytraceCS_rtapi.hlsl new file mode 100644 index 000000000..ec0ff7d9d --- /dev/null +++ b/WickedEngine/shaders/ddgi_raytraceCS_rtapi.hlsl @@ -0,0 +1,2 @@ +#define RTAPI +#include "ddgi_raytraceCS.hlsl" diff --git a/WickedEngine/shaders/ddgi_updateCS.hlsl b/WickedEngine/shaders/ddgi_updateCS.hlsl new file mode 100644 index 000000000..1fd28735b --- /dev/null +++ b/WickedEngine/shaders/ddgi_updateCS.hlsl @@ -0,0 +1,141 @@ +#include "globals.hlsli" +#include "ShaderInterop_DDGI.h" + +// This shader collects all traced rays (one probe per thread group) and integrates them +// Rays are first gathered to shared memory +// Then for each pixel, all traced rays will be evaluated and contributed, weighted based on pixel's own direction and ray's direction +// This shader will run twice in DDGI, once it integrates the radiances +// After that it will also integrate the ray depths, when DDGI_UPDATE_DEPTH is defined +// Based on: https://github.com/diharaw/hybrid-rendering/blob/master/src/shaders/gi/gi_probe_update.glsl + +PUSHCONSTANT(push, DDGIPushConstants); + +StructuredBuffer ddgiRayBuffer : register(t0); + +static const uint CACHE_SIZE = 64; +groupshared DDGIRayDataPacked ray_cache[CACHE_SIZE]; + +static const float WEIGHT_EPSILON = 0.0001; + +#ifdef DDGI_UPDATE_DEPTH +static const uint THREADCOUNT = DDGI_DEPTH_RESOLUTION; +RWTexture2D output : register(u0); +#else +static const uint THREADCOUNT = DDGI_COLOR_RESOLUTION; +RWTexture2D output : register(u0); +#endif // DDGI_UPDATE_DEPTH + +[numthreads(THREADCOUNT, THREADCOUNT, 1)] +void main(uint3 GTid : SV_GroupThreadID, uint3 Gid : SV_GroupID, uint groupIndex : SV_GroupIndex) +{ + const uint probeIndex = Gid.x; + const uint3 probeCoord = ddgi_probe_coord(probeIndex); + const float maxDistance = ddgi_max_distance(); + +#ifdef DDGI_UPDATE_DEPTH + float2 result = 0; + const uint2 pixel_topleft = ddgi_probe_depth_pixel(probeCoord); +#else + float3 result = 0; + const uint2 pixel_topleft = ddgi_probe_color_pixel(probeCoord); +#endif // DDGI_UPDATE_DEPTH + const uint2 pixel_current = pixel_topleft + GTid.xy; + const uint2 copy_coord = pixel_topleft - 1; + + const float3 texel_direction = decode_oct(((GTid.xy + 0.5) / (float2)THREADCOUNT) * 2 - 1); + + float total_weight = 0; + + uint remaining_rays = push.rayCount; + uint offset = 0; + + while (remaining_rays > 0) + { + uint num_rays = min(CACHE_SIZE, remaining_rays); + + if (groupIndex < num_rays) + { + ray_cache[groupIndex] = ddgiRayBuffer[probeIndex * DDGI_MAX_RAYCOUNT + groupIndex + offset]; + } + + GroupMemoryBarrierWithGroupSync(); + + for (uint r = 0; r < num_rays; ++r) + { + DDGIRayData ray = ray_cache[r].load(); + +#ifdef DDGI_UPDATE_DEPTH + float ray_probe_distance; + if (ray.depth > 0) + { + ray_probe_distance = clamp(ray.depth - 0.01, 0, maxDistance); + } + else + { + ray_probe_distance = maxDistance; + } +#else + const float3 radiance = ray.radiance.rgb; +#endif // DDGI_UPDATE_DEPTH + + float weight = saturate(dot(texel_direction, ray.direction)); +#ifdef DDGI_UPDATE_DEPTH + weight = pow(weight, 64); +#endif // DDGI_UPDATE_DEPTH + + if (weight > WEIGHT_EPSILON) + { +#ifdef DDGI_UPDATE_DEPTH + result += float2(ray_probe_distance * weight, sqr(ray_probe_distance) * weight); +#else + result += ray.radiance.rgb * weight; +#endif // DDGI_UPDATE_DEPTH + + total_weight += weight; + } + } + + GroupMemoryBarrierWithGroupSync(); + + remaining_rays -= num_rays; + offset += num_rays; + } + + if (total_weight > WEIGHT_EPSILON) + { + result /= total_weight; + } + +#ifdef DDGI_UPDATE_DEPTH + const float2 prev_result = bindless_textures[GetScene().ddgi.depth_texture][pixel_current].xy; +#else + const float3 prev_result = bindless_textures[GetScene().ddgi.color_texture][pixel_current].rgb; +#endif // DDGI_UPDATE_DEPTH + + if (push.frameIndex > 0) + { + result = lerp(prev_result, result, 0.02); + } + + output[pixel_current] = result; + + DeviceMemoryBarrierWithGroupSync(); + +#ifdef DDGI_UPDATE_DEPTH + // Copy depth borders: + for (uint index = groupIndex; index < 68; index += THREADCOUNT * THREADCOUNT) + { + uint2 src_coord = copy_coord + DDGI_DEPTH_BORDER_OFFSETS[index].xy; + uint2 dst_coord = copy_coord + DDGI_DEPTH_BORDER_OFFSETS[index].zw; + output[dst_coord] = output[src_coord]; + } +#else + // Copy color borders: + for (uint index = groupIndex; index < 36; index += THREADCOUNT * THREADCOUNT) + { + uint2 src_coord = copy_coord + DDGI_COLOR_BORDER_OFFSETS[index].xy; + uint2 dst_coord = copy_coord + DDGI_COLOR_BORDER_OFFSETS[index].zw; + output[dst_coord] = output[src_coord]; + } +#endif // DDGI_UPDATE_DEPTH +} diff --git a/WickedEngine/shaders/ddgi_updateCS_depth.hlsl b/WickedEngine/shaders/ddgi_updateCS_depth.hlsl new file mode 100644 index 000000000..f0959fa68 --- /dev/null +++ b/WickedEngine/shaders/ddgi_updateCS_depth.hlsl @@ -0,0 +1,2 @@ +#define DDGI_UPDATE_DEPTH +#include "ddgi_updateCS.hlsl" diff --git a/WickedEngine/shaders/objectHF.hlsli b/WickedEngine/shaders/objectHF.hlsli index a949301b6..0869bc0d0 100644 --- a/WickedEngine/shaders/objectHF.hlsli +++ b/WickedEngine/shaders/objectHF.hlsli @@ -21,6 +21,7 @@ #include "brdf.hlsli" #include "lightingHF.hlsli" #include "ShaderInterop_SurfelGI.h" +#include "ShaderInterop_DDGI.h" // DEFINITIONS ////////////////// @@ -350,7 +351,7 @@ inline void ApplyEmissive(in Surface surface, inout Lighting lighting) lighting.direct.specular += surface.emissiveColor; } -inline void LightMapping(in int lightmap, in float2 ATLAS, inout Lighting lighting) +inline void LightMapping(in int lightmap, in float2 ATLAS, inout Lighting lighting, inout Surface surface) { [branch] if (lightmap >= 0 && any(ATLAS)) @@ -361,6 +362,8 @@ inline void LightMapping(in int lightmap, in float2 ATLAS, inout Lighting lighti #else lighting.indirect.diffuse = texture_lightmap.SampleLevel(sampler_linear_clamp, ATLAS, 0).rgb; #endif // LIGHTMAP_QUALITY_BICUBIC + + surface.flags |= SURFACE_FLAG_GI_APPLIED; } } @@ -626,6 +629,13 @@ inline void ForwardLighting(inout Surface surface, inout Lighting lighting) } } + [branch] + if ((surface.flags & SURFACE_FLAG_GI_APPLIED) == 0 && GetScene().ddgi.color_texture >= 0) + { + lighting.indirect.diffuse = ddgi_sample_irradiance(surface.P, surface.N); + surface.flags |= SURFACE_FLAG_GI_APPLIED; + } + } inline void TiledLighting(inout Surface surface, inout Lighting lighting) @@ -900,15 +910,22 @@ inline void TiledLighting(inout Surface surface, inout Lighting lighting) } } - #ifndef TRANSPARENT [branch] - if (GetFrame().options & OPTION_BIT_SURFELGI_ENABLED && GetCamera().texture_surfelgi_index >= 0 && surfel_cellvalid(surfel_cell(surface.P))) + if ((surface.flags & SURFACE_FLAG_GI_APPLIED) == 0 && GetFrame().options & OPTION_BIT_SURFELGI_ENABLED && GetCamera().texture_surfelgi_index >= 0 && surfel_cellvalid(surfel_cell(surface.P))) { - lighting.indirect.diffuse = bindless_textures[GetCamera().texture_surfelgi_index][surface.pixel].rgb * GetFrame().surfelgi_boost; + lighting.indirect.diffuse = bindless_textures[GetCamera().texture_surfelgi_index][surface.pixel].rgb * GetFrame().gi_boost; + surface.flags |= SURFACE_FLAG_GI_APPLIED; } #endif // TRANSPARENT + [branch] + if ((surface.flags & SURFACE_FLAG_GI_APPLIED) == 0 && GetScene().ddgi.color_texture >= 0) + { + lighting.indirect.diffuse = ddgi_sample_irradiance(surface.P, surface.N) * GetFrame().gi_boost; + surface.flags |= SURFACE_FLAG_GI_APPLIED; + } + } inline void ApplyLighting(in Surface surface, in Lighting lighting, inout float4 color) @@ -1652,7 +1669,7 @@ float4 main(PixelInput input, in bool is_frontface : SV_IsFrontFace) : SV_Target #ifdef OBJECTSHADER_USE_ATLAS - LightMapping(load_instance(input.instanceID).lightmap, input.atl, lighting); + LightMapping(load_instance(input.instanceID).lightmap, input.atl, lighting, surface); #endif // OBJECTSHADER_USE_ATLAS diff --git a/WickedEngine/shaders/raytraceCS.hlsl b/WickedEngine/shaders/raytraceCS.hlsl index fc59dc82d..ea61c3f6a 100644 --- a/WickedEngine/shaders/raytraceCS.hlsl +++ b/WickedEngine/shaders/raytraceCS.hlsl @@ -114,7 +114,11 @@ void main(uint3 DTid : SV_DispatchThreadID, uint groupIndex : SV_GroupIndex) prim.instanceIndex = q.CommittedInstanceID(); prim.subsetIndex = q.CommittedGeometryIndex(); - surface.is_frontface = q.CommittedTriangleFrontFace(); + if (!q.CommittedTriangleFrontFace()) + { + surface.flags |= SURFACE_FLAG_BACKFACE; + } + if (!surface.load(prim, q.CommittedTriangleBarycentrics())) return; diff --git a/WickedEngine/shaders/rtreflectionCS.hlsl b/WickedEngine/shaders/rtreflectionCS.hlsl index b5814433c..358db255f 100644 --- a/WickedEngine/shaders/rtreflectionCS.hlsl +++ b/WickedEngine/shaders/rtreflectionCS.hlsl @@ -7,6 +7,7 @@ #include "raytracingHF.hlsli" #include "stochasticSSRHF.hlsli" #include "lightingHF.hlsli" +#include "ShaderInterop_DDGI.h" PUSHCONSTANT(postprocess, PostProcess); @@ -143,7 +144,10 @@ void main(uint2 DTid : SV_DispatchThreadID) prim.subsetIndex = q.CommittedGeometryIndex(); Surface surface; - surface.is_frontface = q.CommittedTriangleFrontFace(); + if (!q.CommittedTriangleFrontFace()) + { + surface.flags |= SURFACE_FLAG_BACKFACE; + } if (!surface.load(prim, q.CommittedTriangleBarycentrics())) return; @@ -198,6 +202,12 @@ void main(uint2 DTid : SV_DispatchThreadID) lighting.indirect.specular += max(0, EnvironmentReflection_Global(surface)); + [branch] + if (GetScene().ddgi.color_texture >= 0) + { + lighting.indirect.diffuse = ddgi_sample_irradiance(surface.P, surface.N); + } + LightingPart combined_lighting = CombineLighting(surface, lighting); payload.data.xyz += surface.albedo * combined_lighting.diffuse + combined_lighting.specular + surface.emissiveColor; } diff --git a/WickedEngine/shaders/rtreflectionLIB.hlsl b/WickedEngine/shaders/rtreflectionLIB.hlsl index 056a2359d..1cedcb5f9 100644 --- a/WickedEngine/shaders/rtreflectionLIB.hlsl +++ b/WickedEngine/shaders/rtreflectionLIB.hlsl @@ -124,7 +124,10 @@ void RTReflection_ClosestHit(inout RayPayload payload, in BuiltInTriangleInterse prim.subsetIndex = GeometryIndex(); Surface surface; - surface.is_frontface = (HitKind() == HIT_KIND_TRIANGLE_FRONT_FACE); + if (HitKind() != HIT_KIND_TRIANGLE_FRONT_FACE) + { + surface.flags |= SURFACE_FLAG_BACKFACE; + } if (!surface.load(prim, attr.barycentrics)) return; diff --git a/WickedEngine/shaders/surfel_raytraceCS.hlsl b/WickedEngine/shaders/surfel_raytraceCS.hlsl index 2c2baa78e..738b461d0 100644 --- a/WickedEngine/shaders/surfel_raytraceCS.hlsl +++ b/WickedEngine/shaders/surfel_raytraceCS.hlsl @@ -108,6 +108,10 @@ void main(uint3 DTid : SV_DispatchThreadID) prim.instanceIndex = q.CommittedInstanceID(); prim.subsetIndex = q.CommittedGeometryIndex(); + if (!q.CommittedTriangleFrontFace()) + { + surface.flags |= SURFACE_FLAG_BACKFACE; + } if(!surface.load(prim, q.CommittedTriangleBarycentrics())) break; diff --git a/WickedEngine/wiEnums.h b/WickedEngine/wiEnums.h index 47d78a452..0e382fbcd 100644 --- a/WickedEngine/wiEnums.h +++ b/WickedEngine/wiEnums.h @@ -122,6 +122,7 @@ namespace wi::enums VSTYPE_RAYTRACE_SCREEN, VSTYPE_POSTPROCESS, VSTYPE_LENSFLARE, + VSTYPE_DDGI_DEBUG, // pixel shaders @@ -188,6 +189,7 @@ namespace wi::enums PSTYPE_POSTPROCESS_UPSAMPLE_BILATERAL, PSTYPE_POSTPROCESS_OUTLINE, PSTYPE_LENSFLARE, + PSTYPE_DDGI_DEBUG, // geometry shaders @@ -344,6 +346,9 @@ namespace wi::enums CSTYPE_SURFEL_BINNING, CSTYPE_VISIBILITY_RESOLVE, CSTYPE_VISIBILITY_RESOLVE_MSAA, + CSTYPE_DDGI_RAYTRACE, + CSTYPE_DDGI_UPDATE, + CSTYPE_DDGI_UPDATE_DEPTH, // raytracing pipelines: diff --git a/WickedEngine/wiRandom.cpp b/WickedEngine/wiRandom.cpp index a8a4ac218..05f56fe41 100644 --- a/WickedEngine/wiRandom.cpp +++ b/WickedEngine/wiRandom.cpp @@ -40,4 +40,14 @@ namespace wi::random { return GetRandom(0ull, maxValue); } + + float GetRandom(float minValue, float maxValue) + { + std::uniform_real_distribution distr(minValue, maxValue); + return distr(generator()); + } + float GetRandom(float maxValue) + { + return GetRandom(0.0f, maxValue); + } } diff --git a/WickedEngine/wiRandom.h b/WickedEngine/wiRandom.h index 7e30b2777..223f50bbe 100644 --- a/WickedEngine/wiRandom.h +++ b/WickedEngine/wiRandom.h @@ -11,5 +11,8 @@ namespace wi::random uint64_t GetRandom(uint64_t minValue, uint64_t maxValue); uint64_t GetRandom(uint64_t maxValue); + + float GetRandom(float minValue, float maxValue); + float GetRandom(float maxValue); }; diff --git a/WickedEngine/wiRenderPath3D.cpp b/WickedEngine/wiRenderPath3D.cpp index 1819d97eb..21e82e4cd 100644 --- a/WickedEngine/wiRenderPath3D.cpp +++ b/WickedEngine/wiRenderPath3D.cpp @@ -523,6 +523,7 @@ void RenderPath3D::Update(float dt) if (getSceneUpdateEnabled()) { if (wi::renderer::GetSurfelGIEnabled() || + wi::renderer::GetDDGIEnabled() || wi::renderer::GetRaytracedShadowsEnabled() || getAO() == AO_RTAO || getRaytracedReflectionEnabled()) @@ -697,6 +698,15 @@ void RenderPath3D::Render() const ); } + if (wi::renderer::GetDDGIEnabled()) + { + wi::renderer::DDGI( + *scene, + cmd, + instanceInclusionMask_DDGI + ); + } + }); static const uint32_t drawscene_flags = diff --git a/WickedEngine/wiRenderPath3D.h b/WickedEngine/wiRenderPath3D.h index 9efb3fa50..cfdda9677 100644 --- a/WickedEngine/wiRenderPath3D.h +++ b/WickedEngine/wiRenderPath3D.h @@ -161,6 +161,7 @@ namespace wi uint8_t instanceInclusionMask_RTReflection = 0xFF; uint8_t instanceInclusionMask_SurfelGI = 0xFF; uint8_t instanceInclusionMask_Lightmap = 0xFF; + uint8_t instanceInclusionMask_DDGI = 0xFF; const wi::graphics::Texture* GetDepthStencil() const override { return &depthBuffer_Main; } const wi::graphics::Texture* GetGUIBlurredBackground() const override { return &rtGUIBlurredBackground[2]; } diff --git a/WickedEngine/wiRenderer.cpp b/WickedEngine/wiRenderer.cpp index 3f9d90b1f..b825fa699 100644 --- a/WickedEngine/wiRenderer.cpp +++ b/WickedEngine/wiRenderer.cpp @@ -24,6 +24,7 @@ #include "shaders/ShaderInterop_Postprocess.h" #include "shaders/ShaderInterop_Raytracing.h" #include "shaders/ShaderInterop_BVH.h" +#include "shaders/ShaderInterop_DDGI.h" #include #include @@ -96,8 +97,11 @@ bool disableAlbedoMaps = false; bool forceDiffuseLighting = false; bool SCREENSPACESHADOWS = false; bool SURFELGI = false; -float SURFELGI_BOOST = 1.0f; SURFEL_DEBUG SURFELGI_DEBUG = SURFEL_DEBUG_NONE; +bool DDGI_ENABLED = false; +bool DDGI_DEBUG_ENABLED = false; +uint32_t DDGI_RAYCOUNT = 128u; +float GI_BOOST = 1.0f; struct VoxelizedSceneData @@ -581,6 +585,7 @@ PipelineState PSO_sky[SKYRENDERING_COUNT]; enum DEBUGRENDERING { DEBUGRENDERING_ENVPROBE, + DEBUGRENDERING_DDGI, DEBUGRENDERING_GRID, DEBUGRENDERING_CUBE, DEBUGRENDERING_LINES, @@ -748,6 +753,7 @@ void LoadShaders() wi::jobsystem::Execute(ctx, [](wi::jobsystem::JobArgs args) { LoadShader(ShaderStage::VS, shaders[VSTYPE_RAYTRACE_SCREEN], "raytrace_screenVS.cso"); }); wi::jobsystem::Execute(ctx, [](wi::jobsystem::JobArgs args) { LoadShader(ShaderStage::VS, shaders[VSTYPE_POSTPROCESS], "postprocessVS.cso"); }); wi::jobsystem::Execute(ctx, [](wi::jobsystem::JobArgs args) { LoadShader(ShaderStage::VS, shaders[VSTYPE_LENSFLARE], "lensFlareVS.cso"); }); + wi::jobsystem::Execute(ctx, [](wi::jobsystem::JobArgs args) { LoadShader(ShaderStage::VS, shaders[VSTYPE_DDGI_DEBUG], "ddgi_debugVS.cso"); }); if (device->CheckCapability(GraphicsDeviceCapability::RENDERTARGET_AND_VIEWPORT_ARRAYINDEX_WITHOUT_GS)) { @@ -840,6 +846,7 @@ void LoadShaders() wi::jobsystem::Execute(ctx, [](wi::jobsystem::JobArgs args) { LoadShader(ShaderStage::PS, shaders[PSTYPE_POSTPROCESS_UPSAMPLE_BILATERAL], "upsample_bilateralPS.cso"); }); wi::jobsystem::Execute(ctx, [](wi::jobsystem::JobArgs args) { LoadShader(ShaderStage::PS, shaders[PSTYPE_POSTPROCESS_OUTLINE], "outlinePS.cso"); }); wi::jobsystem::Execute(ctx, [](wi::jobsystem::JobArgs args) { LoadShader(ShaderStage::PS, shaders[PSTYPE_LENSFLARE], "lensFlarePS.cso"); }); + wi::jobsystem::Execute(ctx, [](wi::jobsystem::JobArgs args) { LoadShader(ShaderStage::PS, shaders[PSTYPE_DDGI_DEBUG], "ddgi_debugPS.cso"); }); wi::jobsystem::Execute(ctx, [](wi::jobsystem::JobArgs args) { LoadShader(ShaderStage::GS, shaders[GSTYPE_VOXELIZER], "objectGS_voxelizer.cso"); }); wi::jobsystem::Execute(ctx, [](wi::jobsystem::JobArgs args) { LoadShader(ShaderStage::GS, shaders[GSTYPE_VOXEL], "voxelGS.cso"); }); @@ -998,6 +1005,17 @@ void LoadShaders() wi::jobsystem::Execute(ctx, [](wi::jobsystem::JobArgs args) { LoadShader(ShaderStage::CS, shaders[CSTYPE_VISIBILITY_RESOLVE], "visibility_resolveCS.cso"); }); wi::jobsystem::Execute(ctx, [](wi::jobsystem::JobArgs args) { LoadShader(ShaderStage::CS, shaders[CSTYPE_VISIBILITY_RESOLVE_MSAA], "visibility_resolveCS_MSAA.cso"); }); + if (device->CheckCapability(GraphicsDeviceCapability::RAYTRACING)) + { + wi::jobsystem::Execute(ctx, [](wi::jobsystem::JobArgs args) { LoadShader(ShaderStage::CS, shaders[CSTYPE_DDGI_RAYTRACE], "ddgi_raytraceCS_rtapi.cso", ShaderModel::SM_6_5); }); + } + else + { + wi::jobsystem::Execute(ctx, [](wi::jobsystem::JobArgs args) { LoadShader(ShaderStage::CS, shaders[CSTYPE_DDGI_RAYTRACE], "ddgi_raytraceCS.cso"); }); + } + wi::jobsystem::Execute(ctx, [](wi::jobsystem::JobArgs args) { LoadShader(ShaderStage::CS, shaders[CSTYPE_DDGI_UPDATE], "ddgi_updateCS.cso"); }); + wi::jobsystem::Execute(ctx, [](wi::jobsystem::JobArgs args) { LoadShader(ShaderStage::CS, shaders[CSTYPE_DDGI_UPDATE_DEPTH], "ddgi_updateCS_depth.cso"); }); + wi::jobsystem::Execute(ctx, [](wi::jobsystem::JobArgs args) { LoadShader(ShaderStage::HS, shaders[HSTYPE_OBJECT], "objectHS.cso"); }); wi::jobsystem::Execute(ctx, [](wi::jobsystem::JobArgs args) { LoadShader(ShaderStage::HS, shaders[HSTYPE_OBJECT_PREPASS], "objectHS_prepass.cso"); }); wi::jobsystem::Execute(ctx, [](wi::jobsystem::JobArgs args) { LoadShader(ShaderStage::HS, shaders[HSTYPE_OBJECT_PREPASS_ALPHATEST], "objectHS_prepass_alphatest.cso"); }); @@ -1481,6 +1499,14 @@ void LoadShaders() desc.bs = &blendStates[BSTYPE_OPAQUE]; desc.pt = PrimitiveTopology::TRIANGLELIST; break; + case DEBUGRENDERING_DDGI: + desc.vs = &shaders[VSTYPE_DDGI_DEBUG]; + desc.ps = &shaders[PSTYPE_DDGI_DEBUG]; + desc.dss = &depthStencils[DSSTYPE_DEFAULT]; + desc.rs = &rasterizers[RSTYPE_FRONT]; + desc.bs = &blendStates[BSTYPE_OPAQUE]; + desc.pt = PrimitiveTopology::TRIANGLELIST; + break; case DEBUGRENDERING_GRID: desc.vs = &shaders[VSTYPE_VERTEXCOLOR]; desc.ps = &shaders[PSTYPE_VERTEXCOLOR]; @@ -2992,7 +3018,7 @@ void UpdatePerFrameData( frameCB.envprobe_mipcount_rcp = 1.0f / (float)frameCB.envprobe_mipcount; } - frameCB.surfelgi_boost = GetSurfelGIBoost(); + frameCB.gi_boost = GetGIBoost(); frameCB.temporalaa_samplerotation = 0; if (GetTemporalAAEnabled()) @@ -5654,6 +5680,17 @@ void DrawDebugWorld( } + if (GetDDGIDebugEnabled()) + { + device->EventBegin("Debug DDGI", cmd); + + device->BindPipelineState(&PSO_debug[DEBUGRENDERING_DDGI], cmd); + device->DrawInstanced(2880, DDGI_GRID_DIMENSIONS.x* DDGI_GRID_DIMENSIONS.y* DDGI_GRID_DIMENSIONS.z, 0, 0, cmd); // uv-sphere + + device->EventEnd(cmd); + } + + if (gridHelper) { device->EventBegin("GridHelper", cmd); @@ -7951,6 +7988,120 @@ void SurfelGI( device->EventEnd(cmd); } +void DDGI( + const wi::scene::Scene& scene, + wi::graphics::CommandList cmd, + uint8_t instanceInclusionMask +) +{ + if (!scene.TLAS.IsValid() && !scene.BVH.IsValid()) + return; + + auto prof_range = wi::profiler::BeginRangeGPU("DDGI", cmd); + device->EventBegin("DDGI", cmd); + + BindCommonResources(cmd); + + DDGIPushConstants push; + push.instanceInclusionMask = instanceInclusionMask; + push.frameIndex = scene.ddgi_frameIndex; + push.rayCount = std::min(GetDDGIRayCount(), DDGI_MAX_RAYCOUNT); + + // Raytracing: + { + device->EventBegin("Raytrace", cmd); + + device->BindComputeShader(&shaders[CSTYPE_DDGI_RAYTRACE], cmd); + device->PushConstants(&push, sizeof(push), cmd); + + MiscCB cb = {}; + float angle = wi::random::GetRandom(0.0f, 1.0f) * XM_2PI; + XMVECTOR axis = XMVectorSet( + wi::random::GetRandom(-1.0f, 1.0f), + wi::random::GetRandom(-1.0f, 1.0f), + wi::random::GetRandom(-1.0f, 1.0f), + 0 + ); + axis = XMVector3Normalize(axis); + XMStoreFloat4x4(&cb.g_xTransform, XMMatrixRotationAxis(axis, angle)); + device->BindDynamicConstantBuffer(cb, CB_GETBINDSLOT(MiscCB), cmd); + + const GPUResource* uavs[] = { + &scene.ddgiRayBuffer + }; + device->BindUAVs(uavs, 0, arraysize(uavs), cmd); + + device->Dispatch(DDGI_PROBE_COUNT, 1, 1, cmd); + + device->EventEnd(cmd); + } + + { + GPUBarrier barriers[] = { + GPUBarrier::Memory(), + GPUBarrier::Buffer(&scene.ddgiRayBuffer, ResourceState::UNORDERED_ACCESS, ResourceState::SHADER_RESOURCE_COMPUTE), + GPUBarrier::Image(&scene.ddgiColorTexture[1], ResourceState::SHADER_RESOURCE_COMPUTE, ResourceState::UNORDERED_ACCESS), + GPUBarrier::Image(&scene.ddgiDepthTexture[1], ResourceState::SHADER_RESOURCE_COMPUTE, ResourceState::UNORDERED_ACCESS), + }; + device->Barrier(barriers, arraysize(barriers), cmd); + } + + // Update: + { + device->EventBegin("Update", cmd); + + device->BindComputeShader(&shaders[CSTYPE_DDGI_UPDATE], cmd); + device->PushConstants(&push, sizeof(push), cmd); + + const GPUResource* res[] = { + &scene.ddgiRayBuffer, + }; + device->BindResources(res, 0, arraysize(res), cmd); + + const GPUResource* uavs[] = { + &scene.ddgiColorTexture[1], + }; + device->BindUAVs(uavs, 0, arraysize(uavs), cmd); + + device->Dispatch(DDGI_PROBE_COUNT, 1, 1, cmd); + + device->EventEnd(cmd); + } + + // Update Depth: + { + device->EventBegin("Update Depth", cmd); + + device->BindComputeShader(&shaders[CSTYPE_DDGI_UPDATE_DEPTH], cmd); + device->PushConstants(&push, sizeof(push), cmd); + + const GPUResource* res[] = { + &scene.ddgiRayBuffer, + }; + device->BindResources(res, 0, arraysize(res), cmd); + + const GPUResource* uavs[] = { + &scene.ddgiDepthTexture[1], + }; + device->BindUAVs(uavs, 0, arraysize(uavs), cmd); + + device->Dispatch(DDGI_PROBE_COUNT, 1, 1, cmd); + + device->EventEnd(cmd); + } + + { + GPUBarrier barriers[] = { + GPUBarrier::Image(&scene.ddgiColorTexture[1], ResourceState::UNORDERED_ACCESS, ResourceState::SHADER_RESOURCE_COMPUTE), + GPUBarrier::Image(&scene.ddgiDepthTexture[1], ResourceState::UNORDERED_ACCESS, ResourceState::SHADER_RESOURCE_COMPUTE), + }; + device->Barrier(barriers, arraysize(barriers), cmd); + } + + wi::profiler::EndRange(prof_range); + device->EventEnd(cmd); +} + void Postprocess_Blur_Gaussian( const Texture& input, const Texture& temp, @@ -11829,14 +11980,6 @@ bool GetSurfelGIEnabled() { return SURFELGI; } -void SetSurfelGIBoost(float value) -{ - SURFELGI_BOOST = value; -} -float GetSurfelGIBoost() -{ - return SURFELGI_BOOST; -} void SetSurfelGIDebugEnabled(SURFEL_DEBUG value) { SURFELGI_DEBUG = value; @@ -11845,5 +11988,37 @@ SURFEL_DEBUG GetSurfelGIDebugEnabled() { return SURFELGI_DEBUG; } +void SetDDGIEnabled(bool value) +{ + DDGI_ENABLED = value; +} +bool GetDDGIEnabled() +{ + return DDGI_ENABLED; +} +void SetDDGIDebugEnabled(bool value) +{ + DDGI_DEBUG_ENABLED = value; +} +bool GetDDGIDebugEnabled() +{ + return DDGI_DEBUG_ENABLED; +} +void SetDDGIRayCount(uint32_t value) +{ + DDGI_RAYCOUNT = value; +} +uint32_t GetDDGIRayCount() +{ + return DDGI_RAYCOUNT; +} +void SetGIBoost(float value) +{ + GI_BOOST = value; +} +float GetGIBoost() +{ + return GI_BOOST; +} } diff --git a/WickedEngine/wiRenderer.h b/WickedEngine/wiRenderer.h index 4fc465364..b0a14c69e 100644 --- a/WickedEngine/wiRenderer.h +++ b/WickedEngine/wiRenderer.h @@ -342,6 +342,12 @@ namespace wi::renderer uint8_t instanceInclusionMask = 0xFF ); + void DDGI( + const wi::scene::Scene& scene, + wi::graphics::CommandList cmd, + uint8_t instanceInclusionMask = 0xFF + ); + void Postprocess_Blur_Gaussian( const wi::graphics::Texture& input, const wi::graphics::Texture& temp, @@ -770,10 +776,16 @@ namespace wi::renderer bool GetScreenSpaceShadowsEnabled(); void SetSurfelGIEnabled(bool value); bool GetSurfelGIEnabled(); - void SetSurfelGIBoost(float value); - float GetSurfelGIBoost(); void SetSurfelGIDebugEnabled(SURFEL_DEBUG value); SURFEL_DEBUG GetSurfelGIDebugEnabled(); + void SetDDGIEnabled(bool value); + bool GetDDGIEnabled(); + void SetDDGIDebugEnabled(bool value); + bool GetDDGIDebugEnabled(); + void SetDDGIRayCount(uint32_t value); + uint32_t GetDDGIRayCount(); + void SetGIBoost(float value); + float GetGIBoost(); // Gets pick ray according to the current screen resolution and pointer coordinates. Can be used as input into RayIntersectWorld() wi::primitive::Ray GetPickRay(long cursorX, long cursorY, const wi::Canvas& canvas, const wi::scene::CameraComponent& camera = wi::scene::GetCamera()); diff --git a/WickedEngine/wiScene.cpp b/WickedEngine/wiScene.cpp index 99912de9e..b4dd58cef 100644 --- a/WickedEngine/wiScene.cpp +++ b/WickedEngine/wiScene.cpp @@ -13,6 +13,7 @@ #include "wiUnorderedMap.h" #include "shaders/ShaderInterop_SurfelGI.h" +#include "shaders/ShaderInterop_DDGI.h" using namespace wi::ecs; using namespace wi::enums; @@ -1761,6 +1762,51 @@ namespace wi::scene std::swap(surfelMomentsTexture[0], surfelMomentsTexture[1]); } + if (wi::renderer::GetDDGIEnabled()) + { + ddgi_frameIndex++; + if (!ddgiColorTexture[0].IsValid()) + { + ddgi_frameIndex = 0; + + GPUBufferDesc buf; + buf.stride = sizeof(DDGIRayDataPacked); + buf.size = buf.stride * DDGI_PROBE_COUNT * DDGI_MAX_RAYCOUNT; + buf.bind_flags = BindFlag::UNORDERED_ACCESS | BindFlag::SHADER_RESOURCE; + buf.misc_flags = ResourceMiscFlag::BUFFER_STRUCTURED; + device->CreateBuffer(&buf, nullptr, &ddgiRayBuffer); + device->SetName(&ddgiRayBuffer, "ddgiRayBuffer"); + + TextureDesc tex; + tex.width = DDGI_COLOR_TEXTURE_WIDTH; + tex.height = DDGI_COLOR_TEXTURE_HEIGHT; + //tex.format = Format::R11G11B10_FLOAT; // not enough precision with this format, causes green hue in GI + tex.format = Format::R16G16B16A16_FLOAT; + tex.bind_flags = BindFlag::UNORDERED_ACCESS | BindFlag::SHADER_RESOURCE; + device->CreateTexture(&tex, nullptr, &ddgiColorTexture[0]); + device->SetName(&ddgiColorTexture[0], "ddgiColorTexture[0]"); + device->CreateTexture(&tex, nullptr, &ddgiColorTexture[1]); + device->SetName(&ddgiColorTexture[1], "ddgiColorTexture[1]"); + + tex.width = DDGI_DEPTH_TEXTURE_WIDTH; + tex.height = DDGI_DEPTH_TEXTURE_HEIGHT; + tex.format = Format::R16G16_FLOAT; + tex.bind_flags = BindFlag::UNORDERED_ACCESS | BindFlag::SHADER_RESOURCE; + device->CreateTexture(&tex, nullptr, &ddgiDepthTexture[0]); + device->SetName(&ddgiDepthTexture[0], "ddgiDepthTexture[0]"); + device->CreateTexture(&tex, nullptr, &ddgiDepthTexture[1]); + device->SetName(&ddgiDepthTexture[1], "ddgiDepthTexture[1]"); + } + std::swap(ddgiColorTexture[0], ddgiColorTexture[1]); + std::swap(ddgiDepthTexture[0], ddgiDepthTexture[1]); + } + else if (ddgiColorTexture[0].IsValid()) + { + ddgiColorTexture[0] = {}; + ddgiColorTexture[1] = {}; + ddgiDepthTexture[0] = {}; + ddgiDepthTexture[1] = {}; + } // Shader scene resources: shaderscene.instancebuffer = device->GetDescriptorIndex(&instanceBuffer, SubresourceType::SRV); @@ -1810,6 +1856,26 @@ namespace wi::scene shaderscene.weather.wind.direction = weather.windDirection; shaderscene.weather.atmosphere = weather.atmosphereParameters; shaderscene.weather.volumetric_clouds = weather.volumetricCloudParameters; + + shaderscene.ddgi.color_texture = device->GetDescriptorIndex(&ddgiColorTexture[0], SubresourceType::SRV); + shaderscene.ddgi.depth_texture = device->GetDescriptorIndex(&ddgiDepthTexture[0], SubresourceType::SRV); + shaderscene.ddgi.grid_min.x = shaderscene.aabb_min.x - 1; + shaderscene.ddgi.grid_min.y = shaderscene.aabb_min.y - 1; + shaderscene.ddgi.grid_min.z = shaderscene.aabb_min.z - 1; + float3 grid_max = shaderscene.aabb_max; + grid_max.x += 1; + grid_max.y += 1; + grid_max.z += 1; + shaderscene.ddgi.grid_extents.x = abs(grid_max.x - shaderscene.ddgi.grid_min.x); + shaderscene.ddgi.grid_extents.y = abs(grid_max.y - shaderscene.ddgi.grid_min.y); + shaderscene.ddgi.grid_extents.z = abs(grid_max.z - shaderscene.ddgi.grid_min.z); + shaderscene.ddgi.grid_extents_rcp.x = 1.0f / shaderscene.ddgi.grid_extents.x; + shaderscene.ddgi.grid_extents_rcp.y = 1.0f / shaderscene.ddgi.grid_extents.y; + shaderscene.ddgi.grid_extents_rcp.z = 1.0f / shaderscene.ddgi.grid_extents.z; + shaderscene.ddgi.cell_size.x = shaderscene.ddgi.grid_extents.x / (DDGI_GRID_DIMENSIONS.x - 1); + shaderscene.ddgi.cell_size.y = shaderscene.ddgi.grid_extents.y / (DDGI_GRID_DIMENSIONS.y - 1); + shaderscene.ddgi.cell_size.z = shaderscene.ddgi.grid_extents.z / (DDGI_GRID_DIMENSIONS.z - 1); + shaderscene.ddgi.max_distance = std::max(shaderscene.ddgi.cell_size.x, std::max(shaderscene.ddgi.cell_size.y, shaderscene.ddgi.cell_size.z)) * 1.5f; } void Scene::Clear() { diff --git a/WickedEngine/wiScene.h b/WickedEngine/wiScene.h index 7eb5188be..9f097ba70 100644 --- a/WickedEngine/wiScene.h +++ b/WickedEngine/wiScene.h @@ -1333,6 +1333,11 @@ namespace wi::scene wi::graphics::GPUBuffer surfelCellBuffer; wi::graphics::Texture surfelMomentsTexture[2]; + // DDGI resources: + uint ddgi_frameIndex = 0; + wi::graphics::GPUBuffer ddgiRayBuffer; + wi::graphics::Texture ddgiColorTexture[2]; + wi::graphics::Texture ddgiDepthTexture[2]; // Environment probe cubemap array state: static constexpr uint32_t envmapCount = 16; diff --git a/WickedEngine/wiVersion.cpp b/WickedEngine/wiVersion.cpp index a560fe2ed..e1c7e12fe 100644 --- a/WickedEngine/wiVersion.cpp +++ b/WickedEngine/wiVersion.cpp @@ -9,7 +9,7 @@ namespace wi::version // minor features, major updates, breaking compatibility changes const int minor = 60; // minor bug fixes, alterations, refactors, updates - const int revision = 18; + const int revision = 19; const std::string version_string = std::to_string(major) + "." + std::to_string(minor) + "." + std::to_string(revision); diff --git a/features.txt b/features.txt index 61c6efcb0..dde7783cb 100644 --- a/features.txt +++ b/features.txt @@ -83,6 +83,7 @@ Screen Space Contact Shadows Stochastic alphatest transparency Surfel GI HDR display output +Dynamic Diffuse Global Illumination (DDGI) GLTF 2.0 extensions supported: KHR_materials_unlit