416 lines
17 KiB
GLSL
416 lines
17 KiB
GLSL
Shader "Hidden/GameOldBoy/TAA"
|
|
{
|
|
HLSLINCLUDE
|
|
#pragma multi_compile_local_fragment _ _TAA_AntiGhosting
|
|
#pragma multi_compile_local_fragment _ _TAA_UseMotionVector
|
|
#pragma multi_compile_local_fragment _ _TAA_UseBlurSharpenFilter
|
|
#pragma multi_compile_local_fragment _ _TAA_UseBicubicFilter
|
|
#pragma multi_compile_local_fragment _ _TAA_UseClipAABB
|
|
#pragma multi_compile_local_fragment _ _TAA_UseDilation
|
|
#pragma multi_compile_local_fragment _ _TAA_UseTonemap
|
|
#pragma multi_compile_local_fragment _ _TAA_UseVarianceClipping
|
|
#pragma multi_compile_local_fragment _ _TAA_UseYCoCgSpace
|
|
#pragma multi_compile_local_fragment _ _TAA_Use4Tap
|
|
#include "Packages/com.unity.render-pipelines.core/ShaderLibrary/Common.hlsl"
|
|
#include "Packages/com.unity.render-pipelines.universal/ShaderLibrary/Core.hlsl"
|
|
#include "Packages/com.unity.render-pipelines.universal/Shaders/PostProcessing/Common.hlsl"
|
|
#include "Packages/com.unity.render-pipelines.universal/ShaderLibrary/DeclareDepthTexture.hlsl"
|
|
|
|
float4 _CameraDepthTexture_TexelSize;
|
|
TEXTURE2D_X_FLOAT(_MotionVectorTexture);
|
|
TEXTURE2D_X(_SourceTex);
|
|
float4 _SourceTex_TexelSize;
|
|
TEXTURE2D_X(_TAA_Texture);
|
|
float4 _TAA_Texture_TexelSize;
|
|
|
|
float4x4 _TAA_PrevViewProj;
|
|
float2 _TAA_Offset;
|
|
float4 _TAA_Params0;
|
|
#define _TAA_Blend _TAA_Params0.x
|
|
#define _TAA_Gamma _TAA_Params0.y
|
|
#define _TAA_Sharp _TAA_Params0.z
|
|
#define _TAA_PrevSharp _TAA_Params0.w
|
|
|
|
struct VaryingsTAA
|
|
{
|
|
float4 positionCS : SV_POSITION;
|
|
float4 uv : TEXCOORD0;
|
|
UNITY_VERTEX_OUTPUT_STEREO
|
|
};
|
|
|
|
VaryingsTAA VertTAA(Attributes input)
|
|
{
|
|
VaryingsTAA output;
|
|
UNITY_SETUP_INSTANCE_ID(input);
|
|
UNITY_INITIALIZE_VERTEX_OUTPUT_STEREO(output);
|
|
|
|
output.positionCS = TransformObjectToHClip(input.positionOS.xyz);
|
|
output.uv.xy = input.uv;
|
|
|
|
float4 projPos = output.positionCS * 0.5;
|
|
projPos.xy = projPos.xy + projPos.w;
|
|
output.uv.zw = projPos.xy;
|
|
|
|
return output;
|
|
}
|
|
|
|
#if _TAA_AntiGhosting
|
|
float3 clip_color(float3 min_color, float3 max_color, float3 color)
|
|
{
|
|
#if _TAA_UseClipAABB
|
|
float3 p_clip = 0.5 * (max_color + min_color);
|
|
float3 e_clip = 0.5 * (max_color - min_color) + FLT_EPS;
|
|
|
|
float3 v_clip = color - p_clip;
|
|
float3 v_unit = v_clip / 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 p_clip + v_clip / ma_unit;
|
|
else
|
|
return color;
|
|
#else
|
|
return clamp(color, min_color, max_color);
|
|
#endif
|
|
}
|
|
|
|
void minmax(float3 samples[9], out float3 min_color, out float3 max_color)
|
|
{
|
|
float3 color[9];
|
|
#if _TAA_UseYCoCgSpace
|
|
color[0] = RGBToYCoCg(samples[0]);
|
|
color[1] = RGBToYCoCg(samples[1]);
|
|
color[2] = RGBToYCoCg(samples[2]);
|
|
color[3] = RGBToYCoCg(samples[3]);
|
|
color[4] = RGBToYCoCg(samples[4]);
|
|
color[5] = RGBToYCoCg(samples[5]);
|
|
color[6] = RGBToYCoCg(samples[6]);
|
|
color[7] = RGBToYCoCg(samples[7]);
|
|
color[8] = RGBToYCoCg(samples[8]);
|
|
#else
|
|
color[0] = samples[0];
|
|
color[1] = samples[1];
|
|
color[2] = samples[2];
|
|
color[3] = samples[3];
|
|
color[4] = samples[4];
|
|
color[5] = samples[5];
|
|
color[6] = samples[6];
|
|
color[7] = samples[7];
|
|
color[8] = samples[8];
|
|
#endif
|
|
#if _TAA_UseVarianceClipping
|
|
float3 m1 = color[0] + color[1] + color[2]
|
|
+ color[3] + color[4] + color[5]
|
|
+ color[6] + color[7] + color[8];
|
|
float3 m2 = color[0] * color[0] + color[1] * color[1] + color[2] * color[2]
|
|
+ color[3] * color[3] + color[4] * color[4] + color[5] * color[5]
|
|
+ color[6] * color[6] + color[7] * color[7] + color[8] * color[8];
|
|
float3 mu = m1 / 9;
|
|
float3 sigma = sqrt(abs(m2 / 9 - mu * mu));
|
|
min_color = mu - _TAA_Gamma * sigma;
|
|
max_color = mu + _TAA_Gamma * sigma;
|
|
#else
|
|
min_color = min(color[0], min(color[1], min(color[2], min(color[3], min(color[4], min(color[5], min(color[6], min(color[7], color[8]))))))));
|
|
max_color = max(color[0], max(color[1], max(color[2], max(color[3], max(color[4], max(color[5], max(color[6], max(color[7], color[8]))))))));
|
|
float3 min_color5 = min(color[1], min(color[3], min(color[4], min(color[5], color[7]))));
|
|
float3 max_color5 = max(color[1], max(color[3], max(color[4], max(color[5], color[7]))));
|
|
min_color = 0.5 * (min_color + min_color5);
|
|
max_color = 0.5 * (max_color + max_color5);
|
|
#endif
|
|
}
|
|
|
|
void minmax_4tap(float2 uv, float2 mv, float depth, out float3 min_color, out float3 max_color)
|
|
{
|
|
const float _SubpixelThreshold = 0.5;
|
|
const float _GatherBase = 0.5;
|
|
const float _GatherSubpixelMotion = 0.1666;
|
|
|
|
float2 texel_vel = mv / _SourceTex_TexelSize.xy;
|
|
float texel_vel_mag = length(texel_vel) * depth;
|
|
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(-_SourceTex_TexelSize.x, _SourceTex_TexelSize.y);
|
|
float2 ss_offset11 = k_min_max_support * float2(_SourceTex_TexelSize.x, _SourceTex_TexelSize.y);
|
|
float3 c00 = SAMPLE_TEXTURE2D_X(_SourceTex,sampler_LinearClamp, uv - ss_offset11).rgb;
|
|
float3 c10 = SAMPLE_TEXTURE2D_X(_SourceTex,sampler_LinearClamp, uv - ss_offset01).rgb;
|
|
float3 c01 = SAMPLE_TEXTURE2D_X(_SourceTex,sampler_LinearClamp, uv + ss_offset01).rgb;
|
|
float3 c11 = SAMPLE_TEXTURE2D_X(_SourceTex,sampler_LinearClamp, uv + ss_offset11).rgb;
|
|
#if _TAA_UseYCoCgSpace
|
|
c00 = RGBToYCoCg(c00);
|
|
c10 = RGBToYCoCg(c10);
|
|
c01 = RGBToYCoCg(c01);
|
|
c11 = RGBToYCoCg(c11);
|
|
#endif
|
|
|
|
min_color = min(c00, min(c10, min(c01, c11)));
|
|
max_color = max(c00, max(c10, max(c01, c11)));
|
|
}
|
|
#endif
|
|
|
|
float3 filter(float3 _sample)
|
|
{
|
|
return _sample;
|
|
}
|
|
|
|
float3 filter(float3 samples[9])
|
|
{
|
|
#if _TAA_UseBlurSharpenFilter
|
|
const float k_blur0 = 0.6915221;
|
|
const float k_blur1 = 0.07002799;
|
|
const float k_blur2 = 0.007091487;
|
|
float3 blur_color = (samples[0] + samples[2] + samples[6] + samples[8]) * k_blur2 +
|
|
(samples[1] + samples[3] + samples[5] + samples[7]) * k_blur1 +
|
|
samples[4] * k_blur0;
|
|
float3 avg_color = (samples[0] + samples[1] + samples[2]
|
|
+ samples[3] + samples[4] + samples[5]
|
|
+ samples[6] + samples[7] + samples[8]) / 9;
|
|
float3 sharp_color = blur_color + (blur_color - avg_color) * _TAA_Sharp * 3;
|
|
return clamp(sharp_color, 0, 65472.0);
|
|
#else
|
|
return samples[4];
|
|
#endif
|
|
}
|
|
|
|
void get_samples(float2 uv, out float3 _sample)
|
|
{
|
|
_sample = SAMPLE_TEXTURE2D_X(_SourceTex, sampler_PointClamp, uv).rgb;
|
|
}
|
|
|
|
void get_samples(float2 uv, out float3 samples[9])
|
|
{
|
|
samples[0] = SAMPLE_TEXTURE2D_X(_SourceTex, sampler_PointClamp, uv + _SourceTex_TexelSize.xy * float2(-1, -1)).rgb;
|
|
samples[1] = SAMPLE_TEXTURE2D_X(_SourceTex, sampler_PointClamp, uv + _SourceTex_TexelSize.xy * float2( 0, -1)).rgb;
|
|
samples[2] = SAMPLE_TEXTURE2D_X(_SourceTex, sampler_PointClamp, uv + _SourceTex_TexelSize.xy * float2( 1, -1)).rgb;
|
|
samples[3] = SAMPLE_TEXTURE2D_X(_SourceTex, sampler_PointClamp, uv + _SourceTex_TexelSize.xy * float2(-1, 0)).rgb;
|
|
get_samples(uv, samples[4]);
|
|
samples[5] = SAMPLE_TEXTURE2D_X(_SourceTex, sampler_PointClamp, uv + _SourceTex_TexelSize.xy * float2( 1, 0)).rgb;
|
|
samples[6] = SAMPLE_TEXTURE2D_X(_SourceTex, sampler_PointClamp, uv + _SourceTex_TexelSize.xy * float2(-1, 1)).rgb;
|
|
samples[7] = SAMPLE_TEXTURE2D_X(_SourceTex, sampler_PointClamp, uv + _SourceTex_TexelSize.xy * float2( 0, 1)).rgb;
|
|
samples[8] = SAMPLE_TEXTURE2D_X(_SourceTex, sampler_PointClamp, uv + _SourceTex_TexelSize.xy * float2( 1, 1)).rgb;
|
|
}
|
|
|
|
float3 sample_taa_tex(float2 uv)
|
|
{
|
|
#if _TAA_UseBicubicFilter
|
|
float2 samplePos = uv * _TAA_Texture_TexelSize.zw;
|
|
float2 tc1 = floor(samplePos - 0.5) + 0.5;
|
|
float2 f = samplePos - tc1;
|
|
float2 f2 = f * f;
|
|
float2 f3 = f * f2;
|
|
|
|
const float c = _TAA_PrevSharp;
|
|
|
|
float2 w0 = -c * f3 + 2.0 * c * f2 - c * f;
|
|
float2 w1 = (2.0 - c) * f3 - (3.0 - c) * f2 + 1.0;
|
|
float2 w2 = -(2.0 - c) * f3 + (3.0 - 2.0 * c) * f2 + c * f;
|
|
float2 w3 = c * f3 - c * f2;
|
|
|
|
float2 w12 = w1 + w2;
|
|
float2 tc0 = _TAA_Texture_TexelSize.xy * (tc1 - 1.0);
|
|
float2 tc3 = _TAA_Texture_TexelSize.xy * (tc1 + 2.0);
|
|
float2 tc12 = _TAA_Texture_TexelSize.xy * (tc1 + w2 / w12);
|
|
|
|
float3 s0 = SAMPLE_TEXTURE2D_X(_TAA_Texture, sampler_LinearClamp, float2(tc12.x, tc0.y)).rgb;
|
|
float3 s1 = SAMPLE_TEXTURE2D_X(_TAA_Texture, sampler_LinearClamp, float2(tc0.x, tc12.y)).rgb;
|
|
float3 s2 = SAMPLE_TEXTURE2D_X(_TAA_Texture, sampler_LinearClamp, float2(tc12.x, tc12.y)).rgb;
|
|
float3 s3 = SAMPLE_TEXTURE2D_X(_TAA_Texture, sampler_LinearClamp, float2(tc3.x, tc0.y)).rgb;
|
|
float3 s4 = SAMPLE_TEXTURE2D_X(_TAA_Texture, sampler_LinearClamp, float2(tc12.x, tc3.y)).rgb;
|
|
|
|
float cw0 = (w12.x * w0.y);
|
|
float cw1 = (w0.x * w12.y);
|
|
float cw2 = (w12.x * w12.y);
|
|
float cw3 = (w3.x * w12.y);
|
|
float cw4 = (w12.x * w3.y);
|
|
|
|
float3 min_color = min(s0, min(s1, s2));
|
|
min_color = min(min_color, min(s3, s4));
|
|
|
|
float3 max_color = max(s0, max(s1, s2));
|
|
max_color = max(max_color, max(s3, s4));
|
|
|
|
s0 *= cw0;
|
|
s1 *= cw1;
|
|
s2 *= cw2;
|
|
s3 *= cw3;
|
|
s4 *= cw4;
|
|
|
|
float3 historyFiltered = s0 + s1 + s2 + s3 + s4;
|
|
float weightSum = cw0 + cw1 + cw2 + cw3 + cw4;
|
|
|
|
float3 filteredVal = historyFiltered * rcp(weightSum);
|
|
|
|
return clamp(filteredVal, min_color, max_color);
|
|
#else
|
|
return SAMPLE_TEXTURE2D_X(_TAA_Texture, sampler_LinearClamp, uv).rgb;
|
|
#endif
|
|
}
|
|
|
|
float3 ReinhardToneMap(float3 c)
|
|
{
|
|
return c * rcp(Luminance(c) + 1.0);
|
|
}
|
|
|
|
float3 InverseReinhardToneMap(float3 c)
|
|
{
|
|
return c * rcp(1.0 - Luminance(c));
|
|
}
|
|
|
|
#if UNITY_REVERSED_Z
|
|
#define ZCMP_GT(a, b) (a < b)
|
|
#else
|
|
#define ZCMP_GT(a, b) (a > b)
|
|
#endif
|
|
|
|
float2 find_closest_uv(float depth, float2 uv)
|
|
{
|
|
float2 dd = _CameraDepthTexture_TexelSize.xy;
|
|
float2 du = float2(dd.x, 0.0);
|
|
float2 dv = float2(0.0, dd.y);
|
|
|
|
float3 dtl = float3(-1, -1, SAMPLE_TEXTURE2D_X(_CameraDepthTexture, sampler_PointClamp, uv - dv - du).r);
|
|
float3 dtc = float3( 0, -1, SAMPLE_TEXTURE2D_X(_CameraDepthTexture, sampler_PointClamp, uv - dv).r);
|
|
float3 dtr = float3( 1, -1, SAMPLE_TEXTURE2D_X(_CameraDepthTexture, sampler_PointClamp, uv - dv + du).r);
|
|
|
|
float3 dml = float3(-1, 0, SAMPLE_TEXTURE2D_X(_CameraDepthTexture, sampler_PointClamp, uv - du).r);
|
|
float3 dmc = float3( 0, 0, depth);
|
|
float3 dmr = float3( 1, 0, SAMPLE_TEXTURE2D_X(_CameraDepthTexture, sampler_PointClamp, uv + du).r);
|
|
|
|
float3 dbl = float3(-1, 1, SAMPLE_TEXTURE2D_X(_CameraDepthTexture, sampler_PointClamp, uv + dv - du).r);
|
|
float3 dbc = float3( 0, 1, SAMPLE_TEXTURE2D_X(_CameraDepthTexture, sampler_PointClamp, uv + dv).r);
|
|
float3 dbr = float3( 1, 1, SAMPLE_TEXTURE2D_X(_CameraDepthTexture, sampler_PointClamp, uv + dv + du).r);
|
|
|
|
float3 dmin = dtl;
|
|
if (ZCMP_GT(dmin.z, dtc.z)) dmin = dtc;
|
|
if (ZCMP_GT(dmin.z, dtr.z)) dmin = dtr;
|
|
|
|
if (ZCMP_GT(dmin.z, dml.z)) dmin = dml;
|
|
if (ZCMP_GT(dmin.z, dmc.z)) dmin = dmc;
|
|
if (ZCMP_GT(dmin.z, dmr.z)) dmin = dmr;
|
|
|
|
if (ZCMP_GT(dmin.z, dbl.z)) dmin = dbl;
|
|
if (ZCMP_GT(dmin.z, dbc.z)) dmin = dbc;
|
|
if (ZCMP_GT(dmin.z, dbr.z)) dmin = dbr;
|
|
|
|
return uv + dd.xy * dmin.xy;
|
|
}
|
|
|
|
float2 reprojection(float depth, float2 uv)
|
|
{
|
|
#if UNITY_REVERSED_Z
|
|
depth = 1.0 - depth;
|
|
#endif
|
|
|
|
depth = 2.0 * depth - 1.0;
|
|
|
|
float3 viewPos = ComputeViewSpacePosition(uv, depth, unity_CameraInvProjection);
|
|
float4 worldPos = float4(mul(unity_CameraToWorld, float4(viewPos, 1.0)).xyz, 1.0);
|
|
|
|
float4 prevClipPos = mul(_TAA_PrevViewProj, worldPos);
|
|
float2 prevPosCS = prevClipPos.xy / prevClipPos.w;
|
|
return prevPosCS * 0.5 + 0.5;
|
|
}
|
|
|
|
float4 Frag(VaryingsTAA input) : SV_Target
|
|
{
|
|
UNITY_SETUP_STEREO_EYE_INDEX_POST_VERTEX(input);
|
|
float2 uv = UnityStereoTransformScreenSpaceTex(input.uv.xy);
|
|
float depth = SAMPLE_TEXTURE2D_X(_CameraDepthTexture, sampler_PointClamp, uv).r;
|
|
#if _TAA_UseMotionVector
|
|
#if _TAA_UseDilation
|
|
float2 mv = SAMPLE_TEXTURE2D_X(_MotionVectorTexture, sampler_LinearClamp, find_closest_uv(depth, uv)).rg;
|
|
#else
|
|
float2 mv = SAMPLE_TEXTURE2D_X(_MotionVectorTexture, sampler_LinearClamp, uv).rg;
|
|
#endif
|
|
float2 prev_uv = uv - mv - _TAA_Offset;
|
|
mv = uv - prev_uv;
|
|
#else
|
|
float2 prev_uv = reprojection(depth, input.uv.zw);
|
|
float2 mv = uv - prev_uv;
|
|
#endif
|
|
#if _TAA_Use4Tap
|
|
float3 samples;
|
|
#else
|
|
float3 samples[9];
|
|
#endif
|
|
get_samples(uv, samples);
|
|
if (prev_uv.x > 1.0 || prev_uv.y > 1.0 || prev_uv.x < 0.0 || prev_uv.y < 0.0)
|
|
{
|
|
return float4(max(float3(0.0, 0.0, 0.0), filter(samples)), 1.0);
|
|
}
|
|
float3 prev_color = sample_taa_tex(prev_uv);
|
|
#if _TAA_AntiGhosting
|
|
float3 min_color, max_color;
|
|
#if _TAA_Use4Tap
|
|
minmax_4tap(uv, mv, depth, min_color, max_color);
|
|
#else
|
|
minmax(samples, min_color, max_color);
|
|
#endif
|
|
#if _TAA_UseYCoCgSpace
|
|
prev_color = YCoCgToRGB(clip_color(min_color, max_color, RGBToYCoCg(prev_color)));
|
|
#else
|
|
prev_color = clip_color(min_color, max_color, prev_color);
|
|
#endif
|
|
#endif
|
|
float final_blend = lerp(_TAA_Blend, 0.2, saturate(length(mv) * 20.0));
|
|
#if _TAA_UseTonemap
|
|
float3 color = ReinhardToneMap(filter(samples));
|
|
prev_color = ReinhardToneMap(prev_color);
|
|
float3 final_color = InverseReinhardToneMap(lerp(color, prev_color, final_blend));
|
|
#else
|
|
float3 color = filter(samples);
|
|
float3 final_color = lerp(color, prev_color, final_blend);
|
|
#endif
|
|
return float4(max(float3(0.0, 0.0, 0.0), final_color), 1.0);
|
|
}
|
|
|
|
Varyings VertBlit(Attributes input)
|
|
{
|
|
Varyings output;
|
|
UNITY_SETUP_INSTANCE_ID(input);
|
|
UNITY_INITIALIZE_VERTEX_OUTPUT_STEREO(output);
|
|
|
|
output.positionCS = TransformObjectToHClip(input.positionOS.xyz);
|
|
output.uv = input.uv;
|
|
|
|
return output;
|
|
}
|
|
|
|
half4 FragBlit(Varyings input) : SV_Target
|
|
{
|
|
UNITY_SETUP_STEREO_EYE_INDEX_POST_VERTEX(input);
|
|
float2 uv = UnityStereoTransformScreenSpaceTex(input.uv);
|
|
return half4(SAMPLE_TEXTURE2D_X(_SourceTex, sampler_PointClamp, uv).rgb, 1.0);
|
|
}
|
|
|
|
ENDHLSL
|
|
|
|
SubShader
|
|
{
|
|
Tags{ "RenderType" = "Opaque" "RenderPipeline" = "UniversalPipeline" }
|
|
LOD 100
|
|
ZTest Always ZWrite Off Cull Off
|
|
|
|
Pass // Index 0
|
|
{
|
|
Name "TAA"
|
|
|
|
HLSLPROGRAM
|
|
#pragma vertex VertTAA
|
|
#pragma fragment Frag
|
|
ENDHLSL
|
|
}
|
|
|
|
Pass // Index 1
|
|
{
|
|
Name "Blit"
|
|
|
|
HLSLPROGRAM
|
|
#pragma vertex VertBlit
|
|
#pragma fragment FragBlit
|
|
ENDHLSL
|
|
}
|
|
}
|
|
}
|