#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__ 
 |