| #ifndef __TAA__ | 
| #define __TAA__ | 
|   | 
| #pragma only_renderers ps4 xboxone d3d11 d3d9 xbox360 opengl glcore | 
| #pragma exclude_renderers gles | 
|   | 
| #include "UnityCG.cginc" | 
| #include "Common.cginc" | 
|   | 
| // ----------------------------------------------------------------------------- | 
| // Solver | 
|   | 
| #define TAA_USE_STABLE_BUT_GHOSTY_VARIANT 0 | 
|   | 
| #if !defined(TAA_DILATE_MOTION_VECTOR_SAMPLE) | 
|     #define TAA_DILATE_MOTION_VECTOR_SAMPLE 1 | 
| #endif | 
|   | 
| #define TAA_FRAGMENT_MOTION_HISTORY_DECAY 0.85 | 
|   | 
| #define TAA_FINAL_BLEND_STATIC_FACTOR _FinalBlendParameters.x | 
| #define TAA_FINAL_BLEND_DYNAMIC_FACTOR _FinalBlendParameters.y | 
| #define TAA_MOTION_AMPLIFICATION _FinalBlendParameters.z | 
|   | 
| struct VaryingsSolver | 
| { | 
|     float4 vertex : SV_POSITION; | 
|     float4 uv : TEXCOORD0; // [xy: _MainTex.uv, zw: _HistoryTex.uv] | 
| }; | 
|   | 
| struct OutputSolver | 
| { | 
|     float4 destination : SV_Target0; | 
|     float4 history : SV_Target1; | 
| }; | 
|   | 
| sampler2D _HistoryTex; | 
|   | 
| sampler2D _CameraMotionVectorsTexture; | 
| sampler2D _CameraDepthTexture; | 
|   | 
| float4 _HistoryTex_TexelSize; | 
| float4 _CameraDepthTexture_TexelSize; | 
|   | 
| float2 _Jitter; | 
| float4 _SharpenParameters; | 
| float4 _FinalBlendParameters; | 
|   | 
| VaryingsSolver VertSolver(AttributesDefault input) | 
| { | 
|     VaryingsSolver output; | 
|   | 
|     float4 vertex = UnityObjectToClipPos(input.vertex); | 
|   | 
|     output.vertex = vertex; | 
|     output.uv = input.texcoord.xyxy; | 
|   | 
| #if UNITY_UV_STARTS_AT_TOP | 
|     if (_MainTex_TexelSize.y < 0) | 
|         output.uv.y = 1.0 - input.texcoord.y; | 
| #endif | 
|   | 
|     return output; | 
| } | 
|   | 
| float2 GetClosestFragment(float2 uv) | 
| { | 
|     const float2 k = _CameraDepthTexture_TexelSize.xy; | 
|     const float4 neighborhood = float4( | 
|         SAMPLE_DEPTH_TEXTURE(_CameraDepthTexture, uv - k), | 
|         SAMPLE_DEPTH_TEXTURE(_CameraDepthTexture, uv + float2(k.x, -k.y)), | 
|         SAMPLE_DEPTH_TEXTURE(_CameraDepthTexture, uv + float2(-k.x, k.y)), | 
|         SAMPLE_DEPTH_TEXTURE(_CameraDepthTexture, uv + k) | 
|         ); | 
|   | 
| #if defined(UNITY_REVERSED_Z) | 
|     #define COMPARE_DEPTH(a, b) step(b, a) | 
| #else | 
|     #define COMPARE_DEPTH(a, b) step(a, b) | 
| #endif | 
|   | 
|     float3 result = float3(0.0, 0.0, SAMPLE_DEPTH_TEXTURE(_CameraDepthTexture, uv)); | 
|     result = lerp(result, float3(-1.0, -1.0, neighborhood.x), COMPARE_DEPTH(neighborhood.x, result.z)); | 
|     result = lerp(result, float3( 1.0, -1.0, neighborhood.y), COMPARE_DEPTH(neighborhood.y, result.z)); | 
|     result = lerp(result, float3(-1.0,  1.0, neighborhood.z), COMPARE_DEPTH(neighborhood.z, result.z)); | 
|     result = lerp(result, float3( 1.0,  1.0, neighborhood.w), COMPARE_DEPTH(neighborhood.w, result.z)); | 
|   | 
|     return (uv + result.xy * k); | 
| } | 
|   | 
| // Adapted from Playdead's TAA implementation | 
| // https://github.com/playdeadgames/temporal | 
| float4 ClipToAABB(float4 color, float p, float3 minimum, float3 maximum) | 
| { | 
|     // note: only clips towards aabb center (but fast!) | 
|     float3 center  = 0.5 * (maximum + minimum); | 
|     float3 extents = 0.5 * (maximum - minimum); | 
|   | 
|     // This is actually `distance`, however the keyword is reserved | 
|     float4 offset = color - float4(center, p); | 
|     float3 repeat = abs(offset.xyz / extents); | 
|   | 
|     repeat.x = max(repeat.x, max(repeat.y, repeat.z)); | 
|   | 
|     if (repeat.x > 1.0) | 
|     { | 
|         // `color` is not intersecting (nor inside) the AABB; it's clipped to the closest extent | 
|         return float4(center, p) + offset / repeat.x; | 
|     } | 
|     else | 
|     { | 
|         // `color` is intersecting (or inside) the AABB. | 
|   | 
|         // Note: for whatever reason moving this return statement from this else into a higher | 
|         // scope makes the NVIDIA drivers go beyond bonkers | 
|         return color; | 
|     } | 
| } | 
|   | 
| OutputSolver FragSolver(VaryingsSolver input) | 
| { | 
| #if TAA_DILATE_MOTION_VECTOR_SAMPLE | 
|     float2 motion = tex2D(_CameraMotionVectorsTexture, GetClosestFragment(input.uv.zw)).xy; | 
| #else | 
|     // Don't dilate in ortho ! | 
|     float2 motion = tex2D(_CameraMotionVectorsTexture, input.uv.zw).xy; | 
| #endif | 
|   | 
|     const float2 k = _MainTex_TexelSize.xy; | 
|     float2 uv = input.uv.xy; | 
|   | 
| #if UNITY_UV_STARTS_AT_TOP | 
|     uv -= _MainTex_TexelSize.y < 0 ? _Jitter * float2(1.0, -1.0) : _Jitter; | 
| #else | 
|     uv -= _Jitter; | 
| #endif | 
|   | 
|     float4 color = tex2D(_MainTex, uv); | 
|   | 
|     float4 topLeft = tex2D(_MainTex, uv - k * 0.5); | 
|     float4 bottomRight = tex2D(_MainTex, uv + k * 0.5); | 
|   | 
|     float4 corners = 4.0 * (topLeft + bottomRight) - 2.0 * color; | 
|   | 
|     // Sharpen output | 
|     color += (color - (corners * 0.166667)) * 2.718282 * _SharpenParameters.x; | 
|     color = max(0.0, color); | 
|   | 
|     // Tonemap color and history samples | 
|     float4 average = FastToneMap((corners + color) * 0.142857); | 
|   | 
|     topLeft = FastToneMap(topLeft); | 
|     bottomRight = FastToneMap(bottomRight); | 
|   | 
|     color = FastToneMap(color); | 
|   | 
|     float4 history = tex2D(_HistoryTex, input.uv.zw - motion); | 
|   | 
| // Only use this variant for arch viz or scenes that don't have any animated objects (camera animation is fine) | 
| #if TAA_USE_STABLE_BUT_GHOSTY_VARIANT | 
|     float4 luma = float4(Luminance(topLeft.rgb), Luminance(bottomRight.rgb), Luminance(average.rgb), Luminance(color.rgb)); | 
|     float nudge = lerp(6.28318530718, 0.5, saturate(2.0 * history.a)) * max(abs(luma.z - luma.w), abs(luma.x - luma.y)); | 
|   | 
|     float4 minimum = lerp(bottomRight, topLeft, step(luma.x, luma.y)) - nudge; | 
|     float4 maximum = lerp(topLeft, bottomRight, step(luma.x, luma.y)) + nudge; | 
| #else | 
|     float2 luma = float2(Luminance(average.rgb), Luminance(color.rgb)); | 
|     float nudge = 4.0 * abs(luma.x - luma.y); | 
|   | 
|     float4 minimum = min(bottomRight, topLeft) - nudge; | 
|     float4 maximum = max(topLeft, bottomRight) + nudge; | 
| #endif | 
|   | 
|     history = FastToneMap(history); | 
|   | 
|     // Clip history samples | 
|     history = ClipToAABB(history, history.a, minimum.xyz, maximum.xyz); | 
|   | 
|     // Store fragment motion history | 
|     color.a = saturate(smoothstep(0.002 * _MainTex_TexelSize.z, 0.0035 * _MainTex_TexelSize.z, length(motion))); | 
|   | 
|     // Blend method | 
|     float weight = clamp(lerp(TAA_FINAL_BLEND_STATIC_FACTOR, TAA_FINAL_BLEND_DYNAMIC_FACTOR, | 
|         length(motion) * TAA_MOTION_AMPLIFICATION), TAA_FINAL_BLEND_DYNAMIC_FACTOR, TAA_FINAL_BLEND_STATIC_FACTOR); | 
|   | 
|     color = FastToneUnmap(lerp(color, history, weight)); | 
|   | 
|     OutputSolver output; | 
|   | 
|     output.destination = color; | 
|     color.a *= TAA_FRAGMENT_MOTION_HISTORY_DECAY; | 
|   | 
|     output.history = color; | 
|   | 
|     return output; | 
| } | 
|   | 
| // ----------------------------------------------------------------------------- | 
| // Alpha clearance | 
|   | 
| float4 FragAlphaClear(VaryingsDefault input) : SV_Target | 
| { | 
|     return float4(tex2D(_MainTex, input.uv).rgb, 0.0); | 
| } | 
|   | 
| #endif // __TAA__ |