Shader "Hidden/Dof/DepthOfFieldHdr" { Properties { _MainTex ("-", 2D) = "black" {} _FgOverlap ("-", 2D) = "black" {} _LowRez ("-", 2D) = "black" {} } CGINCLUDE #include "UnityCG.cginc" struct v2f { float4 pos : SV_POSITION; float2 uv : TEXCOORD0; float2 uv1 : TEXCOORD1; }; struct v2fRadius { float4 pos : SV_POSITION; float2 uv : TEXCOORD0; float4 uv1[4] : TEXCOORD1; }; struct v2fBlur { float4 pos : SV_POSITION; float2 uv : TEXCOORD0; float4 uv01 : TEXCOORD1; float4 uv23 : TEXCOORD2; float4 uv45 : TEXCOORD3; float4 uv67 : TEXCOORD4; float4 uv89 : TEXCOORD5; }; uniform sampler2D _MainTex; uniform sampler2D_float _CameraDepthTexture; uniform sampler2D _FgOverlap; uniform sampler2D _LowRez; uniform float4 _CurveParams; uniform float4 _MainTex_TexelSize; half4 _MainTex_ST; uniform float4 _Offsets; half4 _CameraDepthTexture_ST; half4 _LowRez_ST; half4 _FgOverlap_ST; v2f vert( appdata_img v ) { v2f o; o.pos = UnityObjectToClipPos(v.vertex); o.uv1.xy = v.texcoord.xy; o.uv.xy = v.texcoord.xy; #if UNITY_UV_STARTS_AT_TOP if (_MainTex_TexelSize.y < 0) o.uv.y = 1-o.uv.y; #endif return o; } v2f vertFlip( appdata_img v ) { v2f o; o.pos = UnityObjectToClipPos(v.vertex); o.uv1.xy = v.texcoord.xy; o.uv.xy = v.texcoord.xy; #if UNITY_UV_STARTS_AT_TOP if (_MainTex_TexelSize.y < 0) o.uv.y = 1-o.uv.y; if (_MainTex_TexelSize.y < 0) o.uv1.y = 1-o.uv1.y; #endif return o; } v2fBlur vertBlurPlusMinus (appdata_img v) { v2fBlur o; o.pos = UnityObjectToClipPos(v.vertex); o.uv.xy = UnityStereoScreenSpaceUVAdjust(v.texcoord.xy, _MainTex_ST); o.uv01 = UnityStereoScreenSpaceUVAdjust(v.texcoord.xyxy + _Offsets.xyxy * float4(1,1, -1,-1) * _MainTex_TexelSize.xyxy / 6.0, _MainTex_ST); o.uv23 = UnityStereoScreenSpaceUVAdjust(v.texcoord.xyxy + _Offsets.xyxy * float4(2,2, -2,-2) * _MainTex_TexelSize.xyxy / 6.0, _MainTex_ST); o.uv45 = UnityStereoScreenSpaceUVAdjust(v.texcoord.xyxy + _Offsets.xyxy * float4(3,3, -3,-3) * _MainTex_TexelSize.xyxy / 6.0, _MainTex_ST); o.uv67 = UnityStereoScreenSpaceUVAdjust(v.texcoord.xyxy + _Offsets.xyxy * float4(4,4, -4,-4) * _MainTex_TexelSize.xyxy / 6.0, _MainTex_ST); o.uv89 = UnityStereoScreenSpaceUVAdjust(v.texcoord.xyxy + _Offsets.xyxy * float4(5,5, -5,-5) * _MainTex_TexelSize.xyxy / 6.0, _MainTex_ST); return o; } #define SCATTER_OVERLAP_SMOOTH (-0.265) inline float BokehWeightDisc(float4 theSample, float sampleDistance, float4 centerSample) { return smoothstep(SCATTER_OVERLAP_SMOOTH, 0.0, theSample.a - centerSample.a*sampleDistance); } inline float2 BokehWeightDisc2(float4 sampleA, float4 sampleB, float2 sampleDistance2, float4 centerSample) { return smoothstep(float2(SCATTER_OVERLAP_SMOOTH, SCATTER_OVERLAP_SMOOTH), float2(0.0,0.0), float2(sampleA.a, sampleB.a) - centerSample.aa*sampleDistance2); } static const int SmallDiscKernelSamples = 12; static const float2 SmallDiscKernel[SmallDiscKernelSamples] = { float2(-0.326212,-0.40581), float2(-0.840144,-0.07358), float2(-0.695914,0.457137), float2(-0.203345,0.620716), float2(0.96234,-0.194983), float2(0.473434,-0.480026), float2(0.519456,0.767022), float2(0.185461,-0.893124), float2(0.507431,0.064425), float2(0.89642,0.412458), float2(-0.32194,-0.932615), float2(-0.791559,-0.59771) }; static const int NumDiscSamples = 28; static const float3 DiscKernel[NumDiscSamples] = { float3(0.62463,0.54337,0.82790), float3(-0.13414,-0.94488,0.95435), float3(0.38772,-0.43475,0.58253), float3(0.12126,-0.19282,0.22778), float3(-0.20388,0.11133,0.23230), float3(0.83114,-0.29218,0.88100), float3(0.10759,-0.57839,0.58831), float3(0.28285,0.79036,0.83945), float3(-0.36622,0.39516,0.53876), float3(0.75591,0.21916,0.78704), float3(-0.52610,0.02386,0.52664), float3(-0.88216,-0.24471,0.91547), float3(-0.48888,-0.29330,0.57011), float3(0.44014,-0.08558,0.44838), float3(0.21179,0.51373,0.55567), float3(0.05483,0.95701,0.95858), float3(-0.59001,-0.70509,0.91938), float3(-0.80065,0.24631,0.83768), float3(-0.19424,-0.18402,0.26757), float3(-0.43667,0.76751,0.88304), float3(0.21666,0.11602,0.24577), float3(0.15696,-0.85600,0.87027), float3(-0.75821,0.58363,0.95682), float3(0.99284,-0.02904,0.99327), float3(-0.22234,-0.57907,0.62029), float3(0.55052,-0.66984,0.86704), float3(0.46431,0.28115,0.54280), float3(-0.07214,0.60554,0.60982), }; float4 fragBlurInsaneMQ (v2f i) : SV_Target { float4 centerTap = tex2D(_MainTex, UnityStereoScreenSpaceUVAdjust(i.uv1.xy, _MainTex_ST)); float4 sum = centerTap; float4 poissonScale = _MainTex_TexelSize.xyxy * centerTap.a * _Offsets.w; float sampleCount = max(centerTap.a * 0.25, _Offsets.z); // <- weighing with 0.25 looks nicer for small high freq spec sum *= sampleCount; float weights = 0; for(int l=0; l < NumDiscSamples; l++) { float2 sampleUV = i.uv1.xy + DiscKernel[l].xy * poissonScale.xy; float4 sample0 = tex2D(_MainTex, UnityStereoScreenSpaceUVAdjust(sampleUV.xy, _MainTex_ST)); if( sample0.a > 0.0 ) { weights = BokehWeightDisc(sample0, DiscKernel[l].z, centerTap); sum += sample0 * weights; sampleCount += weights; } } float4 returnValue = sum / sampleCount; returnValue.a = centerTap.a; return returnValue; } float4 fragBlurInsaneHQ (v2f i) : SV_Target { float4 centerTap = tex2D(_MainTex, UnityStereoScreenSpaceUVAdjust(i.uv1.xy, _MainTex_ST)); float4 sum = centerTap; float4 poissonScale = _MainTex_TexelSize.xyxy * centerTap.a * _Offsets.w; float sampleCount = max(centerTap.a * 0.25, _Offsets.z); // <- weighing with 0.25 looks nicer for small high freq spec sum *= sampleCount; float2 weights = 0; for(int l=0; l < NumDiscSamples; l++) { float4 sampleUV = i.uv1.xyxy + DiscKernel[l].xyxy * poissonScale.xyxy / float4(1.2,1.2,DiscKernel[l].zz); float4 sample0 = tex2D(_MainTex, UnityStereoScreenSpaceUVAdjust(sampleUV.xy, _MainTex_ST)); float4 sample1 = tex2D(_MainTex, UnityStereoScreenSpaceUVAdjust(sampleUV.zw, _MainTex_ST)); if( (sample0.a + sample1.a) > 0.0 ) { weights = BokehWeightDisc2(sample0, sample1, float2(DiscKernel[l].z/1.2, 1.0), centerTap); sum += sample0 * weights.x + sample1 * weights.y; sampleCount += dot(weights, 1); } } float4 returnValue = sum / sampleCount; returnValue.a = centerTap.a; return returnValue; } inline float4 BlendLowWithHighHQ(float coc, float4 low, float4 high) { float blend = smoothstep(0.65,0.85, coc); return lerp(low, high, blend); } inline float4 BlendLowWithHighMQ(float coc, float4 low, float4 high) { float blend = smoothstep(0.4,0.6, coc); return lerp(low, high, blend); } float4 fragBlurUpsampleCombineHQ (v2f i) : SV_Target { float4 bigBlur = tex2D(_LowRez, UnityStereoScreenSpaceUVAdjust(i.uv1.xy, _LowRez_ST)); float4 centerTap = tex2D(_MainTex, UnityStereoScreenSpaceUVAdjust(i.uv1.xy, _MainTex_ST)); float4 smallBlur = centerTap; float4 poissonScale = _MainTex_TexelSize.xyxy * centerTap.a * _Offsets.w ; float sampleCount = max(centerTap.a * 0.25, 0.1f); // <- weighing with 0.25 looks nicer for small high freq spec smallBlur *= sampleCount; for(int l=0; l < NumDiscSamples; l++) { float2 sampleUV = i.uv1.xy + DiscKernel[l].xy * poissonScale.xy; float4 sample0 = tex2D(_MainTex, UnityStereoScreenSpaceUVAdjust(sampleUV, _MainTex_ST)); float weight0 = BokehWeightDisc(sample0, DiscKernel[l].z, centerTap); smallBlur += sample0 * weight0; sampleCount += weight0; } smallBlur /= (sampleCount+1e-5f); smallBlur = BlendLowWithHighHQ(centerTap.a, smallBlur, bigBlur); return centerTap.a < 1e-2f ? centerTap : float4(smallBlur.rgb,centerTap.a); } float4 fragBlurUpsampleCombineMQ (v2f i) : SV_Target { float4 bigBlur = tex2D(_LowRez, UnityStereoScreenSpaceUVAdjust(i.uv1.xy, _LowRez_ST)); float4 centerTap = tex2D(_MainTex, UnityStereoScreenSpaceUVAdjust(i.uv1.xy, _MainTex_ST)); float4 smallBlur = centerTap; float4 poissonScale = _MainTex_TexelSize.xyxy * centerTap.a * _Offsets.w ; float sampleCount = max(centerTap.a * 0.25, 0.1f); // <- weighing with 0.25 looks nicer for small high freq spec smallBlur *= sampleCount; for(int l=0; l < SmallDiscKernelSamples; l++) { float2 sampleUV = i.uv1.xy + SmallDiscKernel[l].xy * poissonScale.xy*1.1; float4 sample0 = tex2D(_MainTex, UnityStereoScreenSpaceUVAdjust(sampleUV, _MainTex_ST)); float weight0 = BokehWeightDisc(sample0, length(SmallDiscKernel[l].xy*1.1), centerTap); smallBlur += sample0 * weight0; sampleCount += weight0; } smallBlur /= (sampleCount+1e-5f); smallBlur = BlendLowWithHighMQ(centerTap.a, smallBlur, bigBlur); return centerTap.a < 1e-2f ? centerTap : float4(smallBlur.rgb,centerTap.a); } float4 fragBlurUpsampleCheap (v2f i) : SV_Target { float4 centerTap = tex2D(_MainTex, UnityStereoScreenSpaceUVAdjust(i.uv1.xy, _MainTex_ST)); float4 bigBlur = tex2D(_LowRez, UnityStereoScreenSpaceUVAdjust(i.uv1.xy, _LowRez_ST)); float fgCoc = tex2D(_FgOverlap, UnityStereoScreenSpaceUVAdjust(i.uv1.xy, _FgOverlap_ST)).a; float4 smallBlur = lerp(centerTap, bigBlur, saturate( max(centerTap.a,fgCoc)*8.0 )); return float4(smallBlur.rgb, centerTap.a); } float4 fragBlurBox (v2f i) : SV_Target { const int TAPS = 12; float4 centerTap = tex2D(_MainTex, UnityStereoScreenSpaceUVAdjust(i.uv1.xy, _MainTex_ST)); // TODO: important ? breaks when HR blur is being used //centerTap.a = max(centerTap.a, 0.1f); float sampleCount = centerTap.a; float4 sum = centerTap * sampleCount; float2 lenStep = centerTap.aa * (1.0 / (TAPS-1.0)); float4 steps = (_Offsets.xyxy * _MainTex_TexelSize.xyxy) * lenStep.xyxy * float4(1,1, -1,-1); for(int l=1; l 1e-5f) outColor.rgb = color.rgb/sumWeights; return outColor; } float4 fragCaptureColorAndSignedCoc (v2f i) : SV_Target { float4 color = tex2D (_MainTex, UnityStereoScreenSpaceUVAdjust(i.uv1.xy, _MainTex_ST)); float d = SAMPLE_DEPTH_TEXTURE(_CameraDepthTexture, UnityStereoScreenSpaceUVAdjust(i.uv1.xy, _CameraDepthTexture_ST)); d = Linear01Depth (d); color.a = _CurveParams.z * abs(d - _CurveParams.w) / (d + 1e-5f); color.a = clamp( max(0.0, color.a - _CurveParams.y), 0.0, _CurveParams.x) * sign(d - _CurveParams.w); return color; } float4 fragCaptureCoc (v2f i) : SV_Target { float4 color = float4(0,0,0,0); //tex2D (_MainTex, i.uv1.xy); float d = SAMPLE_DEPTH_TEXTURE(_CameraDepthTexture, UnityStereoScreenSpaceUVAdjust(i.uv1.xy, _CameraDepthTexture_ST)); d = Linear01Depth (d); color.a = _CurveParams.z * abs(d - _CurveParams.w) / (d + 1e-5f); color.a = clamp( max(0.0, color.a - _CurveParams.y), 0.0, _CurveParams.x); return color; } float4 AddFgCoc (v2f i) : SV_Target { return tex2D (_MainTex, UnityStereoScreenSpaceUVAdjust(i.uv1.xy, _MainTex_ST)); } float4 fragMergeCoc (v2f i) : SV_Target { float4 color = tex2D (_FgOverlap, UnityStereoScreenSpaceUVAdjust(i.uv.xy, _FgOverlap_ST)); // this is the foreground overlap value float fgCoc = color.a; float d = SAMPLE_DEPTH_TEXTURE(_CameraDepthTexture, UnityStereoScreenSpaceUVAdjust(i.uv1.xy, _CameraDepthTexture_ST)); d = Linear01Depth (d); color.a = _CurveParams.z * abs(d - _CurveParams.w) / (d + 1e-5f); color.a = clamp( max(0.0, color.a - _CurveParams.y), 0.0, _CurveParams.x); return max(color.aaaa, float4(fgCoc,fgCoc,fgCoc,fgCoc)); } float4 fragCombineCocWithMaskBlur (v2f i) : SV_Target { float bgAndFgCoc = tex2D (_MainTex, UnityStereoScreenSpaceUVAdjust(i.uv1.xy, _MainTex_ST)).a; float fgOverlapCoc = tex2D (_FgOverlap, UnityStereoScreenSpaceUVAdjust(i.uv1.xy, _FgOverlap_ST)).a; return (bgAndFgCoc < 0.01) * saturate(fgOverlapCoc-bgAndFgCoc); } float4 fragCaptureForegroundCoc (v2f i) : SV_Target { float4 color = float4(0,0,0,0); //tex2D (_MainTex, i.uv1.xy); float d = SAMPLE_DEPTH_TEXTURE(_CameraDepthTexture, UnityStereoScreenSpaceUVAdjust(i.uv1.xy, _CameraDepthTexture_ST)); d = Linear01Depth (d); color.a = _CurveParams.z * (_CurveParams.w-d) / (d + 1e-5f); color.a = clamp(max(0.0, color.a - _CurveParams.y), 0.0, _CurveParams.x); return color; } float4 fragCaptureForegroundCocMask (v2f i) : SV_Target { float4 color = float4(0,0,0,0); float d = SAMPLE_DEPTH_TEXTURE(_CameraDepthTexture, UnityStereoScreenSpaceUVAdjust(i.uv1.xy, _CameraDepthTexture_ST)); d = Linear01Depth (d); color.a = _CurveParams.z * (_CurveParams.w-d) / (d + 1e-5f); color.a = clamp(max(0.0, color.a - _CurveParams.y), 0.0, _CurveParams.x); return color.a > 0; } float4 fragBlendInHighRez (v2f i) : SV_Target { float4 tapHighRez = tex2D(_MainTex, UnityStereoScreenSpaceUVAdjust(i.uv.xy, _MainTex_ST)); return float4(tapHighRez.rgb, 1.0-saturate(tapHighRez.a*5.0)); } float4 fragBlendInLowRezParts (v2f i) : SV_Target { float4 from = tex2D(_MainTex, UnityStereoScreenSpaceUVAdjust(i.uv1.xy, _MainTex_ST)); from.a = saturate(from.a * _Offsets.w) / (_CurveParams.x + 1e-5f); float square = from.a * from.a; from.a = square * square * _CurveParams.x; return from; } float4 fragUpsampleWithAlphaMask(v2f i) : SV_Target { float4 c = tex2D(_MainTex, i.uv1.xy); return c; } float4 fragAlphaMask(v2f i) : SV_Target { float4 c = tex2D(_MainTex, UnityStereoScreenSpaceUVAdjust(i.uv1.xy, _MainTex_ST)); c.a = saturate(c.a*100.0); return c; } ENDCG Subshader { // pass 0 Pass { ZTest Always Cull Off ZWrite Off ColorMask A CGPROGRAM #pragma target 3.0 #pragma vertex vert #pragma fragment fragCaptureCoc ENDCG } // pass 1 Pass { ZTest Always Cull Off ZWrite Off CGPROGRAM #pragma target 3.0 #pragma vertex vertBlurPlusMinus #pragma fragment fragGaussBlur ENDCG } // pass 2 Pass { ZTest Always Cull Off ZWrite Off CGPROGRAM #pragma target 3.0 #pragma vertex vertBlurPlusMinus #pragma fragment fragBlurForFgCoc ENDCG } // pass 3 Pass { ZTest Always Cull Off ZWrite Off ColorMask A BlendOp Max, Max Blend One One, One One CGPROGRAM #pragma target 3.0 #pragma vertex vert #pragma fragment AddFgCoc ENDCG } // pass 4 Pass { ZTest Always Cull Off ZWrite Off ColorMask A CGPROGRAM #pragma target 3.0 #pragma vertex vert #pragma fragment fragCaptureForegroundCoc ENDCG } // pass 5 Pass { ZTest Always Cull Off ZWrite Off CGPROGRAM #pragma target 3.0 #pragma vertex vert #pragma fragment fragBlurBox ENDCG } // pass 6 Pass { ZTest Always Cull Off ZWrite Off CGPROGRAM #pragma target 3.0 #pragma vertex vert #pragma fragment frag4TapBlurForLRSpawn ENDCG } // pass 7 Pass { ZTest Always Cull Off ZWrite Off ColorMask RGB Blend SrcAlpha OneMinusSrcAlpha CGPROGRAM #pragma target 3.0 #pragma vertex vert #pragma fragment fragBlendInHighRez ENDCG } // pass 8 Pass { ZTest Always Cull Off ZWrite Off ColorMask A CGPROGRAM #pragma target 3.0 #pragma vertex vert #pragma fragment fragCaptureForegroundCocMask ENDCG } // pass 9 Pass { ZTest Always Cull Off ZWrite Off CGPROGRAM #pragma target 3.0 #pragma vertex vert #pragma fragment fragBlurUpsampleCheap ENDCG } // pass 10 Pass { ZTest Always Cull Off ZWrite Off CGPROGRAM #pragma target 3.0 #pragma vertex vert #pragma fragment fragCaptureColorAndSignedCoc ENDCG } // pass 11 Pass { ZTest Always Cull Off ZWrite Off CGPROGRAM #pragma target 3.0 #pragma vertex vert #pragma fragment fragBlurInsaneMQ ENDCG } // pass 12 Pass { ZTest Always Cull Off ZWrite Off CGPROGRAM #pragma target 3.0 #pragma vertex vert #pragma fragment fragBlurUpsampleCombineMQ ENDCG } // pass 13 Pass { ZTest Always Cull Off ZWrite Off ColorMask A CGPROGRAM #pragma target 3.0 #pragma vertex vert #pragma fragment fragMergeCoc ENDCG } // pass 14 Pass { ZTest Always Cull Off ZWrite Off ColorMask A BlendOp Max, Max Blend One One, One One CGPROGRAM #pragma target 3.0 #pragma vertex vert #pragma fragment fragCombineCocWithMaskBlur ENDCG } // pass 15 Pass { ZTest Always Cull Off ZWrite Off CGPROGRAM #pragma target 3.0 #pragma vertex vert #pragma fragment fragBoxDownsample ENDCG } // pass 16 Pass { ZTest Always Cull Off ZWrite Off CGPROGRAM #pragma target 3.0 #pragma vertex vert #pragma fragment fragVisualize ENDCG } // pass 17 Pass { ZTest Always Cull Off ZWrite Off CGPROGRAM #pragma target 3.0 #pragma vertex vert #pragma fragment fragBlurInsaneHQ ENDCG } // pass 18 Pass { ZTest Always Cull Off ZWrite Off CGPROGRAM #pragma target 3.0 #pragma vertex vert #pragma fragment fragBlurUpsampleCombineHQ ENDCG } // pass 19 Pass { ZTest Always Cull Off ZWrite Off CGPROGRAM #pragma target 3.0 #pragma vertex vertBlurPlusMinus #pragma fragment fragBlurAlphaWeighted ENDCG } // pass 20 Pass { ZTest Always Cull Off ZWrite Off CGPROGRAM #pragma target 3.0 #pragma vertex vert #pragma fragment fragAlphaMask ENDCG } // pass 21 Pass { ZTest Always Cull Off ZWrite Off BlendOp Add, Add Blend DstAlpha OneMinusDstAlpha, Zero One CGPROGRAM #pragma target 3.0 #pragma vertex vertFlip #pragma fragment fragBlurBox ENDCG } // pass 22 Pass { ZTest Always Cull Off ZWrite Off // destination alpha needs to stay intact as we have layed alpha before BlendOp Add, Add Blend DstAlpha One, Zero One CGPROGRAM #pragma target 3.0 #pragma vertex vert #pragma fragment fragUpsampleWithAlphaMask ENDCG } } Fallback off }