|
|
- // Upgrade NOTE: replaced 'mul(UNITY_MATRIX_MVP,*)' with 'UnityObjectToClipPos(*)'
-
- // Copyright (c) <2015> <Playdead>
- // This file is subject to the MIT License as seen in the root of this folder structure (LICENSE.TXT)
- // AUTHOR: Lasse Jon Fuglsang Pedersen <lasse@playdead.com>
-
- Shader "Hidden/TAA"
- {
- Properties
- {
- _MainTex ("Base (RGB)", 2D) = "white" {}
- }
-
- CGINCLUDE
- //--- program begin
-
- #pragma only_renderers ps4 xboxone d3d11 d3d9 xbox360 opengl glcore gles3 metal vulkan
- #pragma target 3.0
-
- #pragma multi_compile CAMERA_PERSPECTIVE CAMERA_ORTHOGRAPHIC
- #pragma multi_compile MINMAX_3X3 MINMAX_3X3_ROUNDED MINMAX_4TAP_VARYING
- #pragma multi_compile __ UNJITTER_COLORSAMPLES
- #pragma multi_compile __ UNJITTER_NEIGHBORHOOD
- #pragma multi_compile __ UNJITTER_REPROJECTION
- #pragma multi_compile __ USE_YCOCG
- #pragma multi_compile __ USE_CLIPPING
- #pragma multi_compile __ USE_DILATION
- #pragma multi_compile __ USE_MOTION_BLUR
- #pragma multi_compile __ USE_MOTION_BLUR_NEIGHBORMAX
- #pragma multi_compile __ USE_OPTIMIZATIONS
-
- #include "UnityCG.cginc"
- #include "IncDepth.cginc"
- #include "IncNoise.cginc"
-
- #if SHADER_API_MOBILE
- static const float FLT_EPS = 0.0001f;
- #else
- static const float FLT_EPS = 0.00000001f;
- #endif
-
- uniform float4 _JitterUV;// frustum jitter uv deltas, where xy = current frame, zw = previous
-
- uniform sampler2D _MainTex;
- uniform float4 _MainTex_TexelSize;
-
- uniform sampler2D_half _VelocityBuffer;
- uniform sampler2D _VelocityNeighborMax;
-
- uniform sampler2D _PrevTex;
- uniform float _FeedbackMin;
- uniform float _FeedbackMax;
- uniform float _MotionScale;
-
- struct v2f
- {
- float4 cs_pos : SV_POSITION;
- float2 ss_txc : TEXCOORD0;
- };
-
- v2f vert(appdata_img IN)
- {
- v2f OUT;
-
- #if UNITY_VERSION < 540
- OUT.cs_pos = UnityObjectToClipPos(IN.vertex);
- #else
- OUT.cs_pos = UnityObjectToClipPos(IN.vertex);
- #endif
- #if UNITY_SINGLE_PASS_STEREO
- OUT.ss_txc = UnityStereoTransformScreenSpaceTex(IN.texcoord.xy);
- #else
- OUT.ss_txc = IN.texcoord.xy;
- #endif
-
- return OUT;
- }
-
- // https://software.intel.com/en-us/node/503873
- float3 RGB_YCoCg(float3 c)
- {
- // Y = R/4 + G/2 + B/4
- // Co = R/2 - B/2
- // Cg = -R/4 + G/2 - B/4
- return float3(
- c.x/4.0 + c.y/2.0 + c.z/4.0,
- c.x/2.0 - c.z/2.0,
- -c.x/4.0 + c.y/2.0 - c.z/4.0
- );
- }
-
- // https://software.intel.com/en-us/node/503873
- float3 YCoCg_RGB(float3 c)
- {
- // R = Y + Co - Cg
- // G = Y + Cg
- // B = Y - Co - Cg
- return saturate(float3(
- c.x + c.y - c.z,
- c.x + c.z,
- c.x - c.y - c.z
- ));
- }
-
- float4 sample_color(sampler2D tex, float2 uv)
- {
- #if USE_YCOCG
- float4 c = tex2D(tex, uv);
- return float4(RGB_YCoCg(c.rgb), c.a);
- #else
- return tex2D(tex, uv);
- #endif
- }
-
- float4 resolve_color(float4 c)
- {
- #if USE_YCOCG
- return float4(YCoCg_RGB(c.rgb).rgb, c.a);
- #else
- return c;
- #endif
- }
-
- float4 clip_aabb(float3 aabb_min, float3 aabb_max, float4 p, float4 q)
- {
- #if USE_OPTIMIZATIONS
- // note: only clips towards aabb center (but fast!)
- float3 p_clip = 0.5 * (aabb_max + aabb_min);
- float3 e_clip = 0.5 * (aabb_max - aabb_min) + FLT_EPS;
-
- float4 v_clip = q - float4(p_clip, p.w);
- float3 v_unit = v_clip.xyz / e_clip;
- float3 a_unit = abs(v_unit);
- float ma_unit = max(a_unit.x, max(a_unit.y, a_unit.z));
-
- if (ma_unit > 1.0)
- return float4(p_clip, p.w) + v_clip / ma_unit;
- else
- return q;// point inside aabb
- #else
- float4 r = q - p;
- float3 rmax = aabb_max - p.xyz;
- float3 rmin = aabb_min - p.xyz;
-
- const float eps = FLT_EPS;
-
- if (r.x > rmax.x + eps)
- r *= (rmax.x / r.x);
- if (r.y > rmax.y + eps)
- r *= (rmax.y / r.y);
- if (r.z > rmax.z + eps)
- r *= (rmax.z / r.z);
-
- if (r.x < rmin.x - eps)
- r *= (rmin.x / r.x);
- if (r.y < rmin.y - eps)
- r *= (rmin.y / r.y);
- if (r.z < rmin.z - eps)
- r *= (rmin.z / r.z);
-
- return p + r;
- #endif
- }
-
- float2 sample_velocity_dilated(sampler2D tex, float2 uv, int support)
- {
- float2 du = float2(_MainTex_TexelSize.x, 0.0);
- float2 dv = float2(0.0, _MainTex_TexelSize.y);
- float2 mv = 0.0;
- float rmv = 0.0;
-
- int end = support + 1;
- for (int i = -support; i != end; i++)
- {
- for (int j = -support; j != end; j++)
- {
- float2 v = tex2D(tex, uv + i * dv + j * du).xy;
- float rv = dot(v, v);
- if (rv > rmv)
- {
- mv = v;
- rmv = rv;
- }
- }
- }
-
- return mv;
- }
-
- float4 sample_color_motion(sampler2D tex, float2 uv, float2 ss_vel)
- {
- const float2 v = 0.5 * ss_vel;
- const int taps = 3;// on either side!
-
- float srand = PDsrand(uv + _SinTime.xx);
- float2 vtap = v / taps;
- float2 pos0 = uv + vtap * (0.5 * srand);
- float4 accu = 0.0;
- float wsum = 0.0;
-
- [unroll]
- for (int i = -taps; i <= taps; i++)
- {
- float w = 1.0;// box
- //float w = taps - abs(i) + 1;// triangle
- //float w = 1.0 / (1 + abs(i));// pointy triangle
- accu += w * sample_color(tex, pos0 + i * vtap);
- wsum += w;
- }
-
- return accu / wsum;
- }
-
- float4 temporal_reprojection(float2 ss_txc, float2 ss_vel, float vs_dist)
- {
- // read texels
- #if UNJITTER_COLORSAMPLES
- float4 texel0 = sample_color(_MainTex, ss_txc - _JitterUV.xy);
- #else
- float4 texel0 = sample_color(_MainTex, ss_txc);
- #endif
- float4 texel1 = sample_color(_PrevTex, ss_txc - ss_vel);
-
- // calc min-max of current neighbourhood
- #if UNJITTER_NEIGHBORHOOD
- float2 uv = ss_txc - _JitterUV.xy;
- #else
- float2 uv = ss_txc;
- #endif
-
- #if MINMAX_3X3 || MINMAX_3X3_ROUNDED
-
- float2 du = float2(_MainTex_TexelSize.x, 0.0);
- float2 dv = float2(0.0, _MainTex_TexelSize.y);
-
- float4 ctl = sample_color(_MainTex, uv - dv - du);
- float4 ctc = sample_color(_MainTex, uv - dv);
- float4 ctr = sample_color(_MainTex, uv - dv + du);
- float4 cml = sample_color(_MainTex, uv - du);
- float4 cmc = sample_color(_MainTex, uv);
- float4 cmr = sample_color(_MainTex, uv + du);
- float4 cbl = sample_color(_MainTex, uv + dv - du);
- float4 cbc = sample_color(_MainTex, uv + dv);
- float4 cbr = sample_color(_MainTex, uv + dv + du);
-
- float4 cmin = min(ctl, min(ctc, min(ctr, min(cml, min(cmc, min(cmr, min(cbl, min(cbc, cbr))))))));
- float4 cmax = max(ctl, max(ctc, max(ctr, max(cml, max(cmc, max(cmr, max(cbl, max(cbc, cbr))))))));
-
- #if MINMAX_3X3_ROUNDED || USE_YCOCG || USE_CLIPPING
- float4 cavg = (ctl + ctc + ctr + cml + cmc + cmr + cbl + cbc + cbr) / 9.0;
- #endif
-
- #if MINMAX_3X3_ROUNDED
- float4 cmin5 = min(ctc, min(cml, min(cmc, min(cmr, cbc))));
- float4 cmax5 = max(ctc, max(cml, max(cmc, max(cmr, cbc))));
- float4 cavg5 = (ctc + cml + cmc + cmr + cbc) / 5.0;
- cmin = 0.5 * (cmin + cmin5);
- cmax = 0.5 * (cmax + cmax5);
- cavg = 0.5 * (cavg + cavg5);
- #endif
-
- #elif MINMAX_4TAP_VARYING// this is the method used in v2 (PDTemporalReprojection2)
-
- const float _SubpixelThreshold = 0.5;
- const float _GatherBase = 0.5;
- const float _GatherSubpixelMotion = 0.1666;
-
- float2 texel_vel = ss_vel / _MainTex_TexelSize.xy;
- float texel_vel_mag = length(texel_vel) * vs_dist;
- float k_subpixel_motion = saturate(_SubpixelThreshold / (FLT_EPS + texel_vel_mag));
- float k_min_max_support = _GatherBase + _GatherSubpixelMotion * k_subpixel_motion;
-
- float2 ss_offset01 = k_min_max_support * float2(-_MainTex_TexelSize.x, _MainTex_TexelSize.y);
- float2 ss_offset11 = k_min_max_support * float2(_MainTex_TexelSize.x, _MainTex_TexelSize.y);
- float4 c00 = sample_color(_MainTex, uv - ss_offset11);
- float4 c10 = sample_color(_MainTex, uv - ss_offset01);
- float4 c01 = sample_color(_MainTex, uv + ss_offset01);
- float4 c11 = sample_color(_MainTex, uv + ss_offset11);
-
- float4 cmin = min(c00, min(c10, min(c01, c11)));
- float4 cmax = max(c00, max(c10, max(c01, c11)));
-
- #if USE_YCOCG || USE_CLIPPING
- float4 cavg = (c00 + c10 + c01 + c11) / 4.0;
- #endif
-
- #else
- #error "missing keyword MINMAX_..."
- #endif
-
- // shrink chroma min-max
- #if USE_YCOCG
- float2 chroma_extent = 0.25 * 0.5 * (cmax.r - cmin.r);
- float2 chroma_center = texel0.gb;
- cmin.yz = chroma_center - chroma_extent;
- cmax.yz = chroma_center + chroma_extent;
- cavg.yz = chroma_center;
- #endif
-
- // clamp to neighbourhood of current sample
- #if USE_CLIPPING
- texel1 = clip_aabb(cmin.xyz, cmax.xyz, clamp(cavg, cmin, cmax), texel1);
- #else
- texel1 = clamp(texel1, cmin, cmax);
- #endif
-
- // feedback weight from unbiased luminance diff (t.lottes)
- #if USE_YCOCG
- float lum0 = texel0.r;
- float lum1 = texel1.r;
- #else
- float lum0 = Luminance(texel0.rgb);
- float lum1 = Luminance(texel1.rgb);
- #endif
- float unbiased_diff = abs(lum0 - lum1) / max(lum0, max(lum1, 0.2));
- float unbiased_weight = 1.0 - unbiased_diff;
- float unbiased_weight_sqr = unbiased_weight * unbiased_weight;
- float k_feedback = lerp(_FeedbackMin, _FeedbackMax, unbiased_weight_sqr);
-
- // output
- return lerp(texel0, texel1, k_feedback);
- }
-
- struct f2rt
- {
- fixed4 buffer : SV_Target0;
- fixed4 screen : SV_Target1;
- };
-
- f2rt frag(v2f IN)
- {
- f2rt OUT;
-
- #if UNJITTER_REPROJECTION
- float2 uv = IN.ss_txc - _JitterUV.xy;
- #else
- float2 uv = IN.ss_txc;
- #endif
-
- #if USE_DILATION
- //--- 3x3 norm (sucks)
- //float2 ss_vel = sample_velocity_dilated(_VelocityBuffer, uv, 1);
- //float vs_dist = depth_sample_linear(uv);
-
- //--- 5 tap nearest (decent)
- //float3 c_frag = find_closest_fragment_5tap(uv);
- //float2 ss_vel = tex2D(_VelocityBuffer, c_frag.xy).xy;
- //float vs_dist = depth_resolve_linear(c_frag.z);
-
- //--- 3x3 nearest (good)
- float3 c_frag = find_closest_fragment_3x3(uv);
- float2 ss_vel = tex2D(_VelocityBuffer, c_frag.xy).xy;
- float vs_dist = depth_resolve_linear(c_frag.z);
- #else
- float2 ss_vel = tex2D(_VelocityBuffer, uv).xy;
- float vs_dist = depth_sample_linear(uv);
- #endif
-
- // temporal resolve
- float4 color_temporal = temporal_reprojection(IN.ss_txc, ss_vel, vs_dist);
-
- // prepare outputs
- float4 to_buffer = resolve_color(color_temporal);
-
- #if USE_MOTION_BLUR
- #if USE_MOTION_BLUR_NEIGHBORMAX
- ss_vel = _MotionScale * tex2D(_VelocityNeighborMax, IN.ss_txc).xy;
- #else
- ss_vel = _MotionScale * ss_vel;
- #endif
-
- float vel_mag = length(ss_vel * _MainTex_TexelSize.zw);
- const float vel_trust_full = 2.0;
- const float vel_trust_none = 15.0;
- const float vel_trust_span = vel_trust_none - vel_trust_full;
- float trust = 1.0 - clamp(vel_mag - vel_trust_full, 0.0, vel_trust_span) / vel_trust_span;
-
- #if UNJITTER_COLORSAMPLES
- float4 color_motion = sample_color_motion(_MainTex, IN.ss_txc - _JitterUV.xy, ss_vel);
- #else
- float4 color_motion = sample_color_motion(_MainTex, IN.ss_txc, ss_vel);
- #endif
-
- float4 to_screen = resolve_color(lerp(color_motion, color_temporal, trust));
- #else
- float4 to_screen = resolve_color(color_temporal);
- #endif
-
- //// NOTE: velocity debug
- //to_screen.g += 100.0 * length(ss_vel);
- //to_screen = float4(100.0 * abs(ss_vel), 0.0, 0.0);
-
- // add noise
- float4 noise4 = PDsrand4(IN.ss_txc + _SinTime.x + 0.6959174) / 510.0;
- OUT.buffer = saturate(to_buffer /*+ noise4*/);
- //OUT.screen = saturate(to_screen + noise4);
- OUT.screen = saturate(to_screen /*+ noise4*/)/* * float4(1,.2,0,1)*/;
- //OUT.screen = float4(vs_dist, vs_dist, vs_dist,1);
- // done
- return OUT;
- }
-
- //--- program end
- ENDCG
-
- SubShader
- {
- ZTest Always Cull Off ZWrite Off
- Fog { Mode off }
-
- Pass
- {
- CGPROGRAM
-
- #pragma vertex vert
- #pragma fragment frag
-
- ENDCG
- }
- }
-
- Fallback off
- }
|