post processing
[WindSway-HDRP.git] / Library / PackageCache / com.unity.postprocessing@2.1.6 / PostProcessing / Shaders / Builtins / ScalableAO.hlsl
blob317c17e880d210db39954f862dd454efd05027a5
1 #ifndef UNITY_POSTFX_AMBIENT_OCCLUSION
2 #define UNITY_POSTFX_AMBIENT_OCCLUSION
4 #include "../StdLib.hlsl"
5 #include "../Colors.hlsl"
6 #include "Fog.hlsl"
8 // --------
9 // Options for further customization
10 // --------
12 // By default, a 5-tap Gaussian with the linear sampling technique is used
13 // in the bilateral noise filter. It can be replaced with a 7-tap Gaussian
14 // with adaptive sampling by enabling the macro below. Although the
15 // differences are not noticeable in most cases, it may provide preferable
16 // results with some special usage (e.g. NPR without textureing).
17 // #define BLUR_HIGH_QUALITY
19 // By default, a fixed sampling pattern is used in the AO estimator. Although
20 // this gives preferable results in most cases, a completely random sampling
21 // pattern could give aesthetically better results. Disable the macro below
22 // to use such a random pattern instead of the fixed one.
23 #define FIX_SAMPLING_PATTERN
25 // The SampleNormal function normalizes samples from G-buffer because
26 // they're possibly unnormalized. We can eliminate this if it can be said
27 // that there is no wrong shader that outputs unnormalized normals.
28 // #define VALIDATE_NORMALS
30 // The constant below determines the contrast of occlusion. This allows
31 // users to control over/under occlusion. At the moment, this is not exposed
32 // to the editor because it's rarely useful.
33 static const float kContrast = 0.6;
35 // The constant below controls the geometry-awareness of the bilateral
36 // filter. The higher value, the more sensitive it is.
37 static const float kGeometryCoeff = 0.8;
39 // The constants below are used in the AO estimator. Beta is mainly used
40 // for suppressing self-shadowing noise, and Epsilon is used to prevent
41 // calculation underflow. See the paper (Morgan 2011 http://goo.gl/2iz3P)
42 // for further details of these constants.
43 static const float kBeta = 0.002;
45 // --------
47 // System built-in variables
48 TEXTURE2D_SAMPLER2D(_MainTex, sampler_MainTex);
49 TEXTURE2D_SAMPLER2D(_CameraGBufferTexture2, sampler_CameraGBufferTexture2);
50 TEXTURE2D_SAMPLER2D(_CameraDepthTexture, sampler_CameraDepthTexture);
51 TEXTURE2D_SAMPLER2D(_CameraDepthNormalsTexture, sampler_CameraDepthNormalsTexture);
53 float4 _MainTex_TexelSize;
55 float4 _AOParams;
56 float3 _AOColor;
58 // Sample count
59 #if !defined(SHADER_API_GLES)
60     #define SAMPLE_COUNT _AOParams.w
61 #else
62 // GLES2: In many cases, dynamic looping is not supported.
63     #define SAMPLE_COUNT 3
64 #endif
66 // Source texture properties
67 TEXTURE2D_SAMPLER2D(_SAOcclusionTexture, sampler_SAOcclusionTexture);
68 float4 _SAOcclusionTexture_TexelSize;
70 // Other parameters
71 #define INTENSITY _AOParams.x
72 #define RADIUS _AOParams.y
73 #define DOWNSAMPLE _AOParams.z
75 // Accessors for packed AO/normal buffer
76 half4 PackAONormal(half ao, half3 n)
78     return half4(ao, n * 0.5 + 0.5);
81 half GetPackedAO(half4 p)
83     return p.r;
86 half3 GetPackedNormal(half4 p)
88     return p.gba * 2.0 - 1.0;
91 // Boundary check for depth sampler
92 // (returns a very large value if it lies out of bounds)
93 float CheckBounds(float2 uv, float d)
95     float ob = any(uv < 0) + any(uv > 1);
96 #if defined(UNITY_REVERSED_Z)
97     ob += (d <= 0.00001);
98 #else
99     ob += (d >= 0.99999);
100 #endif
101     return ob * 1e8;
104 // Depth/normal sampling functions
105 float SampleDepth(float2 uv)
107     float d = Linear01Depth(SAMPLE_DEPTH_TEXTURE_LOD(_CameraDepthTexture, sampler_CameraDepthTexture, UnityStereoTransformScreenSpaceTex(uv), 0));
108     return d * _ProjectionParams.z + CheckBounds(uv, d);
111 float3 SampleNormal(float2 uv)
113 #if defined(SOURCE_GBUFFER)
114     float3 norm = SAMPLE_TEXTURE2D(_CameraGBufferTexture2, sampler_CameraGBufferTexture2, uv).xyz;
115     norm = norm * 2 - any(norm); // gets (0,0,0) when norm == 0
116     norm = mul((float3x3)unity_WorldToCamera, norm);
117 #if defined(VALIDATE_NORMALS)
118     norm = normalize(norm);
119 #endif
120     return norm;
121 #else
122     float4 cdn = SAMPLE_TEXTURE2D(_CameraDepthNormalsTexture, sampler_CameraDepthNormalsTexture, uv);
123     return DecodeViewNormalStereo(cdn) * float3(1.0, 1.0, -1.0);
124 #endif
127 float SampleDepthNormal(float2 uv, out float3 normal)
129     normal = SampleNormal(UnityStereoTransformScreenSpaceTex(uv));
130     return SampleDepth(uv);
133 // Normal vector comparer (for geometry-aware weighting)
134 half CompareNormal(half3 d1, half3 d2)
136     return smoothstep(kGeometryCoeff, 1.0, dot(d1, d2));
139 // Trigonometric function utility
140 float2 CosSin(float theta)
142     float sn, cs;
143     sincos(theta, sn, cs);
144     return float2(cs, sn);
147 // Pseudo random number generator with 2D coordinates
148 float UVRandom(float u, float v)
150     float f = dot(float2(12.9898, 78.233), float2(u, v));
151     return frac(43758.5453 * sin(f));
154 // Check if the camera is perspective.
155 // (returns 1.0 when orthographic)
156 float CheckPerspective(float x)
158     return lerp(x, 1.0, unity_OrthoParams.w);
161 // Reconstruct view-space position from UV and depth.
162 // p11_22 = (unity_CameraProjection._11, unity_CameraProjection._22)
163 // p13_31 = (unity_CameraProjection._13, unity_CameraProjection._23)
164 float3 ReconstructViewPos(float2 uv, float depth, float2 p11_22, float2 p13_31)
166     return float3((uv * 2.0 - 1.0 - p13_31) / p11_22 * CheckPerspective(depth), depth);
169 // Sample point picker
170 float3 PickSamplePoint(float2 uv, float index)
172     // Uniformaly distributed points on a unit sphere
173     // http://mathworld.wolfram.com/SpherePointPicking.html
174 #if defined(FIX_SAMPLING_PATTERN)
175     float gn = GradientNoise(uv * DOWNSAMPLE);
176     // FIXEME: This was added to avoid a NVIDIA driver issue.
177     //                                   vvvvvvvvvvvv
178     float u = frac(UVRandom(0.0, index + uv.x * 1e-10) + gn) * 2.0 - 1.0;
179     float theta = (UVRandom(1.0, index + uv.x * 1e-10) + gn) * TWO_PI;
180 #else
181     float u = UVRandom(uv.x + _Time.x, uv.y + index) * 2.0 - 1.0;
182     float theta = UVRandom(-uv.x - _Time.x, uv.y + index) * TWO_PI;
183 #endif
184     float3 v = float3(CosSin(theta) * sqrt(1.0 - u * u), u);
185     // Make them distributed between [0, _Radius]
186     float l = sqrt((index + 1.0) / SAMPLE_COUNT) * RADIUS;
187     return v * l;
191 // Distance-based AO estimator based on Morgan 2011
192 // "Alchemy screen-space ambient obscurance algorithm"
193 // http://graphics.cs.williams.edu/papers/AlchemyHPG11/
195 float4 FragAO(VaryingsDefault i) : SV_Target
197     float2 uv = i.texcoord;
199     // Parameters used in coordinate conversion
200     float3x3 proj = (float3x3)unity_CameraProjection;
201     float2 p11_22 = float2(unity_CameraProjection._11, unity_CameraProjection._22);
202     float2 p13_31 = float2(unity_CameraProjection._13, unity_CameraProjection._23);
204     // View space normal and depth
205     float3 norm_o;
206     float depth_o = SampleDepthNormal(uv, norm_o);
208     // Reconstruct the view-space position.
209     float3 vpos_o = ReconstructViewPos(uv, depth_o, p11_22, p13_31);
211     float ao = 0.0;
213     for (int s = 0; s < int(SAMPLE_COUNT); s++)
214     {
215         // Sample point
216 #if defined(SHADER_API_D3D11)
217         // This 'floor(1.0001 * s)' operation is needed to avoid a NVidia shader issue. This issue
218         // is only observed on DX11.
219         float3 v_s1 = PickSamplePoint(uv, floor(1.0001 * s));
220 #else
221         float3 v_s1 = PickSamplePoint(uv, s);
222 #endif
224         v_s1 = faceforward(v_s1, -norm_o, v_s1);
225         float3 vpos_s1 = vpos_o + v_s1;
227         // Reproject the sample point
228         float3 spos_s1 = mul(proj, vpos_s1);
229         float2 uv_s1_01 = (spos_s1.xy / CheckPerspective(vpos_s1.z) + 1.0) * 0.5;
231         // Depth at the sample point
232         float depth_s1 = SampleDepth(uv_s1_01);
234         // Relative position of the sample point
235         float3 vpos_s2 = ReconstructViewPos(uv_s1_01, depth_s1, p11_22, p13_31);
236         float3 v_s2 = vpos_s2 - vpos_o;
238         // Estimate the obscurance value
239         float a1 = max(dot(v_s2, norm_o) - kBeta * depth_o, 0.0);
240         float a2 = dot(v_s2, v_s2) + EPSILON;
241         ao += a1 / a2;
242     }
244     ao *= RADIUS; // Intensity normalization
246     // Apply other parameters.
247     ao = PositivePow(ao * INTENSITY / SAMPLE_COUNT, kContrast);
249     // Apply fog when enabled (forward-only)
250 #if (APPLY_FORWARD_FOG)
251     float d = Linear01Depth(SAMPLE_DEPTH_TEXTURE(_CameraDepthTexture, sampler_CameraDepthTexture, i.texcoordStereo));
252     d = ComputeFogDistance(d);
253     ao *= ComputeFog(d);
254 #endif
256     return PackAONormal(ao, norm_o);
259 // Geometry-aware separable bilateral filter
260 float4 FragBlur(VaryingsDefault i) : SV_Target
262 #if defined(BLUR_HORIZONTAL)
263     // Horizontal pass: Always use 2 texels interval to match to
264     // the dither pattern.
265     float2 delta = float2(_MainTex_TexelSize.x * 2.0, 0.0);
266 #else
267     // Vertical pass: Apply _Downsample to match to the dither
268     // pattern in the original occlusion buffer.
269     float2 delta = float2(0.0, _MainTex_TexelSize.y / DOWNSAMPLE * 2.0);
270 #endif
272 #if defined(BLUR_HIGH_QUALITY)
274     // High quality 7-tap Gaussian with adaptive sampling
276     half4 p0  = SAMPLE_TEXTURE2D(_MainTex, sampler_MainTex, i.texcoordStereo);
277     half4 p1a = SAMPLE_TEXTURE2D(_MainTex, sampler_MainTex, UnityStereoTransformScreenSpaceTex(i.texcoord - delta));
278     half4 p1b = SAMPLE_TEXTURE2D(_MainTex, sampler_MainTex, UnityStereoTransformScreenSpaceTex(i.texcoord + delta));
279     half4 p2a = SAMPLE_TEXTURE2D(_MainTex, sampler_MainTex, UnityStereoTransformScreenSpaceTex(i.texcoord - delta * 2.0));
280     half4 p2b = SAMPLE_TEXTURE2D(_MainTex, sampler_MainTex, UnityStereoTransformScreenSpaceTex(i.texcoord + delta * 2.0));
281     half4 p3a = SAMPLE_TEXTURE2D(_MainTex, sampler_MainTex, UnityStereoTransformScreenSpaceTex(i.texcoord - delta * 3.2307692308));
282     half4 p3b = SAMPLE_TEXTURE2D(_MainTex, sampler_MainTex, UnityStereoTransformScreenSpaceTex(i.texcoord + delta * 3.2307692308));
284 #if defined(BLUR_SAMPLE_CENTER_NORMAL)
285     half3 n0 = SampleNormal(i.texcoordStereo);
286 #else
287     half3 n0 = GetPackedNormal(p0);
288 #endif
290     half w0  = 0.37004405286;
291     half w1a = CompareNormal(n0, GetPackedNormal(p1a)) * 0.31718061674;
292     half w1b = CompareNormal(n0, GetPackedNormal(p1b)) * 0.31718061674;
293     half w2a = CompareNormal(n0, GetPackedNormal(p2a)) * 0.19823788546;
294     half w2b = CompareNormal(n0, GetPackedNormal(p2b)) * 0.19823788546;
295     half w3a = CompareNormal(n0, GetPackedNormal(p3a)) * 0.11453744493;
296     half w3b = CompareNormal(n0, GetPackedNormal(p3b)) * 0.11453744493;
298     half s;
299     s  = GetPackedAO(p0)  * w0;
300     s += GetPackedAO(p1a) * w1a;
301     s += GetPackedAO(p1b) * w1b;
302     s += GetPackedAO(p2a) * w2a;
303     s += GetPackedAO(p2b) * w2b;
304     s += GetPackedAO(p3a) * w3a;
305     s += GetPackedAO(p3b) * w3b;
307     s /= w0 + w1a + w1b + w2a + w2b + w3a + w3b;
309 #else
311     // Fater 5-tap Gaussian with linear sampling
312     half4 p0  = SAMPLE_TEXTURE2D(_MainTex, sampler_MainTex, i.texcoordStereo);
313     half4 p1a = SAMPLE_TEXTURE2D(_MainTex, sampler_MainTex, UnityStereoTransformScreenSpaceTex(i.texcoord - delta * 1.3846153846));
314     half4 p1b = SAMPLE_TEXTURE2D(_MainTex, sampler_MainTex, UnityStereoTransformScreenSpaceTex(i.texcoord + delta * 1.3846153846));
315     half4 p2a = SAMPLE_TEXTURE2D(_MainTex, sampler_MainTex, UnityStereoTransformScreenSpaceTex(i.texcoord - delta * 3.2307692308));
316     half4 p2b = SAMPLE_TEXTURE2D(_MainTex, sampler_MainTex, UnityStereoTransformScreenSpaceTex(i.texcoord + delta * 3.2307692308));
318 #if defined(BLUR_SAMPLE_CENTER_NORMAL)
319     half3 n0 = SampleNormal(i.texcoordStereo);
320 #else
321     half3 n0 = GetPackedNormal(p0);
322 #endif
324     half w0  = 0.2270270270;
325     half w1a = CompareNormal(n0, GetPackedNormal(p1a)) * 0.3162162162;
326     half w1b = CompareNormal(n0, GetPackedNormal(p1b)) * 0.3162162162;
327     half w2a = CompareNormal(n0, GetPackedNormal(p2a)) * 0.0702702703;
328     half w2b = CompareNormal(n0, GetPackedNormal(p2b)) * 0.0702702703;
330     half s;
331     s  = GetPackedAO(p0)  * w0;
332     s += GetPackedAO(p1a) * w1a;
333     s += GetPackedAO(p1b) * w1b;
334     s += GetPackedAO(p2a) * w2a;
335     s += GetPackedAO(p2b) * w2b;
337     s /= w0 + w1a + w1b + w2a + w2b;
339 #endif
341     return PackAONormal(s, n0);
344 // Gamma encoding (only needed in gamma lighting mode)
345 half EncodeAO(half x)
347     #if UNITY_COLORSPACE_GAMMA
348         return 1.0 - max(LinearToSRGB(1.0 - saturate(x)), 0.0);
349     #else
350         return x;
351     #endif
354 // Geometry-aware bilateral filter (single pass/small kernel)
355 half BlurSmall(TEXTURE2D_ARGS(tex, samp), float2 uv, float2 delta)
357     half4 p0 = SAMPLE_TEXTURE2D(tex, samp, UnityStereoTransformScreenSpaceTex(uv));
358     half4 p1 = SAMPLE_TEXTURE2D(tex, samp, UnityStereoTransformScreenSpaceTex(uv + float2(-delta.x, -delta.y)));
359     half4 p2 = SAMPLE_TEXTURE2D(tex, samp, UnityStereoTransformScreenSpaceTex(uv + float2( delta.x, -delta.y)));
360     half4 p3 = SAMPLE_TEXTURE2D(tex, samp, UnityStereoTransformScreenSpaceTex(uv + float2(-delta.x,  delta.y)));
361     half4 p4 = SAMPLE_TEXTURE2D(tex, samp, UnityStereoTransformScreenSpaceTex(uv + float2( delta.x,  delta.y)));
363     half3 n0 = GetPackedNormal(p0);
365     half w0 = 1.0;
366     half w1 = CompareNormal(n0, GetPackedNormal(p1));
367     half w2 = CompareNormal(n0, GetPackedNormal(p2));
368     half w3 = CompareNormal(n0, GetPackedNormal(p3));
369     half w4 = CompareNormal(n0, GetPackedNormal(p4));
371     half s;
372     s  = GetPackedAO(p0) * w0;
373     s += GetPackedAO(p1) * w1;
374     s += GetPackedAO(p2) * w2;
375     s += GetPackedAO(p3) * w3;
376     s += GetPackedAO(p4) * w4;
378     return s / (w0 + w1 + w2 + w3 + w4);
381 // Final composition shader
382 float4 FragComposition(VaryingsDefault i) : SV_Target
384     float2 delta = _SAOcclusionTexture_TexelSize.xy / DOWNSAMPLE;
385     half ao = BlurSmall(TEXTURE2D_PARAM(_SAOcclusionTexture, sampler_SAOcclusionTexture), i.texcoord, delta);
386     ao = EncodeAO(ao);
387     return float4(ao * _AOColor, ao);
390 #if !SHADER_API_GLES // Excluding the MRT pass under GLES2
392 struct CompositionOutput
394     half4 gbuffer0 : SV_Target0;
395     half4 gbuffer3 : SV_Target1;
398 CompositionOutput FragCompositionGBuffer(VaryingsDefault i)
400     // Workaround: _SAOcclusionTexture_Texelsize hasn't been set properly
401     // for some reasons. Use _ScreenParams instead.
402     float2 delta = (_ScreenParams.zw - 1.0) / DOWNSAMPLE;
403     half ao = BlurSmall(TEXTURE2D_PARAM(_SAOcclusionTexture, sampler_SAOcclusionTexture), i.texcoord, delta);
405     CompositionOutput o;
406     o.gbuffer0 = half4(0.0, 0.0, 0.0, ao);
407     o.gbuffer3 = half4((half3)EncodeAO(ao) * _AOColor, 0.0);
408     return o;
411 #else
413 float4 FragCompositionGBuffer(VaryingsDefault i) : SV_Target
415     return (0.0).xxxx;
418 #endif
420 float4 FragDebugOverlay(VaryingsDefault i) : SV_Target
422     float2 delta = _SAOcclusionTexture_TexelSize.xy / DOWNSAMPLE;
423     half ao = BlurSmall(TEXTURE2D_PARAM(_SAOcclusionTexture, sampler_SAOcclusionTexture), i.texcoord, delta);
424     ao = EncodeAO(ao);
425     return float4(1.0 - ao.xxx, 1.0);
428 #endif // UNITY_POSTFX_AMBIENT_OCCLUSION