11#ifndef __DEPTH_OF_FIELD__
22#define __DEPTH_OF_FIELD__
33
4- #include "UnityCG.cginc"
4+ #if SHADER_TARGET >= 50
5+ // Use separate texture/sampler objects on Shader Model 5.0
6+ #define SEPARATE_TEXTURE_SAMPLER
7+ #define DOF_DECL_TEX2D (tex) Texture2D tex; SamplerState sampler ##tex
8+ #define DOF_TEX2D (tex, coord) tex.Sample (sampler ##tex, coord)
9+ #else
10+ #define DOF_DECL_TEX2D (tex) sampler2D tex
11+ #define DOF_TEX2D (tex, coord) tex2D (tex, coord)
12+ #endif
13+
514#include "Common.cginc"
615#include "DiskKernels.cginc"
716
8- #define PREFILTER_LUMA_WEIGHT 1
9-
10- sampler2D_float _CameraDepthTexture;
11- sampler2D_float _HistoryCoC;
12- float _HistoryWeight;
17+ DOF_DECL_TEX2D (_CameraDepthTexture);
18+ DOF_DECL_TEX2D (_CameraMotionVectorsTexture);
19+ DOF_DECL_TEX2D (_CoCTex);
1320
1421// Camera parameters
1522float _Distance;
1623float _LensCoeff; // f^2 / (N * (S1 - f) * film_width * 2)
1724float _MaxCoC;
1825float _RcpMaxCoC;
1926float _RcpAspect;
27+ half3 _TaaParams; // Jitter.x, Jitter.y, Blending
2028
2129struct VaryingsDOF
2230{
@@ -47,75 +55,114 @@ VaryingsDOF VertDOF(AttributesDefault v)
4755 return o;
4856}
4957
50- // Prefilter: CoC calculation, downsampling and premultiplying.
51-
52- #if defined (PREFILTER_TAA)
58+ // CoC calculation
59+ half4 FragCoC (VaryingsDOF i) : SV_Target
60+ {
61+ float depth = LinearEyeDepth (DOF_TEX2D (_CameraDepthTexture, i.uv));
62+ half coc = (depth - _Distance) * _LensCoeff / max (depth, 1e-5 );
63+ return saturate (coc * 0.5 * _RcpMaxCoC + 0.5 );
64+ }
5365
54- // TAA enabled: use MRT to update the history buffer in the same pass.
55- struct PrefilterOutput
66+ // Temporal filter
67+ half4 FragTempFilter (VaryingsDOF i) : SV_Target
5668{
57- half4 base : SV_Target0 ;
58- half4 history : SV_Target1 ;
59- };
60- #define PrefilterSemantics
69+ float3 uvOffs = _MainTex_TexelSize.xyy * float3 (1 , 1 , 0 );
70+
71+ #if defined (SEPARATE_TEXTURE_SAMPLER)
72+
73+ half4 cocTL = _CoCTex.GatherRed (sampler_CoCTex, i.uv - uvOffs.xy * 0.5 ); // top-left
74+ half4 cocBR = _CoCTex.GatherRed (sampler_CoCTex, i.uv + uvOffs.xy * 0.5 ); // bottom-right
75+ half coc1 = cocTL.x; // top
76+ half coc2 = cocTL.z; // left
77+ half coc3 = cocBR.x; // bottom
78+ half coc4 = cocBR.z; // right
6179
6280#else
6381
64- // No TAA
65- #define PrefilterOutput half4
66- #define PrefilterSemantics :SV_Target
82+ half coc1 = DOF_TEX2D (_CoCTex, i.uv - uvOffs.xz).r; // top
83+ half coc2 = DOF_TEX2D (_CoCTex, i.uv - uvOffs.zy).r; // left
84+ half coc3 = DOF_TEX2D (_CoCTex, i.uv + uvOffs.zy).r; // bottom
85+ half coc4 = DOF_TEX2D (_CoCTex, i.uv + uvOffs.xz).r; // right
6786
6887#endif
6988
70- PrefilterOutput FragPrefilter (VaryingsDOF i) PrefilterSemantics
89+ // Dejittered center sample.
90+ half coc0 = DOF_TEX2D (_CoCTex, i.uv - _TaaParams.xy).r;
91+
92+ // CoC dilation: determine the closest point in the four neighbors.
93+ float3 closest = float3 (0 , 0 , coc0);
94+ closest = coc1 < closest.z ? float3 (-uvOffs.xz, coc1) : closest;
95+ closest = coc2 < closest.z ? float3 (-uvOffs.zy, coc2) : closest;
96+ closest = coc3 < closest.z ? float3 (+uvOffs.zy, coc3) : closest;
97+ closest = coc4 < closest.z ? float3 (+uvOffs.xz, coc4) : closest;
98+
99+ // Sample the history buffer with the motion vector at the closest point.
100+ float2 motion = DOF_TEX2D (_CameraMotionVectorsTexture, i.uv + closest.xy).xy;
101+ half cocHis = DOF_TEX2D (_MainTex, i.uv - motion).r;
102+
103+ // Neighborhood clamping.
104+ half cocMin = closest.z;
105+ half cocMax = max (max (max (max (coc0, coc1), coc2), coc3), coc4);
106+ cocHis = clamp (cocHis, cocMin, cocMax);
107+
108+ // Blend with the history.
109+ return lerp (coc0, cocHis, _TaaParams.z);
110+ }
111+
112+ // Prefilter: downsampling and premultiplying.
113+ half4 FragPrefilter (VaryingsDOF i) : SV_Target
71114{
115+ #if defined (SEPARATE_TEXTURE_SAMPLER)
116+
117+ // Sample source colors.
118+ half4 c_r = _MainTex.GatherRed (sampler_MainTex, i.uv);
119+ half4 c_g = _MainTex.GatherGreen (sampler_MainTex, i.uv);
120+ half4 c_b = _MainTex.GatherBlue (sampler_MainTex, i.uv);
121+
122+ half3 c0 = half3 (c_r.x, c_g.x, c_b.x);
123+ half3 c1 = half3 (c_r.y, c_g.y, c_b.y);
124+ half3 c2 = half3 (c_r.z, c_g.z, c_b.z);
125+ half3 c3 = half3 (c_r.w, c_g.w, c_b.w);
126+
127+ // Sample CoCs.
128+ half4 cocs = _CoCTex.Gather (sampler_CoCTex, i.uvAlt) * 2.0 - 1.0 ;
129+ half coc0 = cocs.x;
130+ half coc1 = cocs.y;
131+ half coc2 = cocs.z;
132+ half coc3 = cocs.w;
133+
134+ #else
135+
72136 float3 duv = _MainTex_TexelSize.xyx * float3 (0.5 , 0.5 , -0.5 );
73137
74138 // Sample source colors.
75- half3 c0 = tex2D (_MainTex, i.uv - duv.xy).rgb;
76- half3 c1 = tex2D (_MainTex, i.uv - duv.zy).rgb;
77- half3 c2 = tex2D (_MainTex, i.uv + duv.zy).rgb;
78- half3 c3 = tex2D (_MainTex, i.uv + duv.xy).rgb;
79-
80- // Sample linear depths.
81- float d0 = LinearEyeDepth (SAMPLE_DEPTH_TEXTURE (_CameraDepthTexture, i.uvAlt - duv.xy));
82- float d1 = LinearEyeDepth (SAMPLE_DEPTH_TEXTURE (_CameraDepthTexture, i.uvAlt - duv.zy));
83- float d2 = LinearEyeDepth (SAMPLE_DEPTH_TEXTURE (_CameraDepthTexture, i.uvAlt + duv.zy));
84- float d3 = LinearEyeDepth (SAMPLE_DEPTH_TEXTURE (_CameraDepthTexture, i.uvAlt + duv.xy));
85- float4 depths = float4 (d0, d1, d2, d3);
86-
87- // Calculate the radiuses of CoCs at these sample points.
88- float4 cocs = (depths - _Distance) * _LensCoeff / depths;
89- cocs = clamp (cocs, -_MaxCoC, _MaxCoC);
90-
91- #if defined (PREFILTER_TAA)
92- // Get the average with the history to avoid temporal aliasing.
93- half hcoc = tex2D (_HistoryCoC, i.uv).r;
94- cocs = lerp (cocs, hcoc, _HistoryWeight);
95- #endif
139+ half3 c0 = DOF_TEX2D (_MainTex, i.uv - duv.xy).rgb;
140+ half3 c1 = DOF_TEX2D (_MainTex, i.uv - duv.zy).rgb;
141+ half3 c2 = DOF_TEX2D (_MainTex, i.uv + duv.zy).rgb;
142+ half3 c3 = DOF_TEX2D (_MainTex, i.uv + duv.xy).rgb;
143+
144+ // Sample CoCs.
145+ half coc0 = DOF_TEX2D (_CoCTex, i.uvAlt - duv.xy).r * 2.0 - 1.0 ;
146+ half coc1 = DOF_TEX2D (_CoCTex, i.uvAlt - duv.zy).r * 2.0 - 1.0 ;
147+ half coc2 = DOF_TEX2D (_CoCTex, i.uvAlt + duv.zy).r * 2.0 - 1.0 ;
148+ half coc3 = DOF_TEX2D (_CoCTex, i.uvAlt + duv.xy).r * 2.0 - 1.0 ;
96149
97- // Premultiply CoC to reduce background bleeding.
98- float4 weights = saturate (abs (cocs) * _RcpMaxCoC);
99-
100- #if defined (PREFILTER_LUMA_WEIGHT)
101- // Apply luma weights to reduce flickering.
102- // References:
103- // http://gpuopen.com/optimized-reversible-tonemapper-for-resolve/
104- // http://graphicrants.blogspot.fr/2013/12/tone-mapping.html
105- weights.x *= 1.0 / (Max3 (c0) + 1.0 );
106- weights.y *= 1.0 / (Max3 (c1) + 1.0 );
107- weights.z *= 1.0 / (Max3 (c2) + 1.0 );
108- weights.w *= 1.0 / (Max3 (c3) + 1.0 );
109150#endif
110151
152+ // Apply CoC and luma weights to reduce bleeding and flickering.
153+ float w0 = abs (coc0) / (Max3 (c0) + 1.0 );
154+ float w1 = abs (coc1) / (Max3 (c1) + 1.0 );
155+ float w2 = abs (coc2) / (Max3 (c2) + 1.0 );
156+ float w3 = abs (coc3) / (Max3 (c3) + 1.0 );
157+
111158 // Weighted average of the color samples
112- half3 avg = c0 * weights.x + c1 * weights.y + c2 * weights.z + c3 * weights.w ;
113- avg /= dot (weights, 1.0 );
159+ half3 avg = c0 * w0 + c1 * w1 + c2 * w2 + c3 * w3 ;
160+ avg /= max (w0 + w1 + w2 + w3, 1e- 5 );
114161
115- // Output CoC = average of CoCs
116- half cocmin = Min4 (cocs );
117- half cocmax = Max4 (cocs );
118- half coc = -cocmin > cocmax ? cocmin : cocmax ;
162+ // Select the largest CoC value.
163+ half coc_min = Min4 (coc0, coc1, coc2, coc3 );
164+ half coc_max = Max4 (coc0, coc1, coc2, coc3 );
165+ half coc = (-coc_min > coc_max ? coc_min : coc_max) * _MaxCoC ;
119166
120167 // Premultiply CoC again.
121168 avg *= smoothstep (0 , _MainTex_TexelSize.y * 2 , abs (coc));
@@ -124,20 +171,13 @@ PrefilterOutput FragPrefilter(VaryingsDOF i) PrefilterSemantics
124171 avg = GammaToLinearSpace (avg);
125172#endif
126173
127- #if defined (PREFILTER_TAA)
128- PrefilterOutput output;
129- output.base = half4 (avg, coc);
130- output.history = coc.xxxx;
131- return output;
132- #else
133174 return half4 (avg, coc);
134- #endif
135175}
136176
137177// Bokeh filter with disk-shaped kernels
138178half4 FragBlur (VaryingsDOF i) : SV_Target
139179{
140- half4 samp0 = tex2D (_MainTex, i.uv);
180+ half4 samp0 = DOF_TEX2D (_MainTex, i.uv);
141181
142182 half4 bgAcc = 0.0 ; // Background: far field bokeh
143183 half4 fgAcc = 0.0 ; // Foreground: near field bokeh
@@ -148,7 +188,7 @@ half4 FragBlur(VaryingsDOF i) : SV_Target
148188 float dist = length (disp);
149189
150190 float2 duv = float2 (disp.x * _RcpAspect, disp.y);
151- half4 samp = tex2D (_MainTex, i.uv + duv);
191+ half4 samp = DOF_TEX2D (_MainTex, i.uv + duv);
152192
153193 // BG: Compare CoC of the current sample and the center sample
154194 // and select smaller one.
@@ -181,50 +221,23 @@ half4 FragBlur(VaryingsDOF i) : SV_Target
181221 fgAcc.a *= UNITY_PI / kSampleCount;
182222
183223 // Alpha premultiplying
184- half3 rgb = 0.0 ;
185- rgb = lerp (rgb, bgAcc.rgb, saturate (bgAcc.a));
186- rgb = lerp (rgb, fgAcc.rgb, saturate (fgAcc.a));
187-
188- // Combined alpha value
189- half alpha = (1.0 - saturate (bgAcc.a)) * (1.0 - saturate (fgAcc.a));
224+ half alpha = saturate (fgAcc.a);
225+ half3 rgb = lerp (bgAcc.rgb, fgAcc.rgb, alpha);
190226
191227 return half4 (rgb, alpha);
192228}
193229
194230// Postfilter blur
195231half4 FragPostBlur (VaryingsDOF i) : SV_Target
196232{
197- // 9-tap tent filter
198- float4 duv = _MainTex_TexelSize.xyxy * float4 (1 , 1 , -1 , 0 );
199-
200- half4 c0 = tex2D (_MainTex, i.uv - duv.xy);
201- half4 c1 = tex2D (_MainTex, i.uv - duv.wy);
202- half4 c2 = tex2D (_MainTex, i.uv - duv.zy);
203-
204- half4 c3 = tex2D (_MainTex, i.uv + duv.zw);
205- half4 c4 = tex2D (_MainTex, i.uv );
206- half4 c5 = tex2D (_MainTex, i.uv + duv.xw);
207-
208- half4 c6 = tex2D (_MainTex, i.uv + duv.zy);
209- half4 c7 = tex2D (_MainTex, i.uv + duv.wy);
210- half4 c8 = tex2D (_MainTex, i.uv + duv.xy);
211-
212- half4 acc = c0 * 1 + c1 * 2 + c2 * 1 +
213- c3 * 2 + c4 * 4 + c5 * 2 +
214- c6 * 1 + c7 * 2 + c8 * 1 ;
215-
216- half aa =
217- c0.a * c0.a * 1 + c1.a * c1.a * 2 + c2.a * c2.a * 1 +
218- c3.a * c3.a * 2 + c4.a * c4.a * 4 + c5.a * c5.a * 2 +
219- c6.a * c6.a * 1 + c7.a * c7.a * 2 + c8.a * c8.a * 1 ;
220-
221- half wb = 1.2 ;
222- half a = (wb * acc.a - aa) / (wb * 16 - acc.a);
223-
224- acc /= 16 ;
225-
226- half3 rgb = acc.rgb * (1 + saturate (acc.a - a));
227- return half4 (rgb, a);
233+ // 9 tap tent filter with 4 bilinear samples
234+ const float4 duv = _MainTex_TexelSize.xyxy * float4 (0.5 , 0.5 , -0.5 , 0 );
235+ half4 acc;
236+ acc = DOF_TEX2D (_MainTex, i.uv - duv.xy);
237+ acc += DOF_TEX2D (_MainTex, i.uv - duv.zy);
238+ acc += DOF_TEX2D (_MainTex, i.uv + duv.zy);
239+ acc += DOF_TEX2D (_MainTex, i.uv + duv.xy);
240+ return acc / 4.0 ;
228241}
229242
230243#endif // __DEPTH_OF_FIELD__
0 commit comments