|
|
|
|
|
|
#ifndef UNITY_HDRENDERPIPELINE_SSAO_NOISEFILTER |
|
|
|
#define UNITY_HDRENDERPIPELINE_SSAO_NOISEFILTER |
|
|
|
|
|
|
|
half _Downsample; |
|
|
|
|
|
|
|
TEXTURE2D(_MainTex); |
|
|
|
SAMPLER2D(sampler_MainTex); |
|
|
|
float4 _MainTex_TexelSize; |
|
|
|
|
|
|
|
half4 FragSeparableFilter(Varyings input) : SV_Target |
|
|
|
{ |
|
|
|
// input.positionCS is SV_Position |
|
|
|
PositionInputs posInput = GetPositionInput(input.positionCS.xy, _ScreenSize.zw); |
|
|
|
float2 uv = posInput.positionSS; |
|
|
|
|
|
|
|
#if defined(SSAO_NOISEFILTER_HORIZONTAL) |
|
|
|
|
|
|
|
// Horizontal pass: Always use 2 texels interval to match to |
|
|
|
// the dither pattern. |
|
|
|
float2 delta = float2(_MainTex_TexelSize.x * 2.0, 0.0); |
|
|
|
|
|
|
|
#else // SSAO_NOISEFILTER_VERTICAL |
|
|
|
|
|
|
|
// Vertical pass: Apply _Downsample to match to the dither |
|
|
|
// pattern in the original occlusion buffer. |
|
|
|
float2 delta = float2(0.0, _MainTex_TexelSize.y / _Downsample * 2.0); |
|
|
|
|
|
|
|
#endif |
|
|
|
|
|
|
|
// 5-tap Gaussian with linear sampling. |
|
|
|
half4 p0 = SAMPLE_TEXTURE2D(_MainTex, sampler_MainTex, uv); |
|
|
|
half4 p1a = SAMPLE_TEXTURE2D(_MainTex, sampler_MainTex, uv - delta * 1.3846153846); |
|
|
|
half4 p1b = SAMPLE_TEXTURE2D(_MainTex, sampler_MainTex, uv + delta * 1.3846153846); |
|
|
|
half4 p2a = SAMPLE_TEXTURE2D(_MainTex, sampler_MainTex, uv - delta * 3.2307692308); |
|
|
|
half4 p2b = SAMPLE_TEXTURE2D(_MainTex, sampler_MainTex, uv + delta * 3.2307692308); |
|
|
|
|
|
|
|
#if defined(SSAO_NOISEFILTER_CENTERNORMAL) |
|
|
|
half3 n0 = SampleNormal(posInput.unPositionSS); |
|
|
|
#else |
|
|
|
half3 n0 = GetPackedNormal(p0); |
|
|
|
#endif |
|
|
|
|
|
|
|
// Geometry-aware weighting. |
|
|
|
half w0 = 0.2270270270; |
|
|
|
half w1a = CompareNormal(n0, GetPackedNormal(p1a)) * 0.3162162162; |
|
|
|
half w1b = CompareNormal(n0, GetPackedNormal(p1b)) * 0.3162162162; |
|
|
|
half w2a = CompareNormal(n0, GetPackedNormal(p2a)) * 0.0702702703; |
|
|
|
half w2b = CompareNormal(n0, GetPackedNormal(p2b)) * 0.0702702703; |
|
|
|
|
|
|
|
half s; |
|
|
|
s = GetPackedAO(p0) * w0; |
|
|
|
s += GetPackedAO(p1a) * w1a; |
|
|
|
s += GetPackedAO(p1b) * w1b; |
|
|
|
s += GetPackedAO(p2a) * w2a; |
|
|
|
s += GetPackedAO(p2b) * w2b; |
|
|
|
s /= w0 + w1a + w1b + w2a + w2b; |
|
|
|
|
|
|
|
return PackAONormal(s, n0); |
|
|
|
} |
|
|
|
|
|
|
|
half4 FragFinalFilter(Varyings input) : SV_Target0 |
|
|
|
{ |
|
|
|
// input.positionCS is SV_Position |
|
|
|
PositionInputs posInput = GetPositionInput(input.positionCS.xy, _ScreenSize.zw); |
|
|
|
float2 uv = posInput.positionSS; |
|
|
|
|
|
|
|
float2 delta = _MainTex_TexelSize.xy / _Downsample; // TODO: is it correct, we have already bilateral upsample here ? |
|
|
|
|
|
|
|
// 5-tap box blur filter. |
|
|
|
half4 p0 = SAMPLE_TEXTURE2D(_MainTex, sampler_MainTex, uv); |
|
|
|
half4 p1 = SAMPLE_TEXTURE2D(_MainTex, sampler_MainTex, uv + float2(-delta.x, -delta.y)); |
|
|
|
half4 p2 = SAMPLE_TEXTURE2D(_MainTex, sampler_MainTex, uv + float2(+delta.x, -delta.y)); |
|
|
|
half4 p3 = SAMPLE_TEXTURE2D(_MainTex, sampler_MainTex, uv + float2(-delta.x, +delta.y)); |
|
|
|
half4 p4 = SAMPLE_TEXTURE2D(_MainTex, sampler_MainTex, uv + float2(+delta.x, +delta.y)); |
|
|
|
|
|
|
|
half3 n0 = GetPackedNormal(p0); |
|
|
|
|
|
|
|
// Geometry-aware weighting. |
|
|
|
half w0 = 1.0; |
|
|
|
half w1 = CompareNormal(n0, GetPackedNormal(p1)); |
|
|
|
half w2 = CompareNormal(n0, GetPackedNormal(p2)); |
|
|
|
half w3 = CompareNormal(n0, GetPackedNormal(p3)); |
|
|
|
half w4 = CompareNormal(n0, GetPackedNormal(p4)); |
|
|
|
|
|
|
|
half ao; |
|
|
|
ao = GetPackedAO(p0) * w0; |
|
|
|
ao += GetPackedAO(p1) * w1; |
|
|
|
ao += GetPackedAO(p2) * w2; |
|
|
|
ao += GetPackedAO(p3) * w3; |
|
|
|
ao += GetPackedAO(p4) * w4; |
|
|
|
ao /= w0 + w1 + w2 + w3 + w4; |
|
|
|
|
|
|
|
// Note: When we ImageLoad outside of texture size, the value returned by Load is 0. |
|
|
|
// We use this property to have a neutral value for AO that doesn't consume a sampler and work also with compute shader (i.e use ImageLoad) |
|
|
|
// We store inverse AO so neutral is black. So either we sample inside or outside the texture it return 0 in case of neutral |
|
|
|
return half4(ao, 0, 0, 0); // <= we don't invert ao here but when we sample the texture for reasons explain above |
|
|
|
} |
|
|
|
|
|
|
|
#endif // UNITY_HDRENDERPIPELINE_SSAO_NOISEFILTER |