added screen space contact shadows
This commit is contained in:
@@ -11,7 +11,7 @@ using namespace wiGraphics;
|
||||
void PostprocessWindow::Create(EditorComponent* editor)
|
||||
{
|
||||
wiWindow::Create("PostProcess Window");
|
||||
SetSize(XMFLOAT2(420, 500));
|
||||
SetSize(XMFLOAT2(420, 520));
|
||||
|
||||
float x = 150;
|
||||
float y = 10;
|
||||
@@ -156,6 +156,36 @@ void PostprocessWindow::Create(EditorComponent* editor)
|
||||
AddWidget(&raytracedReflectionsCheckBox);
|
||||
raytracedReflectionsCheckBox.SetEnabled(wiRenderer::GetDevice()->CheckCapability(GRAPHICSDEVICE_CAPABILITY_RAYTRACING));
|
||||
|
||||
screenSpaceShadowsCheckBox.Create("SS Shadows: ");
|
||||
screenSpaceShadowsCheckBox.SetTooltip("Enable screen space contact shadows. This can add small shadows details to shadow maps in screen space.");
|
||||
screenSpaceShadowsCheckBox.SetSize(XMFLOAT2(hei, hei));
|
||||
screenSpaceShadowsCheckBox.SetPos(XMFLOAT2(x, y += step));
|
||||
screenSpaceShadowsCheckBox.SetCheck(wiRenderer::GetScreenSpaceShadowsEnabled());
|
||||
screenSpaceShadowsCheckBox.OnClick([=](wiEventArgs args) {
|
||||
wiRenderer::SetScreenSpaceShadowsEnabled(args.bValue);
|
||||
});
|
||||
AddWidget(&screenSpaceShadowsCheckBox);
|
||||
|
||||
screenSpaceShadowsRangeSlider.Create(0.1f, 10.0f, 1, 1000, "Range: ");
|
||||
screenSpaceShadowsRangeSlider.SetTooltip("Range of contact shadows");
|
||||
screenSpaceShadowsRangeSlider.SetSize(XMFLOAT2(100, hei));
|
||||
screenSpaceShadowsRangeSlider.SetPos(XMFLOAT2(x + 100, y));
|
||||
screenSpaceShadowsRangeSlider.SetValue((float)editor->renderPath->getScreenSpaceShadowRange());
|
||||
screenSpaceShadowsRangeSlider.OnSlide([=](wiEventArgs args) {
|
||||
editor->renderPath->setScreenSpaceShadowRange(args.fValue);
|
||||
});
|
||||
AddWidget(&screenSpaceShadowsRangeSlider);
|
||||
|
||||
screenSpaceShadowsStepCountSlider.Create(4, 128, 16, 128 - 4, "Sample Count: ");
|
||||
screenSpaceShadowsStepCountSlider.SetTooltip("Sample count of contact shadows. Higher values are better quality but slower.");
|
||||
screenSpaceShadowsStepCountSlider.SetSize(XMFLOAT2(100, hei));
|
||||
screenSpaceShadowsStepCountSlider.SetPos(XMFLOAT2(x + 100, y += step));
|
||||
screenSpaceShadowsStepCountSlider.SetValue((float)editor->renderPath->getScreenSpaceShadowSampleCount());
|
||||
screenSpaceShadowsStepCountSlider.OnSlide([=](wiEventArgs args) {
|
||||
editor->renderPath->setScreenSpaceShadowSampleCount(args.iValue);
|
||||
});
|
||||
AddWidget(&screenSpaceShadowsStepCountSlider);
|
||||
|
||||
eyeAdaptionCheckBox.Create("EyeAdaption: ");
|
||||
eyeAdaptionCheckBox.SetTooltip("Enable eye adaption for the overall screen luminance");
|
||||
eyeAdaptionCheckBox.SetSize(XMFLOAT2(hei, hei));
|
||||
|
||||
@@ -18,6 +18,9 @@ public:
|
||||
wiSlider aoSampleCountSlider;
|
||||
wiCheckBox ssrCheckBox;
|
||||
wiCheckBox raytracedReflectionsCheckBox;
|
||||
wiCheckBox screenSpaceShadowsCheckBox;
|
||||
wiSlider screenSpaceShadowsStepCountSlider;
|
||||
wiSlider screenSpaceShadowsRangeSlider;
|
||||
wiCheckBox eyeAdaptionCheckBox;
|
||||
wiCheckBox motionBlurCheckBox;
|
||||
wiSlider motionBlurStrengthSlider;
|
||||
|
||||
@@ -151,7 +151,6 @@ void RenderPath3D::ResizeBuffers()
|
||||
device->CreateTexture(&desc, nullptr, &rtAO);
|
||||
device->SetName(&rtAO, "rtAO");
|
||||
}
|
||||
if (device->CheckCapability(GRAPHICSDEVICE_CAPABILITY_RAYTRACING))
|
||||
{
|
||||
TextureDesc desc;
|
||||
desc.BindFlags = BIND_SHADER_RESOURCE | BIND_UNORDERED_ACCESS;
|
||||
@@ -844,6 +843,19 @@ void RenderPath3D::Render() const
|
||||
|
||||
RenderSSR(cmd);
|
||||
|
||||
if (wiRenderer::GetScreenSpaceShadowsEnabled())
|
||||
{
|
||||
wiRenderer::Postprocess_ScreenSpaceShadow(
|
||||
depthBuffer_Copy,
|
||||
rtLinearDepth,
|
||||
entityTiles_Opaque,
|
||||
rtShadow,
|
||||
cmd,
|
||||
getScreenSpaceShadowRange(),
|
||||
getScreenSpaceShadowSampleCount()
|
||||
);
|
||||
}
|
||||
|
||||
if (wiRenderer::GetRaytracedShadowsEnabled())
|
||||
{
|
||||
wiRenderer::Postprocess_RTShadow(
|
||||
@@ -857,6 +869,7 @@ void RenderPath3D::Render() const
|
||||
cmd
|
||||
);
|
||||
}
|
||||
|
||||
});
|
||||
|
||||
// Opaque scene:
|
||||
@@ -875,7 +888,7 @@ void RenderPath3D::Render() const
|
||||
vp.Height = (float)depthBuffer_Main.GetDesc().Height;
|
||||
device->BindViewports(1, &vp, cmd);
|
||||
|
||||
if (wiRenderer::GetRaytracedShadowsEnabled())
|
||||
if (wiRenderer::GetRaytracedShadowsEnabled() || wiRenderer::GetScreenSpaceShadowsEnabled())
|
||||
{
|
||||
device->BindResource(PS, &rtShadow, TEXSLOT_RENDERPATH_RTSHADOW, cmd);
|
||||
}
|
||||
|
||||
@@ -35,6 +35,8 @@ private:
|
||||
uint32_t aoSampleCount = 16;
|
||||
float aoPower = 2.0f;
|
||||
float chromaticAberrationAmount = 2.0f;
|
||||
uint32_t screenSpaceShadowSampleCount = 16;
|
||||
float screenSpaceShadowRange = 1;
|
||||
|
||||
AO ao = AO_DISABLED;
|
||||
bool fxaaEnabled = false;
|
||||
@@ -179,6 +181,8 @@ public:
|
||||
constexpr uint32_t getAOSampleCount() const { return aoSampleCount; }
|
||||
constexpr float getAOPower() const { return aoPower; }
|
||||
constexpr float getChromaticAberrationAmount() const { return chromaticAberrationAmount; }
|
||||
constexpr uint32_t getScreenSpaceShadowSampleCount() const { return screenSpaceShadowSampleCount; }
|
||||
constexpr float getScreenSpaceShadowRange() const { return screenSpaceShadowRange; }
|
||||
|
||||
constexpr bool getAOEnabled() const { return ao != AO_DISABLED; }
|
||||
constexpr AO getAO() const { return ao; }
|
||||
@@ -219,6 +223,8 @@ public:
|
||||
constexpr void setAOSampleCount(uint32_t value) { aoSampleCount = value; }
|
||||
constexpr void setAOPower(float value) { aoPower = value; }
|
||||
constexpr void setChromaticAberrationAmount(float value) { chromaticAberrationAmount = value; }
|
||||
constexpr void setScreenSpaceShadowSampleCount(uint32_t value) { screenSpaceShadowSampleCount = value; }
|
||||
constexpr void setScreenSpaceShadowRange(float value) { screenSpaceShadowRange = value; }
|
||||
|
||||
constexpr void setAO(AO value) { ao = value; }
|
||||
constexpr void setSSREnabled(bool value){ ssrEnabled = value; }
|
||||
|
||||
@@ -234,6 +234,7 @@ static const uint OPTION_BIT_SIMPLE_SKY = 1 << 5;
|
||||
static const uint OPTION_BIT_REALISTIC_SKY = 1 << 6;
|
||||
static const uint OPTION_BIT_RAYTRACED_SHADOWS = 1 << 7;
|
||||
static const uint OPTION_BIT_DISABLE_ALBEDO_MAPS = 1 << 8;
|
||||
static const uint OPTION_BIT_SHADOW_MASK = 1 << 9;
|
||||
|
||||
// ---------- Common Constant buffers: -----------------
|
||||
|
||||
|
||||
@@ -869,6 +869,16 @@
|
||||
<ShaderType Condition="'$(Configuration)|$(Platform)'=='Release|ARM'">Compute</ShaderType>
|
||||
<ShaderType Condition="'$(Configuration)|$(Platform)'=='Debug|ARM'">Compute</ShaderType>
|
||||
</FxCompile>
|
||||
<FxCompile Include="$(MSBuildThisFileDirectory)screenspaceshadowCS.hlsl">
|
||||
<ShaderType Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">Compute</ShaderType>
|
||||
<ShaderType Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">Compute</ShaderType>
|
||||
<ShaderType Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">Compute</ShaderType>
|
||||
<ShaderType Condition="'$(Configuration)|$(Platform)'=='Release|ARM64'">Compute</ShaderType>
|
||||
<ShaderType Condition="'$(Configuration)|$(Platform)'=='Debug|ARM64'">Compute</ShaderType>
|
||||
<ShaderType Condition="'$(Configuration)|$(Platform)'=='Release|x64'">Compute</ShaderType>
|
||||
<ShaderType Condition="'$(Configuration)|$(Platform)'=='Release|ARM'">Compute</ShaderType>
|
||||
<ShaderType Condition="'$(Configuration)|$(Platform)'=='Debug|ARM'">Compute</ShaderType>
|
||||
</FxCompile>
|
||||
<FxCompile Include="$(MSBuildThisFileDirectory)skyPS_velocity.hlsl">
|
||||
<ShaderType Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">Pixel</ShaderType>
|
||||
<ShaderType Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">Pixel</ShaderType>
|
||||
|
||||
@@ -956,5 +956,8 @@
|
||||
<FxCompile Include="$(MSBuildThisFileDirectory)objectDS_prepass_alphatest.hlsl">
|
||||
<Filter>DS</Filter>
|
||||
</FxCompile>
|
||||
<FxCompile Include="$(MSBuildThisFileDirectory)screenspaceshadowCS.hlsl">
|
||||
<Filter>CS</Filter>
|
||||
</FxCompile>
|
||||
</ItemGroup>
|
||||
</Project>
|
||||
@@ -1,6 +1,6 @@
|
||||
#define DISABLE_DECALS
|
||||
#define DISABLE_ENVMAPS
|
||||
#define RAYTRACED_SHADOWS_ENABLED
|
||||
#define SHADOW_MASK_ENABLED
|
||||
#include "globals.hlsli"
|
||||
#include "objectHF.hlsli"
|
||||
#include "hairparticleHF.hlsli"
|
||||
@@ -30,13 +30,13 @@ GBuffer main(VertexToPixel input)
|
||||
Lighting lighting;
|
||||
lighting.create(0, 0, GetAmbient(surface.N), 0);
|
||||
|
||||
#ifdef RAYTRACED_SHADOWS_ENABLED
|
||||
#ifdef SHADOW_MASK_ENABLED
|
||||
[branch]
|
||||
if (g_xFrame_Options & OPTION_BIT_RAYTRACED_SHADOWS)
|
||||
{
|
||||
lighting.shadow_mask = texture_rtshadow[surface.pixel];
|
||||
}
|
||||
#endif // RAYTRACED_SHADOWS_ENABLED
|
||||
#endif // SHADOW_MASK_ENABLED
|
||||
|
||||
float depth = input.pos.z;
|
||||
float3 reflection = 0;
|
||||
|
||||
@@ -186,21 +186,12 @@ inline void DirectionalLight(in ShaderEntity light, in Surface surface, inout Li
|
||||
[branch]
|
||||
if (light.IsCastingShadow())
|
||||
{
|
||||
#ifdef RAYTRACED_SHADOWS_ENABLED
|
||||
[branch]
|
||||
if (g_xFrame_Options & OPTION_BIT_RAYTRACED_SHADOWS)
|
||||
{
|
||||
#ifdef RAYTRACING_INLINE
|
||||
shadow *= shadowTrace(surface, normalize(L), FLT_MAX);
|
||||
#else
|
||||
uint mask_shift = (lighting.shadow_index % 4) * 8;
|
||||
uint mask_bucket = lighting.shadow_index / 4;
|
||||
uint mask = (lighting.shadow_mask[mask_bucket] >> mask_shift) & 0xFF;
|
||||
shadow = mask / 255.0;
|
||||
#endif // RAYTRACING_INLINE
|
||||
}
|
||||
else
|
||||
#endif // RAYTRACED_SHADOWS_ENABLED
|
||||
{
|
||||
// Loop through cascades from closest (smallest) to furthest (biggest)
|
||||
[loop]
|
||||
@@ -238,6 +229,17 @@ inline void DirectionalLight(in ShaderEntity light, in Surface surface, inout Li
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#ifdef SHADOW_MASK_ENABLED
|
||||
[branch]
|
||||
if (g_xFrame_Options & OPTION_BIT_SHADOW_MASK)
|
||||
{
|
||||
uint mask_shift = (lighting.shadow_index % 4) * 8;
|
||||
uint mask_bucket = lighting.shadow_index / 4;
|
||||
uint mask = (lighting.shadow_mask[mask_bucket] >> mask_shift) & 0xFF;
|
||||
shadow *= mask / 255.0;
|
||||
}
|
||||
#endif // SHADOW_MASK_ENABLED
|
||||
}
|
||||
|
||||
[branch]
|
||||
@@ -260,7 +262,7 @@ inline void DirectionalLight(in ShaderEntity light, in Surface surface, inout Li
|
||||
}
|
||||
}
|
||||
|
||||
#ifdef RAYTRACED_SHADOWS_ENABLED
|
||||
#ifdef SHADOW_MASK_ENABLED
|
||||
#ifndef RAYTRACING_INLINE
|
||||
[branch]
|
||||
if (light.IsCastingShadow())
|
||||
@@ -274,7 +276,7 @@ inline void DirectionalLight(in ShaderEntity light, in Surface surface, inout Li
|
||||
lighting.shadow_index++;
|
||||
}
|
||||
#endif // RAYTRACING_INLINE
|
||||
#endif // RAYTRACED_SHADOWS_ENABLED
|
||||
#endif // SHADOW_MASK_ENABLED
|
||||
}
|
||||
inline void PointLight(in ShaderEntity light, in Surface surface, inout Lighting lighting)
|
||||
{
|
||||
@@ -300,24 +302,26 @@ inline void PointLight(in ShaderEntity light, in Surface surface, inout Lighting
|
||||
[branch]
|
||||
if (light.IsCastingShadow())
|
||||
{
|
||||
#ifdef RAYTRACED_SHADOWS_ENABLED
|
||||
[branch]
|
||||
if (g_xFrame_Options & OPTION_BIT_RAYTRACED_SHADOWS)
|
||||
{
|
||||
#ifdef RAYTRACING_INLINE
|
||||
shadow *= shadowTrace(surface, L, dist);
|
||||
#else
|
||||
uint mask_shift = (lighting.shadow_index % 4) * 8;
|
||||
uint mask_bucket = lighting.shadow_index / 4;
|
||||
uint mask = (lighting.shadow_mask[mask_bucket] >> mask_shift) & 0xFF;
|
||||
shadow = mask / 255.0;
|
||||
#endif // RAYTRACING_INLINE
|
||||
}
|
||||
else
|
||||
#endif // RAYTRACED_SHADOWS_ENABLED
|
||||
{
|
||||
shadow *= shadowCube(light, L, Lunnormalized);
|
||||
}
|
||||
|
||||
#ifdef SHADOW_MASK_ENABLED
|
||||
[branch]
|
||||
if (g_xFrame_Options & OPTION_BIT_SHADOW_MASK)
|
||||
{
|
||||
uint mask_shift = (lighting.shadow_index % 4) * 8;
|
||||
uint mask_bucket = lighting.shadow_index / 4;
|
||||
uint mask = (lighting.shadow_mask[mask_bucket] >> mask_shift) & 0xFF;
|
||||
shadow *= mask / 255.0;
|
||||
}
|
||||
#endif // SHADOW_MASK_ENABLED
|
||||
}
|
||||
|
||||
[branch]
|
||||
@@ -338,7 +342,7 @@ inline void PointLight(in ShaderEntity light, in Surface surface, inout Lighting
|
||||
}
|
||||
}
|
||||
|
||||
#ifdef RAYTRACED_SHADOWS_ENABLED
|
||||
#ifdef SHADOW_MASK_ENABLED
|
||||
#ifndef RAYTRACING_INLINE
|
||||
[branch]
|
||||
if (light.IsCastingShadow())
|
||||
@@ -352,7 +356,7 @@ inline void PointLight(in ShaderEntity light, in Surface surface, inout Lighting
|
||||
lighting.shadow_index++;
|
||||
}
|
||||
#endif // RAYTRACING_INLINE
|
||||
#endif // RAYTRACED_SHADOWS_ENABLED
|
||||
#endif // SHADOW_MASK_ENABLED
|
||||
}
|
||||
inline void SpotLight(in ShaderEntity light, in Surface surface, inout Lighting lighting)
|
||||
{
|
||||
@@ -383,21 +387,12 @@ inline void SpotLight(in ShaderEntity light, in Surface surface, inout Lighting
|
||||
[branch]
|
||||
if (light.IsCastingShadow())
|
||||
{
|
||||
#ifdef RAYTRACED_SHADOWS_ENABLED
|
||||
[branch]
|
||||
if (g_xFrame_Options & OPTION_BIT_RAYTRACED_SHADOWS)
|
||||
{
|
||||
#ifdef RAYTRACING_INLINE
|
||||
shadow *= shadowTrace(surface, L, dist);
|
||||
#else
|
||||
uint mask_shift = (lighting.shadow_index % 4) * 8;
|
||||
uint mask_bucket = lighting.shadow_index / 4;
|
||||
uint mask = (lighting.shadow_mask[mask_bucket] >> mask_shift) & 0xFF;
|
||||
shadow = mask / 255.0;
|
||||
#endif // RAYTRACING_INLINE
|
||||
}
|
||||
else
|
||||
#endif // RAYTRACED_SHADOWS_ENABLED
|
||||
{
|
||||
float4 ShPos = mul(MatrixArray[light.GetMatrixIndex() + 0], float4(surface.P, 1));
|
||||
ShPos.xyz /= ShPos.w;
|
||||
@@ -408,6 +403,17 @@ inline void SpotLight(in ShaderEntity light, in Surface surface, inout Lighting
|
||||
shadow *= shadowCascade(light, ShPos.xyz, ShTex.xy, 0);
|
||||
}
|
||||
}
|
||||
|
||||
#ifdef SHADOW_MASK_ENABLED
|
||||
[branch]
|
||||
if (g_xFrame_Options & OPTION_BIT_SHADOW_MASK)
|
||||
{
|
||||
uint mask_shift = (lighting.shadow_index % 4) * 8;
|
||||
uint mask_bucket = lighting.shadow_index / 4;
|
||||
uint mask = (lighting.shadow_mask[mask_bucket] >> mask_shift) & 0xFF;
|
||||
shadow *= mask / 255.0;
|
||||
}
|
||||
#endif // SHADOW_MASK_ENABLED
|
||||
}
|
||||
|
||||
[branch]
|
||||
@@ -430,7 +436,7 @@ inline void SpotLight(in ShaderEntity light, in Surface surface, inout Lighting
|
||||
}
|
||||
}
|
||||
|
||||
#ifdef RAYTRACED_SHADOWS_ENABLED
|
||||
#ifdef SHADOW_MASK_ENABLED
|
||||
#ifndef RAYTRACING_INLINE
|
||||
[branch]
|
||||
if (light.IsCastingShadow())
|
||||
@@ -444,7 +450,7 @@ inline void SpotLight(in ShaderEntity light, in Surface surface, inout Lighting
|
||||
lighting.shadow_index++;
|
||||
}
|
||||
#endif // RAYTRACING_INLINE
|
||||
#endif // RAYTRACED_SHADOWS_ENABLED
|
||||
#endif // SHADOW_MASK_ENABLED
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -1486,13 +1486,13 @@ float4 main(PixelInput input) : SV_TARGET
|
||||
#endif
|
||||
|
||||
|
||||
#ifdef RAYTRACED_SHADOWS_ENABLED
|
||||
#ifdef SHADOW_MASK_ENABLED
|
||||
[branch]
|
||||
if (g_xFrame_Options & OPTION_BIT_RAYTRACED_SHADOWS)
|
||||
if (g_xFrame_Options & OPTION_BIT_SHADOW_MASK)
|
||||
{
|
||||
lighting.shadow_mask = texture_rtshadow[surface.pixel];
|
||||
}
|
||||
#endif // RAYTRACED_SHADOWS_ENABLED
|
||||
#endif // SHADOW_MASK_ENABLED
|
||||
|
||||
|
||||
#ifdef FORWARD
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
#define OBJECTSHADER_COMPILE_PS
|
||||
#define OBJECTSHADER_LAYOUT_COMMON
|
||||
#define RAYTRACED_SHADOWS_ENABLED
|
||||
#define SHADOW_MASK_ENABLED
|
||||
#define OUTPUT_GBUFFER
|
||||
#define TILEDFORWARD
|
||||
#define DISABLE_ALPHATEST
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
#define OBJECTSHADER_COMPILE_PS
|
||||
#define OBJECTSHADER_LAYOUT_COMMON
|
||||
#define RAYTRACED_SHADOWS_ENABLED
|
||||
#define SHADOW_MASK_ENABLED
|
||||
#define OUTPUT_GBUFFER
|
||||
#define TILEDFORWARD
|
||||
#define DISABLE_ALPHATEST
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
#define OBJECTSHADER_COMPILE_PS
|
||||
#define OBJECTSHADER_LAYOUT_COMMON
|
||||
#define RAYTRACED_SHADOWS_ENABLED
|
||||
#define SHADOW_MASK_ENABLED
|
||||
#define OUTPUT_GBUFFER
|
||||
#define TILEDFORWARD
|
||||
#define DISABLE_ALPHATEST
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
#define OBJECTSHADER_COMPILE_PS
|
||||
#define OBJECTSHADER_LAYOUT_COMMON
|
||||
#define RAYTRACED_SHADOWS_ENABLED
|
||||
#define SHADOW_MASK_ENABLED
|
||||
#define OUTPUT_GBUFFER
|
||||
#define TILEDFORWARD
|
||||
#define DISABLE_ALPHATEST
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
#define OBJECTSHADER_COMPILE_PS
|
||||
#define OBJECTSHADER_LAYOUT_COMMON
|
||||
#define RAYTRACED_SHADOWS_ENABLED
|
||||
#define SHADOW_MASK_ENABLED
|
||||
#define OUTPUT_GBUFFER
|
||||
#define TILEDFORWARD
|
||||
#define DISABLE_ALPHATEST
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
#define OBJECTSHADER_COMPILE_PS
|
||||
#define OBJECTSHADER_LAYOUT_COMMON
|
||||
#define RAYTRACED_SHADOWS_ENABLED
|
||||
#define SHADOW_MASK_ENABLED
|
||||
#define OUTPUT_GBUFFER
|
||||
#define TILEDFORWARD
|
||||
#define DISABLE_ALPHATEST
|
||||
|
||||
@@ -48,6 +48,10 @@ void RTShadow_Raygen()
|
||||
uint4 shadow_mask = 0;
|
||||
uint shadow_index = 0;
|
||||
|
||||
RayDesc ray;
|
||||
ray.TMin = 0.01;
|
||||
ray.Origin = surface.P + surface.N * 0.1;
|
||||
|
||||
[branch]
|
||||
if (g_xFrame_LightArrayCount > 0)
|
||||
{
|
||||
@@ -88,10 +92,7 @@ void RTShadow_Raygen()
|
||||
continue; // static lights will be skipped (they are used in lightmap baking)
|
||||
}
|
||||
|
||||
RayDesc ray;
|
||||
ray.TMin = 0.01;
|
||||
ray.TMax = 0;
|
||||
ray.Origin = trace_bias_position(surface.P, surface.N);
|
||||
|
||||
float3 L;
|
||||
|
||||
|
||||
@@ -0,0 +1,228 @@
|
||||
#define BRDF_NDOTL_BIAS 0.1
|
||||
#include "globals.hlsli"
|
||||
#include "ShaderInterop_Postprocess.h"
|
||||
#include "raytracingHF.hlsli"
|
||||
|
||||
TEXTURE2D(texture_normals, float3, TEXSLOT_ONDEMAND0);
|
||||
STRUCTUREDBUFFER(EntityTiles, uint, TEXSLOT_RENDERPATH_ENTITYTILES);
|
||||
|
||||
static const uint MAX_RTSHADOWS = 16;
|
||||
RWTEXTURE2D(output, uint4, 0);
|
||||
|
||||
[numthreads(POSTPROCESS_BLOCKSIZE, POSTPROCESS_BLOCKSIZE, 1)]
|
||||
void main(uint3 DTid : SV_DispatchThreadID, uint3 Gid : SV_GroupID, uint3 GTid : SV_GroupThreadID, uint groupIndex : SV_GroupIndex)
|
||||
{
|
||||
const float2 uv = ((float2)DTid.xy + 0.5f) * xPPResolution_rcp;
|
||||
const float depth = texture_depth.SampleLevel(sampler_point_clamp, uv, 1);
|
||||
if (depth == 0.0f)
|
||||
return;
|
||||
|
||||
const float3 P = reconstructPosition(uv, depth);
|
||||
float3 N = normalize(texture_normals.SampleLevel(sampler_point_clamp, uv, 0) * 2 - 1);
|
||||
|
||||
Surface surface;
|
||||
surface.init();
|
||||
surface.pixel = DTid.xy;
|
||||
surface.P = P + N * 0.05;
|
||||
surface.N = N;
|
||||
|
||||
const uint2 tileIndex = uint2(floor(surface.pixel * 2 / TILED_CULLING_BLOCKSIZE));
|
||||
const uint flatTileIndex = flatten2D(tileIndex, g_xFrame_EntityCullingTileCount.xy) * SHADER_ENTITY_TILE_BUCKET_COUNT;
|
||||
|
||||
uint shadow_mask[4] = {0,0,0,0};
|
||||
uint shadow_index = 0;
|
||||
|
||||
const float3 rayOrigin = mul(g_xCamera_View, float4(surface.P, 1)).xyz;
|
||||
|
||||
const float range = xPPParams0.x;
|
||||
const uint samplecount = xPPParams0.y;
|
||||
const float thickness = 0.1;
|
||||
const float stepsize = range / samplecount;
|
||||
const float offset = abs(dither(DTid.xy + GetTemporalAASampleRotation()));
|
||||
|
||||
[branch]
|
||||
if (g_xFrame_LightArrayCount > 0)
|
||||
{
|
||||
// Loop through light buckets in the tile:
|
||||
const uint first_item = g_xFrame_LightArrayOffset;
|
||||
const uint last_item = first_item + g_xFrame_LightArrayCount - 1;
|
||||
const uint first_bucket = first_item / 32;
|
||||
const uint last_bucket = min(last_item / 32, max(0, SHADER_ENTITY_TILE_BUCKET_COUNT - 1));
|
||||
[loop]
|
||||
for (uint bucket = first_bucket; bucket <= last_bucket && shadow_index < MAX_RTSHADOWS; ++bucket)
|
||||
{
|
||||
uint bucket_bits = EntityTiles[flatTileIndex + bucket];
|
||||
|
||||
// Bucket scalarizer - Siggraph 2017 - Improved Culling [Michal Drobot]:
|
||||
bucket_bits = WaveReadLaneFirst(WaveActiveBitOr(bucket_bits));
|
||||
|
||||
[loop]
|
||||
while (bucket_bits != 0 && shadow_index < MAX_RTSHADOWS)
|
||||
{
|
||||
// Retrieve global entity index from local bucket, then remove bit from local bucket:
|
||||
const uint bucket_bit_index = firstbitlow(bucket_bits);
|
||||
const uint entity_index = bucket * 32 + bucket_bit_index;
|
||||
bucket_bits ^= 1 << bucket_bit_index;
|
||||
|
||||
// Check if it is a light and process:
|
||||
[branch]
|
||||
if (entity_index >= first_item && entity_index <= last_item)
|
||||
{
|
||||
ShaderEntity light = EntityArray[entity_index];
|
||||
|
||||
if (!light.IsCastingShadow())
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
if (light.GetFlags() & ENTITY_FLAG_LIGHT_STATIC)
|
||||
{
|
||||
continue; // static lights will be skipped (they are used in lightmap baking)
|
||||
}
|
||||
|
||||
float3 L;
|
||||
bool has_shadow = false;
|
||||
|
||||
switch (light.GetType())
|
||||
{
|
||||
default:
|
||||
case ENTITY_TYPE_DIRECTIONALLIGHT:
|
||||
{
|
||||
L = normalize(light.GetDirection());
|
||||
|
||||
SurfaceToLight surfaceToLight;
|
||||
surfaceToLight.create(surface, L);
|
||||
|
||||
[branch]
|
||||
if (any(surfaceToLight.NdotL))
|
||||
{
|
||||
[branch]
|
||||
if (light.IsCastingShadow())
|
||||
{
|
||||
has_shadow = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
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)
|
||||
{
|
||||
const float3 Lunnormalized = L;
|
||||
const float dist = sqrt(dist2);
|
||||
L /= dist;
|
||||
|
||||
SurfaceToLight surfaceToLight;
|
||||
surfaceToLight.create(surface, L);
|
||||
|
||||
[branch]
|
||||
if (any(surfaceToLight.NdotL))
|
||||
{
|
||||
has_shadow = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
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)
|
||||
{
|
||||
const float dist = sqrt(dist2);
|
||||
L /= dist;
|
||||
|
||||
SurfaceToLight surfaceToLight;
|
||||
surfaceToLight.create(surface, L);
|
||||
|
||||
[branch]
|
||||
if (any(surfaceToLight.NdotL_sss))
|
||||
{
|
||||
const float SpotFactor = dot(L, light.GetDirection());
|
||||
const float spotCutOff = light.GetConeAngleCos();
|
||||
|
||||
[branch]
|
||||
if (SpotFactor > spotCutOff)
|
||||
{
|
||||
has_shadow = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
[branch]
|
||||
if (has_shadow)
|
||||
{
|
||||
const float3 rayDirection = normalize(mul((float3x3)g_xCamera_View, L));
|
||||
float3 rayPos = rayOrigin + rayDirection * stepsize * offset;
|
||||
|
||||
float occlusion = 0;
|
||||
|
||||
[loop]
|
||||
for (uint i = 0; i < samplecount; ++i)
|
||||
{
|
||||
rayPos += rayDirection * stepsize;
|
||||
|
||||
float4 proj = mul(g_xCamera_Proj, float4(rayPos, 1));
|
||||
proj.xyz /= proj.w;
|
||||
proj.xy = proj.xy * float2(0.5f, -0.5f) + float2(0.5f, 0.5f);
|
||||
|
||||
[branch]
|
||||
if (is_saturated(proj.xy))
|
||||
{
|
||||
const float ray_depth_real = proj.w;
|
||||
const float ray_depth_sample = texture_lineardepth.SampleLevel(sampler_point_clamp, proj.xy, 0) * g_xCamera_ZFarP;
|
||||
const float ray_depth_delta = ray_depth_real - ray_depth_sample;
|
||||
if (ray_depth_delta > 0 && ray_depth_delta < thickness)
|
||||
{
|
||||
occlusion = 1;
|
||||
|
||||
// screen edge fade:
|
||||
float2 fade = max(12 * abs(uv - 0.5) - 5, 0);
|
||||
occlusion *= saturate(1 - dot(fade, fade));
|
||||
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
float shadow = 1 - occlusion;
|
||||
|
||||
uint mask = uint(saturate(shadow) * 255); // 8 bits
|
||||
uint mask_shift = (shadow_index % 4) * 8;
|
||||
uint mask_bucket = shadow_index / 4;
|
||||
shadow_mask[mask_bucket] |= mask << mask_shift;
|
||||
}
|
||||
|
||||
// (**) cannot detect exactly same contribution as is pixel shaders!
|
||||
// So we always increment it for shadowed light, even if the
|
||||
// shadow contribution is not traced
|
||||
//
|
||||
// This is because in the pixel shader, we will detect the shadow
|
||||
// contribution more precisely due to more precise surface normals
|
||||
shadow_index++;
|
||||
|
||||
}
|
||||
else if (entity_index > last_item)
|
||||
{
|
||||
// force exit:
|
||||
bucket = SHADER_ENTITY_TILE_BUCKET_COUNT;
|
||||
break;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
output[DTid.xy] = uint4(shadow_mask[0], shadow_mask[1], shadow_mask[2], shadow_mask[3]);
|
||||
}
|
||||
@@ -377,6 +377,7 @@ enum SHADERTYPE
|
||||
CSTYPE_POSTPROCESS_UPSAMPLE_BILATERAL_UINT4,
|
||||
CSTYPE_POSTPROCESS_DOWNSAMPLE4X,
|
||||
CSTYPE_POSTPROCESS_NORMALSFROMDEPTH,
|
||||
CSTYPE_POSTPROCESS_SCREENSPACESHADOW,
|
||||
|
||||
|
||||
|
||||
|
||||
+103
-1
@@ -97,6 +97,7 @@ bool raytracedShadows = false;
|
||||
bool tessellationEnabled = true;
|
||||
bool disableAlbedoMaps = false;
|
||||
uint32_t raytracedShadowsSampleCount = 1;
|
||||
bool SCREENSPACESHADOWS = false;
|
||||
|
||||
|
||||
struct VoxelizedSceneData
|
||||
@@ -1236,6 +1237,7 @@ void LoadShaders()
|
||||
wiJobSystem::Execute(ctx, [](wiJobArgs args) { LoadShader(CS, shaders[CSTYPE_POSTPROCESS_UPSAMPLE_BILATERAL_UINT4], "upsample_bilateral_uint4CS.cso"); });
|
||||
wiJobSystem::Execute(ctx, [](wiJobArgs args) { LoadShader(CS, shaders[CSTYPE_POSTPROCESS_DOWNSAMPLE4X], "downsample4xCS.cso"); });
|
||||
wiJobSystem::Execute(ctx, [](wiJobArgs args) { LoadShader(CS, shaders[CSTYPE_POSTPROCESS_NORMALSFROMDEPTH], "normalsfromdepthCS.cso"); });
|
||||
wiJobSystem::Execute(ctx, [](wiJobArgs args) { LoadShader(CS, shaders[CSTYPE_POSTPROCESS_SCREENSPACESHADOW], "screenspaceshadowCS.cso"); });
|
||||
|
||||
|
||||
wiJobSystem::Execute(ctx, [](wiJobArgs args) { LoadShader(HS, shaders[HSTYPE_OBJECT], "objectHS.cso"); });
|
||||
@@ -3656,11 +3658,16 @@ void UpdatePerFrameData(
|
||||
if (device->CheckCapability(GRAPHICSDEVICE_CAPABILITY_RAYTRACING) && GetRaytracedShadowsEnabled())
|
||||
{
|
||||
frameCB.g_xFrame_Options |= OPTION_BIT_RAYTRACED_SHADOWS;
|
||||
frameCB.g_xFrame_Options |= OPTION_BIT_SHADOW_MASK;
|
||||
}
|
||||
if (disableAlbedoMaps)
|
||||
if (IsDisableAlbedoMaps())
|
||||
{
|
||||
frameCB.g_xFrame_Options |= OPTION_BIT_DISABLE_ALBEDO_MAPS;
|
||||
}
|
||||
if (GetScreenSpaceShadowsEnabled())
|
||||
{
|
||||
frameCB.g_xFrame_Options |= OPTION_BIT_SHADOW_MASK;
|
||||
}
|
||||
}
|
||||
void UpdateRenderData(
|
||||
const Visibility& vis,
|
||||
@@ -10472,6 +10479,93 @@ void Postprocess_RTShadow(
|
||||
wiProfiler::EndRange(prof_range);
|
||||
device->EventEnd(cmd);
|
||||
}
|
||||
void Postprocess_ScreenSpaceShadow(
|
||||
const Texture& depthbuffer,
|
||||
const Texture& lineardepth,
|
||||
const GPUBuffer& entityTiles_Opaque,
|
||||
const Texture& output,
|
||||
CommandList cmd,
|
||||
float range,
|
||||
uint32_t samplecount
|
||||
)
|
||||
{
|
||||
device->EventBegin("Postprocess_ScreenSpaceShadow", cmd);
|
||||
auto prof_range = wiProfiler::BeginRangeGPU("ScreenSpaceShadow", cmd);
|
||||
|
||||
static TextureDesc saved_desc;
|
||||
static Texture temp;
|
||||
static Texture temporal[2];
|
||||
static Texture normals;
|
||||
|
||||
const TextureDesc& lineardepth_desc = lineardepth.GetDesc();
|
||||
if (saved_desc.Width != lineardepth_desc.Width || saved_desc.Height != lineardepth_desc.Height)
|
||||
{
|
||||
saved_desc = lineardepth_desc; // <- this must already have SRV and UAV request flags set up!
|
||||
saved_desc.MipLevels = 1;
|
||||
|
||||
TextureDesc desc = saved_desc;
|
||||
desc.Width = (desc.Width + 1) / 2;
|
||||
desc.Height = (desc.Height + 1) / 2;
|
||||
desc.Format = FORMAT_R32G32B32A32_UINT;
|
||||
device->CreateTexture(&desc, nullptr, &temp);
|
||||
device->SetName(&temp, "rtshadow_temp");
|
||||
|
||||
device->CreateTexture(&desc, nullptr, &temporal[0]);
|
||||
device->SetName(&temporal[0], "rtshadow_temporal[0]");
|
||||
device->CreateTexture(&desc, nullptr, &temporal[1]);
|
||||
device->SetName(&temporal[1], "rtshadow_temporal[1]");
|
||||
|
||||
desc.Format = FORMAT_R11G11B10_FLOAT;
|
||||
device->CreateTexture(&desc, nullptr, &normals);
|
||||
device->SetName(&normals, "rtshadow_normals");
|
||||
}
|
||||
|
||||
Postprocess_NormalsFromDepth(depthbuffer, normals, cmd);
|
||||
|
||||
const TextureDesc& desc = temp.GetDesc();
|
||||
|
||||
PostProcessCB cb;
|
||||
cb.xPPResolution.x = desc.Width;
|
||||
cb.xPPResolution.y = desc.Height;
|
||||
cb.xPPResolution_rcp.x = 1.0f / cb.xPPResolution.x;
|
||||
cb.xPPResolution_rcp.y = 1.0f / cb.xPPResolution.y;
|
||||
cb.xPPParams0.x = range;
|
||||
cb.xPPParams0.y = (float)samplecount;
|
||||
device->UpdateBuffer(&constantBuffers[CBTYPE_POSTPROCESS], &cb, cmd);
|
||||
device->BindConstantBuffer(CS, &constantBuffers[CBTYPE_POSTPROCESS], CB_GETBINDSLOT(PostProcessCB), cmd);
|
||||
|
||||
device->BindComputeShader(&shaders[CSTYPE_POSTPROCESS_SCREENSPACESHADOW], cmd);
|
||||
|
||||
device->BindResource(CS, &depthbuffer, TEXSLOT_DEPTH, cmd);
|
||||
device->BindResource(CS, &lineardepth, TEXSLOT_LINEARDEPTH, cmd);
|
||||
|
||||
device->BindResource(CS, &normals, TEXSLOT_ONDEMAND0, cmd);
|
||||
device->BindResource(CS, &entityTiles_Opaque, TEXSLOT_RENDERPATH_ENTITYTILES, cmd);
|
||||
|
||||
const GPUResource* uavs[] = {
|
||||
&temp,
|
||||
};
|
||||
device->BindUAVs(CS, uavs, 0, arraysize(uavs), cmd);
|
||||
|
||||
device->Dispatch(
|
||||
(desc.Width + POSTPROCESS_BLOCKSIZE - 1) / POSTPROCESS_BLOCKSIZE,
|
||||
(desc.Height + POSTPROCESS_BLOCKSIZE - 1) / POSTPROCESS_BLOCKSIZE,
|
||||
1,
|
||||
cmd
|
||||
);
|
||||
|
||||
GPUBarrier barriers[] = {
|
||||
GPUBarrier::Memory(),
|
||||
};
|
||||
device->Barrier(barriers, arraysize(barriers), cmd);
|
||||
|
||||
device->UnbindUAVs(0, arraysize(uavs), cmd);
|
||||
|
||||
Postprocess_Upsample_Bilateral(temp, lineardepth, output, cmd);
|
||||
|
||||
wiProfiler::EndRange(prof_range);
|
||||
device->EventEnd(cmd);
|
||||
}
|
||||
void Postprocess_LightShafts(
|
||||
const Texture& input,
|
||||
const Texture& output,
|
||||
@@ -12305,5 +12399,13 @@ uint32_t GetRaytracedShadowsSampleCount()
|
||||
{
|
||||
return raytracedShadowsSampleCount;
|
||||
}
|
||||
void SetScreenSpaceShadowsEnabled(bool value)
|
||||
{
|
||||
SCREENSPACESHADOWS = value;
|
||||
}
|
||||
bool GetScreenSpaceShadowsEnabled()
|
||||
{
|
||||
return SCREENSPACESHADOWS;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -353,6 +353,15 @@ namespace wiRenderer
|
||||
const wiGraphics::Texture& output,
|
||||
wiGraphics::CommandList cmd
|
||||
);
|
||||
void Postprocess_ScreenSpaceShadow(
|
||||
const wiGraphics::Texture& depthbuffer,
|
||||
const wiGraphics::Texture& lineardepth,
|
||||
const wiGraphics::GPUBuffer& entityTiles_Opaque,
|
||||
const wiGraphics::Texture& output,
|
||||
wiGraphics::CommandList cmd,
|
||||
float range = 1,
|
||||
uint32_t samplecount = 16
|
||||
);
|
||||
void Postprocess_LightShafts(
|
||||
const wiGraphics::Texture& input,
|
||||
const wiGraphics::Texture& output,
|
||||
@@ -618,6 +627,8 @@ namespace wiRenderer
|
||||
bool IsDisableAlbedoMaps();
|
||||
void SetRaytracedShadowsSampleCount(uint32_t value);
|
||||
uint32_t GetRaytracedShadowsSampleCount();
|
||||
void SetScreenSpaceShadowsEnabled(bool value);
|
||||
bool GetScreenSpaceShadowsEnabled();
|
||||
|
||||
const wiGraphics::Texture* GetGlobalLightmap();
|
||||
|
||||
|
||||
@@ -9,7 +9,7 @@ namespace wiVersion
|
||||
// minor features, major updates, breaking compatibility changes
|
||||
const int minor = 52;
|
||||
// minor bug fixes, alterations, refactors, updates
|
||||
const int revision = 13;
|
||||
const int revision = 14;
|
||||
|
||||
const std::string version_string = std::to_string(major) + "." + std::to_string(minor) + "." + std::to_string(revision);
|
||||
|
||||
|
||||
@@ -87,3 +87,4 @@ Springs
|
||||
Terrain Rendering (material blending)
|
||||
Variable Rate Shading
|
||||
Real time ray tracing: ambient occlusion, shadows, reflections (DXR and Vulkan raytracing)
|
||||
Screen Space Contact Shadows
|
||||
|
||||
Reference in New Issue
Block a user