1 Shader "Hidden/Dof/DepthOfField34" {
2 Properties {
3 _MainTex ("Base", 2D) = "" {}
4 _TapLowBackground ("TapLowBackground", 2D) = "" {}
5 _TapLowForeground ("TapLowForeground", 2D) = "" {}
6 _TapMedium ("TapMedium", 2D) = "" {}
7 }
8
9 CGINCLUDE
10
11 #include "UnityCG.cginc"
12
13 struct v2f {
14 half4 pos : SV_POSITION;
15 half2 uv1 : TEXCOORD0;
16 };
17
18 struct v2fDofApply {
19 half4 pos : SV_POSITION;
20 half2 uv : TEXCOORD0;
21 };
22
23 struct v2fRadius {
24 half4 pos : SV_POSITION;
25 half2 uv : TEXCOORD0;
26 half4 uv1[4] : TEXCOORD1;
27 };
28
29 struct v2fDown {
30 half4 pos : SV_POSITION;
31 half2 uv0 : TEXCOORD0;
32 half2 uv[2] : TEXCOORD1;
33 };
34
35 sampler2D _MainTex;
36 sampler2D_float _CameraDepthTexture;
37 sampler2D _TapLowBackground;
38 sampler2D _TapLowForeground;
39 sampler2D _TapMedium;
40
41 half4 _CurveParams;
42 half _ForegroundBlurExtrude;
43 uniform half3 _Threshhold;
44 uniform float4 _MainTex_TexelSize;
45 uniform float2 _InvRenderTargetSize;
46
47 v2f vert( appdata_img v ) {
48 v2f o;
49 o.pos = mul (UNITY_MATRIX_MVP, v.vertex);
50 o.uv1.xy = v.texcoord.xy;
51 return o;
52 }
53
54 v2fRadius vertWithRadius( appdata_img v ) {
55 v2fRadius o;
56 o.pos = mul(UNITY_MATRIX_MVP, v.vertex);
57 o.uv.xy = v.texcoord.xy;
58
59 const half2 blurOffsets[4] = {
60 half2(-0.5, +1.5),
61 half2(+0.5, -1.5),
62 half2(+1.5, +0.5),
63 half2(-1.5, -0.5)
64 };
65
66 o.uv1[0].xy = v.texcoord.xy + 5.0 * _MainTex_TexelSize.xy * blurOffsets[0];
67 o.uv1[1].xy = v.texcoord.xy + 5.0 * _MainTex_TexelSize.xy * blurOffsets[1];
68 o.uv1[2].xy = v.texcoord.xy + 5.0 * _MainTex_TexelSize.xy * blurOffsets[2];
69 o.uv1[3].xy = v.texcoord.xy + 5.0 * _MainTex_TexelSize.xy * blurOffsets[3];
70
71 o.uv1[0].zw = v.texcoord.xy + 3.0 * _MainTex_TexelSize.xy * blurOffsets[0];
72 o.uv1[1].zw = v.texcoord.xy + 3.0 * _MainTex_TexelSize.xy * blurOffsets[1];
73 o.uv1[2].zw = v.texcoord.xy + 3.0 * _MainTex_TexelSize.xy * blurOffsets[2];
74 o.uv1[3].zw = v.texcoord.xy + 3.0 * _MainTex_TexelSize.xy * blurOffsets[3];
75
76 return o;
77 }
78
79 v2fDofApply vertDofApply( appdata_img v ) {
80 v2fDofApply o;
81 o.pos = mul(UNITY_MATRIX_MVP, v.vertex);
82 o.uv.xy = v.texcoord.xy;
83 return o;
84 }
85
86 v2fDown vertDownsampleWithCocConserve(appdata_img v) {
87 v2fDown o;
88 o.pos = mul(UNITY_MATRIX_MVP, v.vertex);
89 o.uv0.xy = v.texcoord.xy;
90 o.uv[0].xy = v.texcoord.xy + half2(-1.0,-1.0) * _InvRenderTargetSize;
91 o.uv[1].xy = v.texcoord.xy + half2(1.0,-1.0) * _InvRenderTargetSize;
92 return o;
93 }
94
95 half4 BokehPrereqs (sampler2D tex, half4 uv1[4], half4 center, half considerCoc) {
96
97 // @NOTE 1:
98 // we are checking for 3 things in order to create a bokeh.
99 // goal is to get the highest bang for the buck.
100 // 1.) contrast/frequency should be very high (otherwise bokeh mostly unvisible)
101 // 2.) luminance should be high
102 // 3.) no occluder nearby (stored in alpha channel)
103
104 // @NOTE 2: about the alpha channel in littleBlur:
105 // the alpha channel stores an heuristic on how likely it is
106 // that there is no bokeh occluder nearby.
107 // if we didn't' check for that, we'd get very noise bokeh
108 // popping because of the sudden contrast changes
109
110 half4 sampleA = tex2D(tex, uv1[0].zw);
111 half4 sampleB = tex2D(tex, uv1[1].zw);
112 half4 sampleC = tex2D(tex, uv1[2].zw);
113 half4 sampleD = tex2D(tex, uv1[3].zw);
114
115 half4 littleBlur = 0.125 * (sampleA + sampleB + sampleC + sampleD);
116
117 sampleA = tex2D(tex, uv1[0].xy);
118 sampleB = tex2D(tex, uv1[1].xy);
119 sampleC = tex2D(tex, uv1[2].xy);
120 sampleD = tex2D(tex, uv1[3].xy);
121
122 littleBlur += 0.125 * (sampleA + sampleB + sampleC + sampleD);
123
124 littleBlur = lerp (littleBlur, center, saturate(100.0 * considerCoc * abs(littleBlur.a - center.a)));
125
126 return littleBlur;
127 }
128
129 half4 fragDownsampleWithCocConserve(v2fDown i) : SV_Target {
130 half2 rowOfs[4];
131
132 rowOfs[0] = half2(0.0, 0.0);
133 rowOfs[1] = half2(0.0, _InvRenderTargetSize.y);
134 rowOfs[2] = half2(0.0, _InvRenderTargetSize.y) * 2.0;
135 rowOfs[3] = half2(0.0, _InvRenderTargetSize.y) * 3.0;
136
137 half4 color = tex2D(_MainTex, i.uv0.xy);
138
139 half4 sampleA = tex2D(_MainTex, i.uv[0].xy + rowOfs[0]);
140 half4 sampleB = tex2D(_MainTex, i.uv[1].xy + rowOfs[0]);
141 half4 sampleC = tex2D(_MainTex, i.uv[0].xy + rowOfs[2]);
142 half4 sampleD = tex2D(_MainTex, i.uv[1].xy + rowOfs[2]);
143
144 color += sampleA + sampleB + sampleC + sampleD;
145 color *= 0.2;
146
147 // @NOTE we are doing max on the alpha channel for 2 reasons:
148 // 1) foreground blur likes a slightly bigger radius
149 // 2) otherwise we get an ugly outline between high blur- and medium blur-areas
150 // drawback: we get a little bit of color bleeding
151
152 color.a = max(max(sampleA.a, sampleB.a), max(sampleC.a, sampleD.a));
153
154 return color;
155 }
156
157 half4 fragDofApplyBg (v2fDofApply i) : SV_Target {
158 half4 tapHigh = tex2D (_MainTex, i.uv.xy);
159
160 #if UNITY_UV_STARTS_AT_TOP
161 if (_MainTex_TexelSize.y < 0)
162 i.uv.xy = i.uv.xy * half2(1,-1)+half2(0,1);
163 #endif
164
165 half4 tapLow = tex2D (_TapLowBackground, i.uv.xy); // already mixed with medium blur
166 tapHigh = lerp (tapHigh, tapLow, tapHigh.a);
167 return tapHigh;
168 }
169
170 half4 fragDofApplyBgDebug (v2fDofApply i) : SV_Target {
171 half4 tapHigh = tex2D (_MainTex, i.uv.xy);
172
173 half4 tapLow = tex2D (_TapLowBackground, i.uv.xy);
174
175 half4 tapMedium = tex2D (_TapMedium, i.uv.xy);
176 tapMedium.rgb = (tapMedium.rgb + half3 (1, 1, 0)) * 0.5;
177 tapLow.rgb = (tapLow.rgb + half3 (0, 1, 0)) * 0.5;
178
179 tapLow = lerp (tapMedium, tapLow, saturate (tapLow.a * tapLow.a));
180 tapLow = tapLow * 0.5 + tex2D (_TapLowBackground, i.uv.xy) * 0.5;
181
182 return lerp (tapHigh, tapLow, tapHigh.a);
183 }
184
185 half4 fragDofApplyFg (v2fDofApply i) : SV_Target {
186 half4 fgBlur = tex2D(_TapLowForeground, i.uv.xy);
187
188 #if UNITY_UV_STARTS_AT_TOP
189 if (_MainTex_TexelSize.y < 0)
190 i.uv.xy = i.uv.xy * half2(1,-1)+half2(0,1);
191 #endif
192
193 half4 fgColor = tex2D(_MainTex,i.uv.xy);
194
195 //fgBlur.a = saturate(fgBlur.a*_ForegroundBlurWeight+saturate(fgColor.a-fgBlur.a));
196 //fgBlur.a = max (fgColor.a, (2.0 * fgBlur.a - fgColor.a)) * _ForegroundBlurExtrude;
197 fgBlur.a = max(fgColor.a, fgBlur.a * _ForegroundBlurExtrude); //max (fgColor.a, (2.0*fgBlur.a-fgColor.a)) * _ForegroundBlurExtrude;
198
199 return lerp (fgColor, fgBlur, saturate(fgBlur.a));
200 }
201
202 half4 fragDofApplyFgDebug (v2fDofApply i) : SV_Target {
203 half4 fgBlur = tex2D(_TapLowForeground, i.uv.xy);
204
205 half4 fgColor = tex2D(_MainTex,i.uv.xy);
206
207 fgBlur.a = max(fgColor.a, fgBlur.a * _ForegroundBlurExtrude); //max (fgColor.a, (2.0*fgBlur.a-fgColor.a)) * _ForegroundBlurExtrude;
208
209 half4 tapMedium = half4 (1, 1, 0, fgBlur.a);
210 tapMedium.rgb = 0.5 * (tapMedium.rgb + fgColor.rgb);
211
212 fgBlur.rgb = 0.5 * (fgBlur.rgb + half3(0,1,0));
213 fgBlur.rgb = lerp (tapMedium.rgb, fgBlur.rgb, saturate (fgBlur.a * fgBlur.a));
214
215 return lerp ( fgColor, fgBlur, saturate(fgBlur.a));
216 }
217
218 half4 fragCocBg (v2f i) : SV_Target {
219
220 float d = SAMPLE_DEPTH_TEXTURE (_CameraDepthTexture, i.uv1.xy);
221 d = Linear01Depth (d);
222 half coc = 0.0;
223
224 half focalDistance01 = _CurveParams.w + _CurveParams.z;
225
226 if (d > focalDistance01)
227 coc = (d - focalDistance01);
228
229 coc = saturate (coc * _CurveParams.y);
230 return coc;
231 }
232
233 half4 fragCocFg (v2f i) : SV_Target {
234 half4 color = tex2D (_MainTex, i.uv1.xy);
235 color.a = 0.0;
236
237 #if UNITY_UV_STARTS_AT_TOP
238 if (_MainTex_TexelSize.y < 0)
239 i.uv1.xy = i.uv1.xy * half2(1,-1)+half2(0,1);
240 #endif
241
242 float d = SAMPLE_DEPTH_TEXTURE (_CameraDepthTexture, i.uv1.xy);
243 d = Linear01Depth (d);
244
245 half focalDistance01 = (_CurveParams.w - _CurveParams.z);
246
247 if (d < focalDistance01)
248 color.a = (focalDistance01 - d);
249
250 color.a = saturate (color.a * _CurveParams.x);
251 return color;
252 }
253
254 // not being used atm
255
256 half4 fragMask (v2f i) : SV_Target {
257 return half4(0,0,0,0);
258 }
259
260 // used for simple one one blend
261
262 half4 fragAddBokeh (v2f i) : SV_Target {
263 half4 from = tex2D( _MainTex, i.uv1.xy );
264 return from;
265 }
266
267 half4 fragAddFgBokeh (v2f i) : SV_Target {
268 half4 from = tex2D( _MainTex, i.uv1.xy );
269 return from;
270 }
271
272 half4 fragDarkenForBokeh(v2fRadius i) : SV_Target {
273 half4 fromOriginal = tex2D(_MainTex, i.uv.xy);
274 half4 lowRez = BokehPrereqs (_MainTex, i.uv1, fromOriginal, _Threshhold.z);
275 half4 outColor = half4(0,0,0, fromOriginal.a);
276 half modulate = fromOriginal.a;
277
278 // this code imitates the if-then-else conditions below
279 half2 conditionCheck = half2( dot(abs(fromOriginal.rgb-lowRez.rgb), half3(0.3,0.5,0.2)), Luminance(fromOriginal.rgb));
280 conditionCheck *= fromOriginal.a;
281 conditionCheck = saturate(_Threshhold.xy - conditionCheck);
282 outColor = lerp (outColor, fromOriginal, saturate (dot(conditionCheck, half2(1000.0,1000.0))));
283
284 /*
285 if ( abs(dot(fromOriginal.rgb - lowRez.rgb, half3 (0.3,0.5,0.2))) * modulate < _Threshhold.x)
286 outColor = fromOriginal; // no darkening
287 if (Luminance(fromOriginal.rgb) * modulate < _Threshhold.y)
288 outColor = fromOriginal; // no darkening
289 if (lowRez.a < _Threshhold.z) // need to make foreground not cast false bokeh's
290 outColor = fromOriginal; // no darkenin
291 */
292
293 return outColor;
294 }
295
296 half4 fragExtractAndAddToBokeh (v2fRadius i) : SV_Target {
297 half4 from = tex2D(_MainTex, i.uv.xy);
298 half4 lowRez = BokehPrereqs(_MainTex, i.uv1, from, _Threshhold.z);
299 half4 outColor = from;
300
301 // this code imitates the if-then-else conditions below
302 half2 conditionCheck = half2( dot(abs(from.rgb-lowRez.rgb), half3(0.3,0.5,0.2)), Luminance(from.rgb));
303 conditionCheck *= from.a;
304 conditionCheck = saturate(_Threshhold.xy - conditionCheck);
305 outColor = lerp (outColor, half4(0,0,0,0), saturate (dot(conditionCheck, half2(1000.0,1000.0))));
306
307 /*
308 if ( abs(dot(from.rgb - lowRez.rgb, half3 (0.3,0.5,0.2))) * modulate < _Threshhold.x)
309 outColor = half4(0,0,0,0); // don't add
310 if (Luminance(from.rgb) * modulate < _Threshhold.y)
311 outColor = half4(0,0,0,0); // don't add
312 if (lowRez.a < _Threshhold.z) // need to make foreground not cast false bokeh's
313 outColor = half4(0,0,0,0); // don't add
314 */
315
316 return outColor;
317 }
318
319 ENDCG
320
321 Subshader {
322
323 // pass 0
324
325 Pass {
326 ZTest Always Cull Off ZWrite Off
327
328 CGPROGRAM
329 #pragma vertex vertDofApply
330 #pragma fragment fragDofApplyBg
331
332 ENDCG
333 }
334
335 // pass 1
336
337 Pass {
338 ZTest Always Cull Off ZWrite Off
339 ColorMask RGB
340
341 CGPROGRAM
342 #pragma vertex vertDofApply
343 #pragma fragment fragDofApplyFgDebug
344
345 ENDCG
346 }
347
348 // pass 2
349
350 Pass {
351 ZTest Always Cull Off ZWrite Off
352 ColorMask RGB
353
354 CGPROGRAM
355 #pragma vertex vertDofApply
356 #pragma fragment fragDofApplyBgDebug
357
358 ENDCG
359 }
360
361
362
363 // pass 3
364
365 Pass {
366 ZTest Always Cull Off ZWrite Off
367 ColorMask A
368
369 CGPROGRAM
370 #pragma vertex vert
371 #pragma fragment fragCocBg
372
373 ENDCG
374 }
375
376
377 // pass 4
378
379
380 Pass {
381 ZTest Always Cull Off ZWrite Off
382 ColorMask RGB
383 //Blend One One
384
385 CGPROGRAM
386 #pragma vertex vertDofApply
387 #pragma fragment fragDofApplyFg
388
389 ENDCG
390 }
391
392 // pass 5
393
394 Pass {
395 ZTest Always Cull Off ZWrite Off
396 ColorMask ARGB
397
398 CGPROGRAM
399 #pragma vertex vert
400 #pragma fragment fragCocFg
401
402 ENDCG
403 }
404
405 // pass 6
406
407 Pass {
408 ZTest Always Cull Off ZWrite Off
409
410 CGPROGRAM
411 #pragma vertex vertDownsampleWithCocConserve
412 #pragma fragment fragDownsampleWithCocConserve
413
414 ENDCG
415 }
416
417 // pass 7
418 // not being used atm
419
420 Pass {
421 ZTest Always Cull Off ZWrite Off
422 ColorMask RGBA
423
424 CGPROGRAM
425 #pragma vertex vert
426 #pragma fragment fragMask
427
428 ENDCG
429 }
430
431 // pass 8
432
433 Pass {
434 ZTest Always Cull Off ZWrite Off
435 Blend SrcAlpha OneMinusSrcAlpha
436 ColorMask RGB
437
438 CGPROGRAM
439 #pragma vertex vert
440 #pragma fragment fragAddBokeh
441
442 ENDCG
443 }
444
445 // pass 9
446
447 Pass {
448 ZTest Always Cull Off ZWrite Off
449 Blend One One
450 ColorMask RGB
451
452 CGPROGRAM
453 #pragma vertex vertWithRadius
454 #pragma fragment fragExtractAndAddToBokeh
455
456 ENDCG
457 }
458
459 // pass 10
460
461 Pass {
462 ZTest Always Cull Off ZWrite Off
463
464 CGPROGRAM
465 #pragma vertex vertWithRadius
466 #pragma fragment fragDarkenForBokeh
467
468 ENDCG
469 }
470
471 // pass 11
472
473 Pass {
474 ZTest Always Cull Off ZWrite Off
475
476 CGPROGRAM
477 #pragma vertex vertWithRadius
478 #pragma fragment fragExtractAndAddToBokeh
479
480 ENDCG
481 }
482 }
483
484 Fallback off
485
486 }