|
3 | 3 |
|
4 | 4 | #include "UnityCG.cginc" |
5 | 5 | #include "Common.cginc" |
| 6 | +#include "DiskKernels.cginc" |
6 | 7 |
|
7 | | -half4 Frag(VaryingsDefault i) : SV_Target |
| 8 | +#pragma target 3.0 |
| 9 | + |
| 10 | +sampler2D_float _CameraDepthTexture; |
| 11 | +sampler2D_float _DejitteredDepth; |
| 12 | + |
| 13 | +// Camera parameters |
| 14 | +float _Distance; |
| 15 | +float _LensCoeff; // f^2 / (N * (S1 - f) * film_width * 2) |
| 16 | +float _MaxCoC; |
| 17 | +float _RcpMaxCoC; |
| 18 | +float _RcpAspect; |
| 19 | + |
| 20 | +struct VaryingsDOF |
| 21 | +{ |
| 22 | + float4 pos : SV_POSITION; |
| 23 | + half2 uv : TEXCOORD0; |
| 24 | + half2 uvAlt : TEXCOORD1; |
| 25 | +}; |
| 26 | + |
| 27 | +// Common vertex shader with single pass stereo rendering support |
| 28 | +VaryingsDOF VertDOF(AttributesDefault v) |
| 29 | +{ |
| 30 | + half2 uvAlt = v.texcoord; |
| 31 | +#if UNITY_UV_STARTS_AT_TOP |
| 32 | + if (_MainTex_TexelSize.y < 0.0) uvAlt.y = 1.0 - uvAlt.y; |
| 33 | +#endif |
| 34 | + |
| 35 | + VaryingsDOF o; |
| 36 | +#if defined(UNITY_SINGLE_PASS_STEREO) |
| 37 | + o.pos = UnityObjectToClipPos(v.vertex); |
| 38 | + o.uv = UnityStereoScreenSpaceUVAdjust(v.texcoord, _MainTex_ST); |
| 39 | + o.uvAlt = UnityStereoScreenSpaceUVAdjust(uvAlt, _MainTex_ST); |
| 40 | +#else |
| 41 | + o.pos = mul(UNITY_MATRIX_MVP, v.vertex); |
| 42 | + o.uv = v.texcoord; |
| 43 | + o.uvAlt = uvAlt; |
| 44 | +#endif |
| 45 | + |
| 46 | + return o; |
| 47 | +} |
| 48 | + |
| 49 | +// Downsampling, prefiltering and CoC calculation |
| 50 | +half4 FragPrefilter(VaryingsDOF i) : SV_Target |
8 | 51 | { |
9 | | - return tex2D(_MainTex, i.uv); |
| 52 | + float3 duv = _MainTex_TexelSize.xyx * float3(0.5, 0.5, -0.5); |
| 53 | + |
| 54 | + // Sample source colors. |
| 55 | + half3 c0 = tex2D(_MainTex, i.uv - duv.xy).rgb; |
| 56 | + half3 c1 = tex2D(_MainTex, i.uv - duv.zy).rgb; |
| 57 | + half3 c2 = tex2D(_MainTex, i.uv + duv.zy).rgb; |
| 58 | + half3 c3 = tex2D(_MainTex, i.uv + duv.xy).rgb; |
| 59 | + |
| 60 | + // Sample linear depths. |
| 61 | +#if DEJITTER_DEPTH |
| 62 | + float d0 = LinearEyeDepth(tex2D(_DejitteredDepth, i.uvAlt - duv.xy).x); |
| 63 | + float d1 = LinearEyeDepth(tex2D(_DejitteredDepth, i.uvAlt - duv.zy).x); |
| 64 | + float d2 = LinearEyeDepth(tex2D(_DejitteredDepth, i.uvAlt + duv.zy).x); |
| 65 | + float d3 = LinearEyeDepth(tex2D(_DejitteredDepth, i.uvAlt + duv.xy).x); |
| 66 | +#else |
| 67 | + float d0 = LinearEyeDepth(SAMPLE_DEPTH_TEXTURE(_CameraDepthTexture, i.uvAlt - duv.xy)); |
| 68 | + float d1 = LinearEyeDepth(SAMPLE_DEPTH_TEXTURE(_CameraDepthTexture, i.uvAlt - duv.zy)); |
| 69 | + float d2 = LinearEyeDepth(SAMPLE_DEPTH_TEXTURE(_CameraDepthTexture, i.uvAlt + duv.zy)); |
| 70 | + float d3 = LinearEyeDepth(SAMPLE_DEPTH_TEXTURE(_CameraDepthTexture, i.uvAlt + duv.xy)); |
| 71 | +#endif |
| 72 | + |
| 73 | + float4 depths = float4(d0, d1, d2, d3); |
| 74 | + |
| 75 | + // Calculate the radiuses of CoCs at these sample points. |
| 76 | + float4 cocs = (depths - _Distance) * _LensCoeff / depths; |
| 77 | + cocs = clamp(cocs, -_MaxCoC, _MaxCoC); |
| 78 | + |
| 79 | + // Premultiply CoC to reduce background bleeding. |
| 80 | + float4 weights = saturate(abs(cocs) * _RcpMaxCoC); |
| 81 | + |
| 82 | +#if defined(PREFILTER_LUMA_WEIGHT) |
| 83 | + // Apply luma weights to reduce flickering. |
| 84 | + // References: |
| 85 | + // http://gpuopen.com/optimized-reversible-tonemapper-for-resolve/ |
| 86 | + // http://graphicrants.blogspot.fr/2013/12/tone-mapping.html |
| 87 | + weights.x *= 1.0 / (Max3(c0) + 1.0); |
| 88 | + weights.y *= 1.0 / (Max3(c1) + 1.0); |
| 89 | + weights.z *= 1.0 / (Max3(c2) + 1.0); |
| 90 | + weights.w *= 1.0 / (Max3(c3) + 1.0); |
| 91 | +#endif |
| 92 | + |
| 93 | + // Weighted average of the color samples |
| 94 | + half3 avg = c0 * weights.x + c1 * weights.y + c2 * weights.z + c3 * weights.w; |
| 95 | + avg /= dot(weights, 1.0); |
| 96 | + |
| 97 | + // Output CoC = average of CoCs |
| 98 | + half coc = dot(cocs, 0.25); |
| 99 | + |
| 100 | +#if defined(UNITY_COLORSPACE_GAMMA) |
| 101 | + avg = GammaToLinearSpace(avg); |
| 102 | +#endif |
| 103 | + |
| 104 | + return half4(avg, coc); |
| 105 | +} |
| 106 | + |
| 107 | +// Bokeh filter with disk-shaped kernels |
| 108 | +half4 FragBlur(VaryingsDOF i) : SV_Target |
| 109 | +{ |
| 110 | + half4 samp0 = tex2D(_MainTex, i.uv); |
| 111 | + |
| 112 | + half4 bgAcc = 0.0; // Background: far field bokeh |
| 113 | + half4 fgAcc = 0.0; // Foreground: near field bokeh |
| 114 | + |
| 115 | + UNITY_LOOP for (int si = 0; si < kSampleCount; si++) |
| 116 | + { |
| 117 | + float2 disp = kDiskKernel[si] * _MaxCoC; |
| 118 | + float dist = length(disp); |
| 119 | + |
| 120 | + float2 duv = float2(disp.x * _RcpAspect, disp.y); |
| 121 | + half4 samp = tex2D(_MainTex, i.uv + duv); |
| 122 | + |
| 123 | + // BG: Compare CoC of the current sample and the center sample |
| 124 | + // and select smaller one. |
| 125 | + half bgCoC = max(min(samp0.a, samp.a), 0.0); |
| 126 | + |
| 127 | + // Compare the CoC to the sample distance. |
| 128 | + // Add a small margin to smooth out. |
| 129 | + half bgWeight = saturate((bgCoC - dist + 0.005) / 0.01); |
| 130 | + half fgWeight = saturate((-samp.a - dist + 0.005) / 0.01); |
| 131 | + |
| 132 | + // Accumulation |
| 133 | + bgAcc += half4(samp.rgb, 1.0) * bgWeight; |
| 134 | + fgAcc += half4(samp.rgb, 1.0) * fgWeight; |
| 135 | + } |
| 136 | + |
| 137 | + // Get the weighted average. |
| 138 | + bgAcc.rgb /= bgAcc.a + (bgAcc.a == 0.0); // zero-div guard |
| 139 | + fgAcc.rgb /= fgAcc.a + (fgAcc.a == 0.0); |
| 140 | + |
| 141 | + // BG: Calculate the alpha value only based on the center CoC. |
| 142 | + // This is a rather aggressive approximation but provides stable results. |
| 143 | + bgAcc.a = smoothstep(_MainTex_TexelSize.y, _MainTex_TexelSize.y * 2.0, samp0.a); |
| 144 | + |
| 145 | + // FG: Normalize the total of the weights. |
| 146 | + fgAcc.a *= UNITY_PI / kSampleCount; |
| 147 | + |
| 148 | + // Alpha premultiplying |
| 149 | + half3 rgb = 0.0; |
| 150 | + rgb = lerp(rgb, bgAcc.rgb, saturate(bgAcc.a)); |
| 151 | + rgb = lerp(rgb, fgAcc.rgb, saturate(fgAcc.a)); |
| 152 | + |
| 153 | + // Combined alpha value |
| 154 | + half alpha = (1.0 - saturate(bgAcc.a)) * (1.0 - saturate(fgAcc.a)); |
| 155 | + |
| 156 | + return half4(rgb, alpha); |
10 | 157 | } |
11 | 158 |
|
12 | 159 | #endif // __DEPTH_OF_FIELD__ |
0 commit comments