Implement shadows rendering to direct light atlas (with Glboal SDF tracing)
This commit is contained in:
BIN
Content/Shaders/GlobalSurfaceAtlas.flax
(Stored with Git LFS)
BIN
Content/Shaders/GlobalSurfaceAtlas.flax
(Stored with Git LFS)
Binary file not shown.
@@ -32,7 +32,8 @@ PACK_STRUCT(struct Data0
|
|||||||
{
|
{
|
||||||
Vector3 ViewWorldPos;
|
Vector3 ViewWorldPos;
|
||||||
float ViewNearPlane;
|
float ViewNearPlane;
|
||||||
Vector3 Padding00;
|
Vector2 Padding00;
|
||||||
|
float LightShadowsStrength;
|
||||||
float ViewFarPlane;
|
float ViewFarPlane;
|
||||||
Vector4 ViewFrustumWorldRays[4];
|
Vector4 ViewFrustumWorldRays[4];
|
||||||
GlobalSignDistanceFieldPass::GlobalSDFData GlobalSDF;
|
GlobalSignDistanceFieldPass::GlobalSDFData GlobalSDF;
|
||||||
@@ -51,7 +52,7 @@ PACK_STRUCT(struct AtlasTileVertex
|
|||||||
struct GlobalSurfaceAtlasTile : RectPack<GlobalSurfaceAtlasTile, uint16>
|
struct GlobalSurfaceAtlasTile : RectPack<GlobalSurfaceAtlasTile, uint16>
|
||||||
{
|
{
|
||||||
Vector3 ViewDirection;
|
Vector3 ViewDirection;
|
||||||
Vector3 ViewPosition; // TODO: use from ViewMatrix
|
Vector3 ViewPosition;
|
||||||
Vector3 ViewBoundsSize;
|
Vector3 ViewBoundsSize;
|
||||||
Matrix ViewMatrix;
|
Matrix ViewMatrix;
|
||||||
|
|
||||||
@@ -428,7 +429,6 @@ bool GlobalSurfaceAtlasPass::Render(RenderContext& renderContext, GPUContext* co
|
|||||||
|
|
||||||
// Insert tile into atlas
|
// Insert tile into atlas
|
||||||
auto* tile = surfaceAtlasData.AtlasTiles->Insert(tileResolution, tileResolution, 0, &surfaceAtlasData, e.Actor, tileIndex);
|
auto* tile = surfaceAtlasData.AtlasTiles->Insert(tileResolution, tileResolution, 0, &surfaceAtlasData, e.Actor, tileIndex);
|
||||||
// TODO: try to perform atlas defragmentation if it's full (eg. max once per ~10s)
|
|
||||||
if (tile)
|
if (tile)
|
||||||
{
|
{
|
||||||
if (!object)
|
if (!object)
|
||||||
@@ -680,7 +680,10 @@ bool GlobalSurfaceAtlasPass::Render(RenderContext& renderContext, GPUContext* co
|
|||||||
|
|
||||||
// Copy emissive light into the final direct lighting atlas
|
// Copy emissive light into the final direct lighting atlas
|
||||||
// TODO: test perf diff when manually copying only dirty object tiles and dirty light tiles
|
// TODO: test perf diff when manually copying only dirty object tiles and dirty light tiles
|
||||||
context->CopyTexture(surfaceAtlasData.AtlasDirectLight, 0, 0, 0, 0, surfaceAtlasData.AtlasEmissive, 0);
|
{
|
||||||
|
PROFILE_GPU_CPU("Copy Emissive");
|
||||||
|
context->CopyTexture(surfaceAtlasData.AtlasDirectLight, 0, 0, 0, 0, surfaceAtlasData.AtlasEmissive, 0);
|
||||||
|
}
|
||||||
|
|
||||||
context->SetViewportAndScissors(Viewport(0, 0, resolution, resolution));
|
context->SetViewportAndScissors(Viewport(0, 0, resolution, resolution));
|
||||||
context->SetRenderTarget(surfaceAtlasData.AtlasDirectLight->View());
|
context->SetRenderTarget(surfaceAtlasData.AtlasDirectLight->View());
|
||||||
@@ -689,6 +692,11 @@ bool GlobalSurfaceAtlasPass::Render(RenderContext& renderContext, GPUContext* co
|
|||||||
context->BindSR(2, surfaceAtlasData.AtlasGBuffer2->View());
|
context->BindSR(2, surfaceAtlasData.AtlasGBuffer2->View());
|
||||||
context->BindSR(3, surfaceAtlasData.AtlasDepth->View());
|
context->BindSR(3, surfaceAtlasData.AtlasDepth->View());
|
||||||
context->BindSR(4, surfaceAtlasData.ObjectsBuffer.GetBuffer()->View());
|
context->BindSR(4, surfaceAtlasData.ObjectsBuffer.GetBuffer()->View());
|
||||||
|
for (int32 i = 0; i < 4; i++)
|
||||||
|
{
|
||||||
|
context->BindSR(i + 5, bindingDataSDF.Cascades[i]->ViewVolume());
|
||||||
|
context->BindSR(i + 9, bindingDataSDF.CascadeMips[i]->ViewVolume());
|
||||||
|
}
|
||||||
context->BindCB(0, _cb0);
|
context->BindCB(0, _cb0);
|
||||||
Data0 data;
|
Data0 data;
|
||||||
data.ViewWorldPos = renderContext.View.Position;
|
data.ViewWorldPos = renderContext.View.Position;
|
||||||
@@ -717,6 +725,7 @@ bool GlobalSurfaceAtlasPass::Render(RenderContext& renderContext, GPUContext* co
|
|||||||
const bool useShadow = CanRenderShadow(renderContext.View, light);
|
const bool useShadow = CanRenderShadow(renderContext.View, light);
|
||||||
// TODO: test perf/quality when using Shadow Map for directional light (ShadowsPass::Instance()->LastDirLightShadowMap) instead of Global SDF trace
|
// TODO: test perf/quality when using Shadow Map for directional light (ShadowsPass::Instance()->LastDirLightShadowMap) instead of Global SDF trace
|
||||||
light.SetupLightData(&data.Light, useShadow);
|
light.SetupLightData(&data.Light, useShadow);
|
||||||
|
data.LightShadowsStrength = 1.0f - light.ShadowsStrength;
|
||||||
context->UpdateCB(_cb0, &data);
|
context->UpdateCB(_cb0, &data);
|
||||||
context->SetState(_psDirectLighting0);
|
context->SetState(_psDirectLighting0);
|
||||||
VB_DRAW();
|
VB_DRAW();
|
||||||
@@ -743,6 +752,7 @@ bool GlobalSurfaceAtlasPass::Render(RenderContext& renderContext, GPUContext* co
|
|||||||
// Draw draw light
|
// Draw draw light
|
||||||
const bool useShadow = CanRenderShadow(renderContext.View, light);
|
const bool useShadow = CanRenderShadow(renderContext.View, light);
|
||||||
light.SetupLightData(&data.Light, useShadow);
|
light.SetupLightData(&data.Light, useShadow);
|
||||||
|
data.LightShadowsStrength = 1.0f - light.ShadowsStrength;
|
||||||
context->UpdateCB(_cb0, &data);
|
context->UpdateCB(_cb0, &data);
|
||||||
context->SetState(_psDirectLighting1);
|
context->SetState(_psDirectLighting1);
|
||||||
VB_DRAW();
|
VB_DRAW();
|
||||||
@@ -769,6 +779,7 @@ bool GlobalSurfaceAtlasPass::Render(RenderContext& renderContext, GPUContext* co
|
|||||||
// Draw draw light
|
// Draw draw light
|
||||||
const bool useShadow = CanRenderShadow(renderContext.View, light);
|
const bool useShadow = CanRenderShadow(renderContext.View, light);
|
||||||
light.SetupLightData(&data.Light, useShadow);
|
light.SetupLightData(&data.Light, useShadow);
|
||||||
|
data.LightShadowsStrength = 1.0f - light.ShadowsStrength;
|
||||||
context->UpdateCB(_cb0, &data);
|
context->UpdateCB(_cb0, &data);
|
||||||
context->SetState(_psDirectLighting1);
|
context->SetState(_psDirectLighting1);
|
||||||
VB_DRAW();
|
VB_DRAW();
|
||||||
@@ -779,6 +790,8 @@ bool GlobalSurfaceAtlasPass::Render(RenderContext& renderContext, GPUContext* co
|
|||||||
|
|
||||||
// TODO: indirect lighting apply to get infinite bounces for GI
|
// TODO: indirect lighting apply to get infinite bounces for GI
|
||||||
|
|
||||||
|
// TODO: explore atlas tiles optimization with feedback from renderer (eg. when tile is sampled by GI/Reflections mark it as used, then sort tiles by importance and prioritize updates for ones frequently used)
|
||||||
|
|
||||||
#undef WRITE_TILE
|
#undef WRITE_TILE
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -6,6 +6,7 @@
|
|||||||
#define GLOBAL_SDF_RASTERIZE_CHUNK_SIZE 32
|
#define GLOBAL_SDF_RASTERIZE_CHUNK_SIZE 32
|
||||||
#define GLOBAL_SDF_RASTERIZE_CHUNK_MARGIN 4
|
#define GLOBAL_SDF_RASTERIZE_CHUNK_MARGIN 4
|
||||||
#define GLOBAL_SDF_MIP_FLOODS 5
|
#define GLOBAL_SDF_MIP_FLOODS 5
|
||||||
|
#define GLOBAL_SDF_WORLD_SIZE 60000.0f
|
||||||
|
|
||||||
// Global SDF data for a constant buffer
|
// Global SDF data for a constant buffer
|
||||||
struct GlobalSDFData
|
struct GlobalSDFData
|
||||||
@@ -61,7 +62,7 @@ float SampleGlobalSDF(const GlobalSDFData data, Texture3D<float> tex[4], float3
|
|||||||
{
|
{
|
||||||
float distance = data.CascadePosDistance[3].w * 2.0f;
|
float distance = data.CascadePosDistance[3].w * 2.0f;
|
||||||
if (distance <= 0.0f)
|
if (distance <= 0.0f)
|
||||||
return 60000;
|
return GLOBAL_SDF_WORLD_SIZE;
|
||||||
UNROLL
|
UNROLL
|
||||||
for (uint cascade = 0; cascade < 4; cascade++)
|
for (uint cascade = 0; cascade < 4; cascade++)
|
||||||
{
|
{
|
||||||
@@ -83,7 +84,7 @@ float SampleGlobalSDF(const GlobalSDFData data, Texture3D<float> tex[4], float3
|
|||||||
float3 SampleGlobalSDFGradient(const GlobalSDFData data, Texture3D<float> tex[4], float3 worldPosition, out float distance)
|
float3 SampleGlobalSDFGradient(const GlobalSDFData data, Texture3D<float> tex[4], float3 worldPosition, out float distance)
|
||||||
{
|
{
|
||||||
float3 gradient = float3(0, 0.00001f, 0);
|
float3 gradient = float3(0, 0.00001f, 0);
|
||||||
distance = 60000;
|
distance = GLOBAL_SDF_WORLD_SIZE;
|
||||||
if (data.CascadePosDistance[3].w <= 0.0f)
|
if (data.CascadePosDistance[3].w <= 0.0f)
|
||||||
return gradient;
|
return gradient;
|
||||||
UNROLL
|
UNROLL
|
||||||
|
|||||||
@@ -12,7 +12,8 @@
|
|||||||
META_CB_BEGIN(0, Data)
|
META_CB_BEGIN(0, Data)
|
||||||
float3 ViewWorldPos;
|
float3 ViewWorldPos;
|
||||||
float ViewNearPlane;
|
float ViewNearPlane;
|
||||||
float3 Padding00;
|
float2 Padding00;
|
||||||
|
float LightShadowsStrengthOneMinus;
|
||||||
float ViewFarPlane;
|
float ViewFarPlane;
|
||||||
float4 ViewFrustumWorldRays[4];
|
float4 ViewFrustumWorldRays[4];
|
||||||
GlobalSDFData GlobalSDF;
|
GlobalSDFData GlobalSDF;
|
||||||
@@ -66,6 +67,8 @@ void PS_Clear(out float4 Light : SV_Target0, out float4 RT0 : SV_Target1, out fl
|
|||||||
|
|
||||||
// GBuffer+Depth at 0-3 slots
|
// GBuffer+Depth at 0-3 slots
|
||||||
Buffer<float4> GlobalSurfaceAtlasObjects : register(t4);
|
Buffer<float4> GlobalSurfaceAtlasObjects : register(t4);
|
||||||
|
Texture3D<float> GlobalSDFTex[4] : register(t5);
|
||||||
|
Texture3D<float> GlobalSDFMip[4] : register(t9);
|
||||||
|
|
||||||
// Pixel shader for Global Surface Atlas shading with direct light contribution
|
// Pixel shader for Global Surface Atlas shading with direct light contribution
|
||||||
META_PS(true, FEATURE_LEVEL_SM5)
|
META_PS(true, FEATURE_LEVEL_SM5)
|
||||||
@@ -81,11 +84,10 @@ float4 PS_DirectLighting(AtlasVertexOutput input) : SV_Target
|
|||||||
// Load GBuffer sample from atlas
|
// Load GBuffer sample from atlas
|
||||||
GBufferData gBufferData = (GBufferData)0;
|
GBufferData gBufferData = (GBufferData)0;
|
||||||
GBufferSample gBuffer = SampleGBuffer(gBufferData, atlasUV);
|
GBufferSample gBuffer = SampleGBuffer(gBufferData, atlasUV);
|
||||||
|
|
||||||
// Skip unlit pixels
|
|
||||||
BRANCH
|
BRANCH
|
||||||
if (gBuffer.ShadingModel == SHADING_MODEL_UNLIT)
|
if (gBuffer.ShadingModel == SHADING_MODEL_UNLIT)
|
||||||
{
|
{
|
||||||
|
// Skip unlit pixels
|
||||||
discard;
|
discard;
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
@@ -102,11 +104,43 @@ float4 PS_DirectLighting(AtlasVertexOutput input) : SV_Target
|
|||||||
float4x4 tileLocalToWorld = Inverse(tile.WorldToLocal);
|
float4x4 tileLocalToWorld = Inverse(tile.WorldToLocal);
|
||||||
gBuffer.WorldPos = mul(float4(gBufferTilePos, 1), tileLocalToWorld).xyz;
|
gBuffer.WorldPos = mul(float4(gBufferTilePos, 1), tileLocalToWorld).xyz;
|
||||||
|
|
||||||
|
// Calculate shadowing
|
||||||
|
float3 L = Light.Direction;
|
||||||
|
#if RADIAL_LIGHT
|
||||||
|
float3 toLight = Light.Position - gBuffer.WorldPos;
|
||||||
|
float toLightDst = length(toLight);
|
||||||
|
if (toLightDst >= Light.Radius)
|
||||||
|
{
|
||||||
|
// Skip texels outside the light influence range
|
||||||
|
discard;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
L = toLight / toLightDst;
|
||||||
|
#else
|
||||||
|
float toLightDst = GLOBAL_SDF_WORLD_SIZE;
|
||||||
|
#endif
|
||||||
float4 shadowMask = 1;
|
float4 shadowMask = 1;
|
||||||
BRANCH
|
|
||||||
if (Light.CastShadows > 0)
|
if (Light.CastShadows > 0)
|
||||||
{
|
{
|
||||||
// TODO: calculate shadow for the light (use Global SDF)
|
float NoL = dot(gBuffer.Normal, L);
|
||||||
|
float shadowBias = 10.0f;
|
||||||
|
float bias = 2 * shadowBias * saturate(1 - NoL) + shadowBias;
|
||||||
|
BRANCH
|
||||||
|
if (NoL > 0)
|
||||||
|
{
|
||||||
|
// TODO: try using shadow map for on-screen pixels
|
||||||
|
// TODO: try using cone trace with Global SDF for smoother shadow (eg. for sun shadows or for area lights)
|
||||||
|
|
||||||
|
// Shot a ray from light into texel to see if there is any occluder
|
||||||
|
GlobalSDFTrace trace;
|
||||||
|
trace.Init(gBuffer.WorldPos + gBuffer.Normal * shadowBias, L, bias, toLightDst - bias);
|
||||||
|
GlobalSDFHit hit = RayTraceGlobalSDF(GlobalSDF, GlobalSDFTex, GlobalSDFMip, trace);
|
||||||
|
shadowMask = hit.IsHit() ? LightShadowsStrengthOneMinus : 1;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
shadowMask = 0;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Calculate lighting
|
// Calculate lighting
|
||||||
|
|||||||
Reference in New Issue
Block a user