Shader "Hidden/Post FX/Uber Shader" { Properties { _MainTex ("Texture", 2D) = "white" {} _AutoExposure ("", 2D) = "" {} _BloomTex ("", 2D) = "" {} _Bloom_DirtTex ("", 2D) = "" {} _GrainTex ("", 2D) = "" {} _LogLut ("", 2D) = "" {} _UserLut ("", 2D) = "" {} _Vignette_Mask ("", 2D) = "" {} _ChromaticAberration_Spectrum ("", 2D) = "" {} _DitheringTex ("", 2D) = "" {} } CGINCLUDE #pragma target 3.0 #pragma multi_compile __ UNITY_COLORSPACE_GAMMA #pragma multi_compile __ CHROMATIC_ABERRATION #pragma multi_compile __ DEPTH_OF_FIELD DEPTH_OF_FIELD_COC_VIEW #pragma multi_compile __ BLOOM BLOOM_LENS_DIRT #pragma multi_compile __ COLOR_GRADING COLOR_GRADING_LOG_VIEW #pragma multi_compile __ USER_LUT #pragma multi_compile __ GRAIN #pragma multi_compile __ VIGNETTE_CLASSIC VIGNETTE_MASKED #pragma multi_compile __ DITHERING #include "UnityCG.cginc" #include "Bloom.cginc" #include "ColorGrading.cginc" #include "UberSecondPass.cginc" // Auto exposure / eye adaptation sampler2D _AutoExposure; // Chromatic aberration half _ChromaticAberration_Amount; sampler2D _ChromaticAberration_Spectrum; // Depth of field sampler2D_float _CameraDepthTexture; sampler2D _DepthOfFieldTex; sampler2D _DepthOfFieldCoCTex; float4 _DepthOfFieldTex_TexelSize; float3 _DepthOfFieldParams; // x: distance, y: f^2 / (N * (S1 - f) * film_width * 2), z: max coc // Bloom sampler2D _BloomTex; float4 _BloomTex_TexelSize; half2 _Bloom_Settings; // x: sampleScale, y: bloom.intensity sampler2D _Bloom_DirtTex; half _Bloom_DirtIntensity; // Color grading & tonemapping sampler2D _LogLut; half3 _LogLut_Params; // x: 1 / lut_width, y: 1 / lut_height, z: lut_height - 1 half _ExposureEV; // EV (exp2) // User lut sampler2D _UserLut; half4 _UserLut_Params; // @see _LogLut_Params // Vignette half3 _Vignette_Color; half2 _Vignette_Center; // UV space half4 _Vignette_Settings; // x: intensity, y: smoothness, z: roundness, w: rounded sampler2D _Vignette_Mask; half _Vignette_Opacity; // [0;1] struct VaryingsFlipped { float4 pos : SV_POSITION; float2 uv : TEXCOORD0; float2 uvSPR : TEXCOORD1; // Single Pass Stereo UVs float2 uvFlipped : TEXCOORD2; // Flipped UVs (DX/MSAA/Forward) float2 uvFlippedSPR : TEXCOORD3; // Single Pass Stereo flipped UVs }; VaryingsFlipped VertUber(AttributesDefault v) { VaryingsFlipped o; o.pos = UnityObjectToClipPos(v.vertex); o.uv = v.texcoord.xy; o.uvSPR = UnityStereoScreenSpaceUVAdjust(v.texcoord.xy, _MainTex_ST); o.uvFlipped = v.texcoord.xy; #if UNITY_UV_STARTS_AT_TOP if (_MainTex_TexelSize.y < 0.0) o.uvFlipped.y = 1.0 - o.uvFlipped.y; #endif o.uvFlippedSPR = UnityStereoScreenSpaceUVAdjust(o.uvFlipped, _MainTex_ST); return o; } half4 FragUber(VaryingsFlipped i) : SV_Target { float2 uv = i.uv; half autoExposure = tex2D(_AutoExposure, uv).r; half3 color = (0.0).xxx; #if DEPTH_OF_FIELD && CHROMATIC_ABERRATION half4 dof = (0.0).xxxx; half ffa = 0.0; // far field alpha #endif // // HDR effects // --------------------------------------------------------- // Chromatic Aberration // Inspired by the method described in "Rendering Inside" [Playdead 2016] // https://twitter.com/pixelmager/status/717019757766123520 #if CHROMATIC_ABERRATION { float2 coords = 2.0 * uv - 1.0; float2 end = uv - coords * dot(coords, coords) * _ChromaticAberration_Amount; float2 diff = end - uv; int samples = clamp(int(length(_MainTex_TexelSize.zw * diff / 2.0)), 3, 16); float2 delta = diff / samples; float2 pos = uv; half3 sum = (0.0).xxx, filterSum = (0.0).xxx; #if DEPTH_OF_FIELD float2 dofDelta = delta; float2 dofPos = pos; if (_MainTex_TexelSize.y < 0.0) { dofDelta.y = -dofDelta.y; dofPos.y = 1.0 - dofPos.y; } half4 dofSum = (0.0).xxxx; half ffaSum = 0.0; #endif for (int i = 0; i < samples; i++) { half t = (i + 0.5) / samples; half3 s = tex2Dlod(_MainTex, float4(UnityStereoScreenSpaceUVAdjust(pos, _MainTex_ST), 0, 0)).rgb; half3 filter = tex2Dlod(_ChromaticAberration_Spectrum, float4(t, 0, 0, 0)).rgb; sum += s * filter; filterSum += filter; pos += delta; #if DEPTH_OF_FIELD float4 uvDof = float4(UnityStereoScreenSpaceUVAdjust(dofPos, _MainTex_ST), 0, 0); half4 sdof = tex2Dlod(_DepthOfFieldTex, uvDof).rgba; half scoc = tex2Dlod(_DepthOfFieldCoCTex, uvDof).r; scoc = (scoc - 0.5) * 2 * _DepthOfFieldParams.z; dofSum += sdof * half4(filter, 1); ffaSum += smoothstep(_MainTex_TexelSize.y * 2, _MainTex_TexelSize.y * 4, scoc); dofPos += dofDelta; #endif } color = sum / filterSum; #if DEPTH_OF_FIELD dof = dofSum / half4(filterSum, samples); ffa = ffaSum / samples; #endif } #else { color = tex2D(_MainTex, i.uvSPR).rgb; } #endif // Apply auto exposure if any color *= autoExposure; // Gamma space... Gah. #if UNITY_COLORSPACE_GAMMA { color = GammaToLinearSpace(color); } #endif // Depth of field #if DEPTH_OF_FIELD_COC_VIEW { // Calculate the radiuses of CoC. half4 src = tex2D(_DepthOfFieldTex, uv); float depth = LinearEyeDepth(SAMPLE_DEPTH_TEXTURE(_CameraDepthTexture, i.uvFlippedSPR)); float coc = (depth - _DepthOfFieldParams.x) * _DepthOfFieldParams.y / depth; coc *= 80; // Visualize CoC (white -> red -> gray) half3 rgb = lerp(half3(1, 0, 0), half3(1.0, 1.0, 1.0), saturate(-coc)); rgb = lerp(rgb, half3(0.4, 0.4, 0.4), saturate(coc)); // Black and white image overlay rgb *= AcesLuminance(color) + 0.5; // Gamma correction #if !UNITY_COLORSPACE_GAMMA { rgb = GammaToLinearSpace(rgb); } #endif color = rgb; } #elif DEPTH_OF_FIELD { #if !CHROMATIC_ABERRATION half4 dof = tex2D(_DepthOfFieldTex, i.uvFlippedSPR); half coc = tex2D(_DepthOfFieldCoCTex, i.uvFlippedSPR); coc = (coc - 0.5) * 2 * _DepthOfFieldParams.z; // Convert CoC to far field alpha value. float ffa = smoothstep(_MainTex_TexelSize.y * 2, _MainTex_TexelSize.y * 4, coc); #endif // lerp(lerp(color, dof, ffa), dof, dof.a) color = lerp(color, dof.rgb * autoExposure, ffa + dof.a - ffa * dof.a); } #endif // HDR Bloom #if BLOOM || BLOOM_LENS_DIRT { half3 bloom = UpsampleFilter(_BloomTex, i.uvFlippedSPR, _BloomTex_TexelSize.xy, _Bloom_Settings.x) * _Bloom_Settings.y; color += bloom; #if BLOOM_LENS_DIRT { half3 dirt = tex2D(_Bloom_DirtTex, i.uvFlipped).rgb * _Bloom_DirtIntensity; color += bloom * dirt; } #endif } #endif // Procedural vignette #if VIGNETTE_CLASSIC { half2 d = abs(uv - _Vignette_Center) * _Vignette_Settings.x; d.x *= lerp(1.0, _ScreenParams.x / _ScreenParams.y, _Vignette_Settings.w); d = pow(d, _Vignette_Settings.z); // Roundness half vfactor = pow(saturate(1.0 - dot(d, d)), _Vignette_Settings.y); color *= lerp(_Vignette_Color, (1.0).xxx, vfactor); } // Masked vignette #elif VIGNETTE_MASKED { half vfactor = tex2D(_Vignette_Mask, uv).a; half3 new_color = color * lerp(_Vignette_Color, (1.0).xxx, vfactor); color = lerp(color, new_color, _Vignette_Opacity); } #endif // HDR color grading & tonemapping #if COLOR_GRADING_LOG_VIEW { color *= _ExposureEV; color = saturate(LinearToLogC(color)); } #elif COLOR_GRADING { color *= _ExposureEV; // Exposure is in ev units (or 'stops') half3 colorLogC = saturate(LinearToLogC(color)); color = ApplyLut2d(_LogLut, colorLogC, _LogLut_Params); } #endif // // All the following effects happen in LDR // --------------------------------------------------------- color = saturate(color); // Back to gamma space if needed #if UNITY_COLORSPACE_GAMMA { color = LinearToGammaSpace(color); } #endif // LDR user lut #if USER_LUT { color = saturate(color); half3 colorGraded; #if !UNITY_COLORSPACE_GAMMA { colorGraded = ApplyLut2d(_UserLut, LinearToGammaSpace(color), _UserLut_Params.xyz); colorGraded = GammaToLinearSpace(colorGraded); } #else { colorGraded = ApplyLut2d(_UserLut, color, _UserLut_Params.xyz); } #endif color = lerp(color, colorGraded, _UserLut_Params.w); } #endif color = UberSecondPass(color, uv); // Done ! return half4(color, 1.0); } ENDCG SubShader { Cull Off ZWrite Off ZTest Always // (0) Pass { CGPROGRAM #pragma vertex VertUber #pragma fragment FragUber ENDCG } } }