DDGI (#386)
* start ddgi implementation * update * updates * update * ray data packing * removed comment * update * features.txt * ddgi disabled by default * added comments * comments * offlineshadercompiler * updates
This commit is contained in:
@@ -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.");
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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<size_t>(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<size_t>(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<size_t>(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;
|
||||
|
||||
@@ -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
|
||||
@@ -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;
|
||||
};
|
||||
|
||||
@@ -481,6 +481,28 @@
|
||||
<ShaderType Condition="'$(Configuration)|$(Platform)'=='Release|ARM'">Vertex</ShaderType>
|
||||
<ShaderType Condition="'$(Configuration)|$(Platform)'=='Debug|ARM'">Vertex</ShaderType>
|
||||
</FxCompile>
|
||||
<FxCompile Include="$(MSBuildThisFileDirectory)ddgi_debugPS.hlsl">
|
||||
<ShaderType Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">Pixel</ShaderType>
|
||||
</FxCompile>
|
||||
<FxCompile Include="$(MSBuildThisFileDirectory)ddgi_debugVS.hlsl">
|
||||
<ShaderType Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">Vertex</ShaderType>
|
||||
</FxCompile>
|
||||
<FxCompile Include="$(MSBuildThisFileDirectory)ddgi_raytraceCS.hlsl">
|
||||
<ShaderType Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">Compute</ShaderType>
|
||||
<ShaderModel Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">4.0</ShaderModel>
|
||||
</FxCompile>
|
||||
<FxCompile Include="$(MSBuildThisFileDirectory)ddgi_raytraceCS_rtapi.hlsl">
|
||||
<ShaderType Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">Compute</ShaderType>
|
||||
<ShaderModel Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">4.0</ShaderModel>
|
||||
</FxCompile>
|
||||
<FxCompile Include="$(MSBuildThisFileDirectory)ddgi_updateCS.hlsl">
|
||||
<ShaderType Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">Compute</ShaderType>
|
||||
<ShaderModel Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">4.0</ShaderModel>
|
||||
</FxCompile>
|
||||
<FxCompile Include="$(MSBuildThisFileDirectory)ddgi_updateCS_depth.hlsl">
|
||||
<ShaderType Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">Compute</ShaderType>
|
||||
<ShaderModel Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">4.0</ShaderModel>
|
||||
</FxCompile>
|
||||
<FxCompile Include="$(MSBuildThisFileDirectory)occludeeVS.hlsl">
|
||||
<ShaderType Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">Vertex</ShaderType>
|
||||
<ShaderType Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">Vertex</ShaderType>
|
||||
@@ -2809,6 +2831,7 @@
|
||||
<ItemGroup>
|
||||
<ClInclude Include="$(MSBuildThisFileDirectory)ShaderInterop.h" />
|
||||
<ClInclude Include="$(MSBuildThisFileDirectory)ShaderInterop_BVH.h" />
|
||||
<ClInclude Include="$(MSBuildThisFileDirectory)ShaderInterop_DDGI.h" />
|
||||
<ClInclude Include="$(MSBuildThisFileDirectory)ShaderInterop_EmittedParticle.h" />
|
||||
<ClInclude Include="$(MSBuildThisFileDirectory)ShaderInterop_FFTGenerator.h" />
|
||||
<ClInclude Include="$(MSBuildThisFileDirectory)ShaderInterop_Font.h" />
|
||||
|
||||
@@ -1004,6 +1004,24 @@
|
||||
<FxCompile Include="$(MSBuildThisFileDirectory)rtreflectionCS.hlsl">
|
||||
<Filter>CS</Filter>
|
||||
</FxCompile>
|
||||
<FxCompile Include="$(MSBuildThisFileDirectory)ddgi_debugVS.hlsl">
|
||||
<Filter>VS</Filter>
|
||||
</FxCompile>
|
||||
<FxCompile Include="$(MSBuildThisFileDirectory)ddgi_debugPS.hlsl">
|
||||
<Filter>PS</Filter>
|
||||
</FxCompile>
|
||||
<FxCompile Include="$(MSBuildThisFileDirectory)ddgi_raytraceCS.hlsl">
|
||||
<Filter>CS</Filter>
|
||||
</FxCompile>
|
||||
<FxCompile Include="$(MSBuildThisFileDirectory)ddgi_raytraceCS_rtapi.hlsl">
|
||||
<Filter>CS</Filter>
|
||||
</FxCompile>
|
||||
<FxCompile Include="$(MSBuildThisFileDirectory)ddgi_updateCS.hlsl">
|
||||
<Filter>CS</Filter>
|
||||
</FxCompile>
|
||||
<FxCompile Include="$(MSBuildThisFileDirectory)ddgi_updateCS_depth.hlsl">
|
||||
<Filter>CS</Filter>
|
||||
</FxCompile>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ClInclude Include="$(MSBuildThisFileDirectory)ShaderInterop.h">
|
||||
@@ -1048,5 +1066,8 @@
|
||||
<ClInclude Include="$(MSBuildThisFileDirectory)ShaderInterop_Weather.h">
|
||||
<Filter>interop</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="$(MSBuildThisFileDirectory)ShaderInterop_DDGI.h">
|
||||
<Filter>interop</Filter>
|
||||
</ClInclude>
|
||||
</ItemGroup>
|
||||
</Project>
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
@@ -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<DDGIRayDataPacked> 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);
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,2 @@
|
||||
#define RTAPI
|
||||
#include "ddgi_raytraceCS.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<DDGIRayDataPacked> 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<float2> output : register(u0);
|
||||
#else
|
||||
static const uint THREADCOUNT = DDGI_COLOR_RESOLUTION;
|
||||
RWTexture2D<float3> 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
|
||||
}
|
||||
@@ -0,0 +1,2 @@
|
||||
#define DDGI_UPDATE_DEPTH
|
||||
#include "ddgi_updateCS.hlsl"
|
||||
@@ -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
|
||||
|
||||
|
||||
|
||||
@@ -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;
|
||||
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
|
||||
|
||||
@@ -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;
|
||||
|
||||
|
||||
@@ -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:
|
||||
|
||||
@@ -40,4 +40,14 @@ namespace wi::random
|
||||
{
|
||||
return GetRandom(0ull, maxValue);
|
||||
}
|
||||
|
||||
float GetRandom(float minValue, float maxValue)
|
||||
{
|
||||
std::uniform_real_distribution<float> distr(minValue, maxValue);
|
||||
return distr(generator());
|
||||
}
|
||||
float GetRandom(float maxValue)
|
||||
{
|
||||
return GetRandom(0.0f, maxValue);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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);
|
||||
};
|
||||
|
||||
|
||||
@@ -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 =
|
||||
|
||||
@@ -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]; }
|
||||
|
||||
+185
-10
@@ -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 <algorithm>
|
||||
#include <array>
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -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());
|
||||
|
||||
@@ -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()
|
||||
{
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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);
|
||||
|
||||
|
||||
@@ -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
|
||||
|
||||
Reference in New Issue
Block a user