Use TraceSceenSpaceReflection in SSR shader for opaque
This commit is contained in:
BIN
Content/Shaders/SSR.flax
(Stored with Git LFS)
BIN
Content/Shaders/SSR.flax
(Stored with Git LFS)
Binary file not shown.
@@ -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();
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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
|
||||
|
||||
Reference in New Issue
Block a user