Use TraceSceenSpaceReflection in SSR shader for opaque

This commit is contained in:
Wojtek Figat
2022-04-12 22:16:45 +02:00
parent 58491e6d23
commit 96ed170871
4 changed files with 13 additions and 164 deletions

BIN
Content/Shaders/SSR.flax (Stored with Git LFS)

Binary file not shown.

View File

@@ -42,13 +42,10 @@ PACK_STRUCT(struct Data
float TemporalScale;
float RayTraceStep;
float NoTemporalEffect;
float TemporalEffect;
float Intensity;
float FadeOutDistance;
Vector3 Dummy0;
float InvFadeDistance;
Matrix ViewMatrix;
Matrix ViewProjectionMatrix;
});
@@ -248,11 +245,10 @@ void ScreenSpaceReflectionsPass::Render(RenderContext& renderContext, GPUTexture
data.MaxColorMiplevel = settings.UseColorBufferMips ? (float)colorBufferMips - 2.0f : 0.0f;
data.RayTraceStep = static_cast<float>(settings.DepthResolution) / (float)width;
data.Intensity = settings.Intensity;
data.FadeOutDistance = settings.FadeOutDistance;
data.InvFadeDistance = 1.0f / settings.FadeDistance;
data.FadeOutDistance = Math::Max(settings.FadeOutDistance, 100.0f);
data.TemporalScale = settings.TemporalScale;
data.TemporalResponse = settings.TemporalResponse;
data.NoTemporalEffect = useTemporal ? 0.0f : 1.0f;
data.TemporalEffect = useTemporal ? 1.0f : 0.0f;
if (useTemporal)
{
const float time = Time::Draw.UnscaledTime.GetTotalSeconds();

View File

@@ -52,7 +52,7 @@ float RayAttenBorder(float2 pos, float value)
// Screen Space Reflection ray tracing utility.
// Returns: xy: hitUV, z: hitMask, where hitUV is the result UV of hit pixel, hitMask is the normalized sample weight (0 if no hit).
float3 TraceSceenSpaceReflection(float2 uv, GBufferSample gBuffer, Texture2D depthBuffer, float3 viewPos, float4x4 viewMatrix, float4x4 viewProjectionMatrix, float stepSize, float maxSamples = 20, bool temporal = true, float temporalTime = 0.0f, float worldAntiSelfOcclusionBias = 0.1f, float brdfBias = 0.82f, float drawDistance = 5000.0f, float roughnessThreshold = 0.4f, float edgeFade = 0.1f)
float3 TraceSceenSpaceReflection(float2 uv, GBufferSample gBuffer, Texture2D depthBuffer, float3 viewPos, float4x4 viewMatrix, float4x4 viewProjectionMatrix, float stepSize, float maxSamples = 20, bool temporal = false, float temporalTime = 0.0f, float worldAntiSelfOcclusionBias = 0.1f, float brdfBias = 0.82f, float drawDistance = 5000.0f, float roughnessThreshold = 0.4f, float edgeFade = 0.1f)
{
// Reject invalid pixels
if (gBuffer.ShadingModel == SHADING_MODEL_UNLIT || gBuffer.Roughness > roughnessThreshold || gBuffer.ViewPos.z > drawDistance)

View File

@@ -1,13 +1,10 @@
// Copyright (c) 2012-2022 Wojciech Figat. All rights reserved.
#include "./Flax/Common.hlsl"
#include "./Flax/BRDF.hlsl"
#include "./Flax/Random.hlsl"
#include "./Flax/MonteCarlo.hlsl"
#include "./Flax/LightingCommon.hlsl"
#include "./Flax/GBuffer.hlsl"
#include "./Flax/ReflectionsCommon.hlsl"
#include "./Flax/BRDF.hlsl"
#include "./Flax/SSR.hlsl"
#include "./Flax/GBuffer.hlsl"
// Enable/disable luminance filter to reduce reflections highlights
#define SSR_REDUCE_HIGHLIGHTS 1
@@ -34,13 +31,10 @@ float TemporalResponse;
float TemporalScale;
float RayTraceStep;
float NoTemporalEffect;
float TemporalEffect;
float Intensity;
float FadeOutDistance;
float3 Dummy0;
float InvFadeDistance;
float4x4 ViewMatrix;
float4x4 ViewProjectionMatrix;
@@ -52,50 +46,6 @@ Texture2D Texture0 : register(t4);
Texture2D Texture1 : register(t5);
Texture2D Texture2 : register(t6);
float max2(float2 v)
{
return max(v.x, v.y);
}
float2 RandN2(float2 pos, float2 random)
{
return frac(sin(dot(pos.xy + random, float2(12.9898, 78.233))) * float2(43758.5453, 28001.8384));
}
// 1:-1 to 0:1
float2 ClipToUv(float2 clipPos)
{
return clipPos * float2(0.5, -0.5) + float2(0.5, 0.5);
}
// go into clip space (-1:1 from bottom/left to up/right)
float3 ProjectWorldToClip(float3 wsPos)
{
float4 clipPos = mul(float4(wsPos, 1), ViewProjectionMatrix);
return clipPos.xyz / clipPos.w;
}
// go into UV space. (0:1 from top/left to bottom/right)
float3 ProjectWorldToUv(float3 wsPos)
{
float3 clipPos = ProjectWorldToClip(wsPos);
return float3(ClipToUv(clipPos.xy), clipPos.z);
}
float4 TangentToWorld(float3 N, float4 H)
{
float3 upVector = abs(N.z) < 0.999 ? float3(0.0, 0.0, 1.0) : float3(1.0, 0.0, 0.0);
float3 T = normalize(cross(upVector, N));
float3 B = cross(N, T);
return float4((T * H.x) + (B * H.y) + (N * H.z), H.w);
}
float RayAttenBorder(float2 pos, float value)
{
float borderDist = min(1.0 - max(pos.x, pos.y), min(pos.x, pos.y));
return saturate(borderDist > value ? 1.0 : borderDist / value);
}
// Pixel Shader for screen space reflections rendering - combine pass
META_PS(true, FEATURE_LEVEL_ES2)
float4 PS_CombinePass(Quad_VS2PS input) : SV_Target0
@@ -135,112 +85,15 @@ float4 PS_CombinePass(Quad_VS2PS input) : SV_Target0
META_PS(true, FEATURE_LEVEL_ES2)
float4 PS_RayTracePass(Quad_VS2PS input) : SV_Target0
{
float2 uv = input.TexCoord;
// Sample GBuffer
GBufferData gBufferData = GetGBufferData();
GBufferSample gBuffer = SampleGBuffer(gBufferData, uv);
GBufferSample gBuffer = SampleGBuffer(gBufferData, input.TexCoord);
// Reject invalid pixels
if (gBuffer.ShadingModel == SHADING_MODEL_UNLIT || gBuffer.Roughness > RoughnessFade || gBuffer.ViewPos.z > FadeOutDistance)
return 0;
// Calculate view space normal vector
float3 normalVS = mul(gBuffer.Normal, (float3x3)ViewMatrix);
// Randomize it a little
float2 jitter = RandN2(uv, TemporalTime);
float2 Xi = jitter;
Xi.y = lerp(Xi.y, 0.0, BRDFBias);
float4 H = TangentToWorld(gBuffer.Normal, ImportanceSampleGGX(Xi, gBuffer.Roughness));
if (NoTemporalEffect)
H.xyz = gBuffer.Normal;
// Calculate normalized view space reflection vector
float3 reflectVS = normalize(reflect(gBuffer.ViewPos, normalVS));
if (gBuffer.ViewPos.z < 1.0 && reflectVS.z < 0.4)
return 0;
float3 viewWS = normalize(gBuffer.WorldPos - GBuffer.ViewPos);
float3 reflectWS = reflect(viewWS, H.xyz);
float3 startWS = gBuffer.WorldPos + gBuffer.Normal * WorldAntiSelfOcclusionBias;
float3 startUV = ProjectWorldToUv(startWS);
float3 endUV = ProjectWorldToUv(startWS + reflectWS);
float3 rayUV = endUV - startUV;
rayUV *= RayTraceStep / max2(abs(rayUV.xy));
float3 startUv = startUV + rayUV * 2;
float3 currOffset = startUv;
float3 rayStep = rayUV * 2;
// Calculate number of samples
float3 samplesToEdge = ((sign(rayStep.xyz) * 0.5 + 0.5) - currOffset.xyz) / rayStep.xyz;
samplesToEdge.x = min(samplesToEdge.x, min(samplesToEdge.y, samplesToEdge.z)) * 1.05f;
float numSamples = min(MaxTraceSamples, samplesToEdge.x);
rayStep *= samplesToEdge.x / numSamples;
// Calculate depth difference error
float depthDiffError = 1.3f * abs(rayStep.z);
// Ray trace
float currSampleIndex = 0;
float currSample, depthDiff;
LOOP
while (currSampleIndex < numSamples)
{
// Sample depth buffer and calculate depth difference
currSample = SampleZ(currOffset.xy);
depthDiff = currOffset.z - currSample;
// Check intersection
if (depthDiff >= 0)
{
if (depthDiff < depthDiffError)
{
break;
}
else
{
currOffset -= rayStep;
rayStep *= 0.5;
}
}
// Move forward
currOffset += rayStep;
currSampleIndex++;
}
// Check if has valid result after ray tracing
if (currSampleIndex >= numSamples)
{
// All samples done but no result
return 0;
}
float2 hitUV = currOffset.xy;
// Fade rays close to screen edge
const float fadeStart = 0.9f;
const float fadeEnd = 1.0f;
const float fadeDiffRcp = 1.0f / (fadeEnd - fadeStart);
float2 boundary = abs(hitUV - float2(0.5f, 0.5f)) * 2.0f;
float fadeOnBorder = 1.0f - saturate((boundary.x - fadeStart) * fadeDiffRcp);
fadeOnBorder *= 1.0f - saturate((boundary.y - fadeStart) * fadeDiffRcp);
fadeOnBorder = smoothstep(0.0f, 1.0f, fadeOnBorder);
fadeOnBorder *= RayAttenBorder(hitUV, EdgeFadeFactor);
// Fade rays on high roughness
float roughnessFade = saturate((RoughnessFade - gBuffer.Roughness) * 20);
// Fade on distance
float distanceFade = saturate((FadeOutDistance - gBuffer.ViewPos.z) * InvFadeDistance);
// Trace depth buffer to find intersection
float3 hit = TraceSceenSpaceReflection(input.TexCoord, gBuffer, Depth, gBufferData.ViewPos, ViewMatrix, ViewProjectionMatrix, RayTraceStep, MaxTraceSamples, TemporalEffect, TemporalTime, WorldAntiSelfOcclusionBias, BRDFBias, FadeOutDistance, RoughnessFade, EdgeFadeFactor);
// Output: xy: hitUV, z: hitMask, w: unused
return float4(hitUV, fadeOnBorder * roughnessFade * distanceFade * Intensity, 0);
return float4(hit.xy, hit.z * Intensity, 0);
}
#ifndef RESOLVE_SAMPLES