1 using System;
2 using
UnityEngine;
3
4 namespace
UnityStandardAssets.ImageEffects
5 {
6     
[ExecuteInEditMode]
7     
[RequireComponent (typeof(Camera))]
8     
[AddComponentMenu ("Image Effects/Camera/Depth of Field (Lens Blur, Scatter, DX11)") ]
9     
public class DepthOfField : PostEffectsBase {
10
11         
public bool visualizeFocus = false;
12         
public float focalLength = 10.0f;
13         
public float focalSize = 0.05f;
14         
public float aperture = 11.5f;
15         
public Transform focalTransform = null;
16         
public float maxBlurSize = 2.0f;
17         
public bool highResolution = false;
18
19         
public enum BlurType {
20             DiscBlur =
0,
21             DX11 =
1,
22         }
23
24         
public enum BlurSampleCount {
25             Low =
0,
26             Medium =
1,
27             High =
2,
28         }
29
30         
public BlurType blurType = BlurType.DiscBlur;
31         
public BlurSampleCount blurSampleCount = BlurSampleCount.High;
32
33         
public bool nearBlur = false;
34         
public float foregroundOverlap = 1.0f;
35
36         
public Shader dofHdrShader;
37         
private Material dofHdrMaterial = null;
38
39         
public Shader dx11BokehShader;
40         
private Material dx11bokehMaterial;
41
42         
public float dx11BokehThreshold = 0.5f;
43         
public float dx11SpawnHeuristic = 0.0875f;
44         
public Texture2D dx11BokehTexture = null;
45         
public float dx11BokehScale = 1.2f;
46         
public float dx11BokehIntensity = 2.5f;
47
48         
private float focalDistance01 = 10.0f;
49         
private ComputeBuffer cbDrawArgs;
50         
private ComputeBuffer cbPoints;
51         
private float internalBlurWidth = 1.0f;
52
53
54         
public override bool CheckResources () {
55             CheckSupport (
true); // only requires depth, not HDR
56
57             dofHdrMaterial = CheckShaderAndCreateMaterial (dofHdrShader, dofHdrMaterial);
58             
if (supportDX11 && blurType == BlurType.DX11) {
59                 dx11bokehMaterial = CheckShaderAndCreateMaterial(dx11BokehShader, dx11bokehMaterial);
60                 CreateComputeResources ();
61             }
62
63             
if (!isSupported)
64                 ReportAutoDisable ();
65
66             
return isSupported;
67         }
68
69         
void OnEnable () {
70             GetComponent<Camera>().depthTextureMode |= DepthTextureMode.Depth;
71         }
72
73         
void OnDisable () {
74             ReleaseComputeResources ();
75
76             
if (dofHdrMaterial) DestroyImmediate(dofHdrMaterial);
77             dofHdrMaterial =
null;
78             
if (dx11bokehMaterial) DestroyImmediate(dx11bokehMaterial);
79             dx11bokehMaterial =
null;
80         }
81
82         
void ReleaseComputeResources () {
83             
if (cbDrawArgs != null) cbDrawArgs.Release();
84             cbDrawArgs =
null;
85             
if (cbPoints != null) cbPoints.Release();
86             cbPoints =
null;
87         }
88
89         
void CreateComputeResources () {
90             
if (cbDrawArgs == null)
91             {
92                 cbDrawArgs =
new ComputeBuffer (1, 16, ComputeBufferType.IndirectArguments);
93                 
var args= new int[4];
94                 args[
0] = 0; args[1] = 1; args[2] = 0; args[3] = 0;
95                 cbDrawArgs.SetData (args);
96             }
97             
if (cbPoints == null)
98             {
99                 cbPoints =
new ComputeBuffer (90000, 12+16, ComputeBufferType.Append);
100             }
101         }
102
103         
float FocalDistance01 ( float worldDist) {
104             
return GetComponent<Camera>().WorldToViewportPoint((worldDist-GetComponent<Camera>().nearClipPlane) * GetComponent<Camera>().transform.forward + GetComponent<Camera>().transform.position).z / (GetComponent<Camera>().farClipPlane-GetComponent<Camera>().nearClipPlane);
105         }
106
107         
private void WriteCoc ( RenderTexture fromTo, bool fgDilate) {
108             dofHdrMaterial.SetTexture(
"_FgOverlap", null);
109
110             
if (nearBlur && fgDilate) {
111
112                 
int rtW = fromTo.width/2;
113                 
int rtH = fromTo.height/2;
114
115                 
// capture fg coc
116                 RenderTexture temp2 = RenderTexture.GetTemporary (rtW, rtH,
0, fromTo.format);
117                 Graphics.Blit (fromTo, temp2, dofHdrMaterial,
4);
118
119                 
// special blur
120                 
float fgAdjustment = internalBlurWidth * foregroundOverlap;
121
122                 dofHdrMaterial.SetVector (
"_Offsets", new Vector4 (0.0f, fgAdjustment , 0.0f, fgAdjustment));
123                 RenderTexture temp1 = RenderTexture.GetTemporary (rtW, rtH,
0, fromTo.format);
124                 Graphics.Blit (temp2, temp1, dofHdrMaterial,
2);
125                 RenderTexture.ReleaseTemporary(temp2);
126
127                 dofHdrMaterial.SetVector (
"_Offsets", new Vector4 (fgAdjustment, 0.0f, 0.0f, fgAdjustment));
128                 temp2 = RenderTexture.GetTemporary (rtW, rtH,
0, fromTo.format);
129                 Graphics.Blit (temp1, temp2, dofHdrMaterial,
2);
130                 RenderTexture.ReleaseTemporary(temp1);
131
132                 
// "merge up" with background COC
133                 dofHdrMaterial.SetTexture(
"_FgOverlap", temp2);
134                 fromTo.MarkRestoreExpected();
// only touching alpha channel, RT restore expected
135                 Graphics.Blit (fromTo, fromTo, dofHdrMaterial,
13);
136                 RenderTexture.ReleaseTemporary(temp2);
137             }
138             
else {
139                 
// capture full coc in alpha channel (fromTo is not read, but bound to detect screen flip)
140                 fromTo.MarkRestoreExpected();
// only touching alpha channel, RT restore expected
141                 Graphics.Blit (fromTo, fromTo, dofHdrMaterial,
0);
142             }
143         }
144
145         
void OnRenderImage (RenderTexture source, RenderTexture destination) {
146             
if (!CheckResources ()) {
147                 Graphics.Blit (source, destination);
148                 
return;
149             }
150
151             
// clamp & prepare values so they make sense
152
153             
if (aperture < 0.0f) aperture = 0.0f;
154             
if (maxBlurSize < 0.1f) maxBlurSize = 0.1f;
155             focalSize = Mathf.Clamp(focalSize,
0.0f, 2.0f);
156             internalBlurWidth = Mathf.Max(maxBlurSize,
0.0f);
157
158             
// focal & coc calculations
159
160             focalDistance01 = (focalTransform) ? (GetComponent<Camera>().WorldToViewportPoint (focalTransform.position)).z / (GetComponent<Camera>().farClipPlane) : FocalDistance01 (focalLength);
161             dofHdrMaterial.SetVector (
"_CurveParams", new Vector4 (1.0f, focalSize, aperture/10.0f, focalDistance01));
162
163             
// possible render texture helpers
164
165             RenderTexture rtLow =
null;
166             RenderTexture rtLow2 =
null;
167             RenderTexture rtSuperLow1 =
null;
168             RenderTexture rtSuperLow2 =
null;
169             
float fgBlurDist = internalBlurWidth * foregroundOverlap;
170
171             
if (visualizeFocus)
172             {
173
174                 
//
175                 
// 2.
176                 
// visualize coc
177                 
//
178                 
//
179
180                 WriteCoc (source,
true);
181                 Graphics.Blit (source, destination, dofHdrMaterial,
16);
182             }
183             
else if ((blurType == BlurType.DX11) && dx11bokehMaterial)
184             {
185
186                 
//
187                 
// 1.
188                 
// optimized dx11 bokeh scatter
189                 
//
190                 
//
191
192
193                 
if (highResolution) {
194
195                     internalBlurWidth = internalBlurWidth <
0.1f ? 0.1f : internalBlurWidth;
196                     fgBlurDist = internalBlurWidth * foregroundOverlap;
197
198                     rtLow = RenderTexture.GetTemporary (source.width, source.height,
0, source.format);
199
200                     
var dest2= RenderTexture.GetTemporary (source.width, source.height, 0, source.format);
201
202                     
// capture COC
203                     WriteCoc (source,
false);
204
205                     
// blur a bit so we can do a frequency check
206                     rtSuperLow1 = RenderTexture.GetTemporary(source.width>>
1, source.height>>1, 0, source.format);
207                     rtSuperLow2 = RenderTexture.GetTemporary(source.width>>
1, source.height>>1, 0, source.format);
208
209                     Graphics.Blit(source, rtSuperLow1, dofHdrMaterial,
15);
210                     dofHdrMaterial.SetVector (
"_Offsets", new Vector4 (0.0f, 1.5f , 0.0f, 1.5f));
211                     Graphics.Blit (rtSuperLow1, rtSuperLow2, dofHdrMaterial,
19);
212                     dofHdrMaterial.SetVector (
"_Offsets", new Vector4 (1.5f, 0.0f, 0.0f, 1.5f));
213                     Graphics.Blit (rtSuperLow2, rtSuperLow1, dofHdrMaterial,
19);
214
215                     
// capture fg coc
216                     
if (nearBlur)
217                         Graphics.Blit (source, rtSuperLow2, dofHdrMaterial,
4);
218
219                     dx11bokehMaterial.SetTexture (
"_BlurredColor", rtSuperLow1);
220                     dx11bokehMaterial.SetFloat (
"_SpawnHeuristic", dx11SpawnHeuristic);
221                     dx11bokehMaterial.SetVector (
"_BokehParams", new Vector4(dx11BokehScale, dx11BokehIntensity, Mathf.Clamp(dx11BokehThreshold, 0.005f, 4.0f), internalBlurWidth));
222                     dx11bokehMaterial.SetTexture (
"_FgCocMask", nearBlur ? rtSuperLow2 : null);
223
224                     
// collect bokeh candidates and replace with a darker pixel
225                     Graphics.SetRandomWriteTarget (
1, cbPoints);
226                     Graphics.Blit (source, rtLow, dx11bokehMaterial,
0);
227                     Graphics.ClearRandomWriteTargets ();
228
229                     
// fg coc blur happens here (after collect!)
230                     
if (nearBlur) {
231                         dofHdrMaterial.SetVector (
"_Offsets", new Vector4 (0.0f, fgBlurDist , 0.0f, fgBlurDist));
232                         Graphics.Blit (rtSuperLow2, rtSuperLow1, dofHdrMaterial,
2);
233                         dofHdrMaterial.SetVector (
"_Offsets", new Vector4 (fgBlurDist, 0.0f, 0.0f, fgBlurDist));
234                         Graphics.Blit (rtSuperLow1, rtSuperLow2, dofHdrMaterial,
2);
235
236                         
// merge fg coc with bg coc
237                         Graphics.Blit (rtSuperLow2, rtLow, dofHdrMaterial,
3);
238                     }
239
240                     
// NEW: LAY OUT ALPHA on destination target so we get nicer outlines for the high rez version
241                     Graphics.Blit (rtLow, dest2, dofHdrMaterial,
20);
242
243                     
// box blur (easier to merge with bokeh buffer)
244                     dofHdrMaterial.SetVector (
"_Offsets", new Vector4 (internalBlurWidth, 0.0f , 0.0f, internalBlurWidth));
245                     Graphics.Blit (rtLow, source, dofHdrMaterial,
5);
246                     dofHdrMaterial.SetVector (
"_Offsets", new Vector4 (0.0f, internalBlurWidth, 0.0f, internalBlurWidth));
247                     Graphics.Blit (source, dest2, dofHdrMaterial,
21);
248
249                     
// apply bokeh candidates
250                     Graphics.SetRenderTarget (dest2);
251                     ComputeBuffer.CopyCount (cbPoints, cbDrawArgs,
0);
252                     dx11bokehMaterial.SetBuffer (
"pointBuffer", cbPoints);
253                     dx11bokehMaterial.SetTexture (
"_MainTex", dx11BokehTexture);
254                     dx11bokehMaterial.SetVector (
"_Screen", new Vector3(1.0f/(1.0f*source.width), 1.0f/(1.0f*source.height), internalBlurWidth));
255                     dx11bokehMaterial.SetPass (
2);
256
257                     Graphics.DrawProceduralIndirect (MeshTopology.Points, cbDrawArgs,
0);
258
259                     Graphics.Blit (dest2, destination);
// hackaround for DX11 high resolution flipfun (OPTIMIZEME)
260
261                     RenderTexture.ReleaseTemporary(dest2);
262                     RenderTexture.ReleaseTemporary(rtSuperLow1);
263                     RenderTexture.ReleaseTemporary(rtSuperLow2);
264                 }
265                 
else {
266                     rtLow = RenderTexture.GetTemporary (source.width>>
1, source.height>>1, 0, source.format);
267                     rtLow2 = RenderTexture.GetTemporary (source.width>>
1, source.height>>1, 0, source.format);
268
269                     fgBlurDist = internalBlurWidth * foregroundOverlap;
270
271                     
// capture COC & color in low resolution
272                     WriteCoc (source,
false);
273                     source.filterMode = FilterMode.Bilinear;
274                     Graphics.Blit (source, rtLow, dofHdrMaterial,
6);
275
276                     
// blur a bit so we can do a frequency check
277                     rtSuperLow1 = RenderTexture.GetTemporary(rtLow.width>>
1, rtLow.height>>1, 0, rtLow.format);
278                     rtSuperLow2 = RenderTexture.GetTemporary(rtLow.width>>
1, rtLow.height>>1, 0, rtLow.format);
279
280                     Graphics.Blit(rtLow, rtSuperLow1, dofHdrMaterial,
15);
281                     dofHdrMaterial.SetVector (
"_Offsets", new Vector4 (0.0f, 1.5f , 0.0f, 1.5f));
282                     Graphics.Blit (rtSuperLow1, rtSuperLow2, dofHdrMaterial,
19);
283                     dofHdrMaterial.SetVector (
"_Offsets", new Vector4 (1.5f, 0.0f, 0.0f, 1.5f));
284                     Graphics.Blit (rtSuperLow2, rtSuperLow1, dofHdrMaterial,
19);
285
286                     RenderTexture rtLow3 =
null;
287
288                     
if (nearBlur) {
289                         
// capture fg coc
290                         rtLow3 = RenderTexture.GetTemporary (source.width>>
1, source.height>>1, 0, source.format);
291                         Graphics.Blit (source, rtLow3, dofHdrMaterial,
4);
292                     }
293
294                     dx11bokehMaterial.SetTexture (
"_BlurredColor", rtSuperLow1);
295                     dx11bokehMaterial.SetFloat (
"_SpawnHeuristic", dx11SpawnHeuristic);
296                     dx11bokehMaterial.SetVector (
"_BokehParams", new Vector4(dx11BokehScale, dx11BokehIntensity, Mathf.Clamp(dx11BokehThreshold, 0.005f, 4.0f), internalBlurWidth));
297                     dx11bokehMaterial.SetTexture (
"_FgCocMask", rtLow3);
298
299                     
// collect bokeh candidates and replace with a darker pixel
300                     Graphics.SetRandomWriteTarget (
1, cbPoints);
301                     Graphics.Blit (rtLow, rtLow2, dx11bokehMaterial,
0);
302                     Graphics.ClearRandomWriteTargets ();
303
304                     RenderTexture.ReleaseTemporary(rtSuperLow1);
305                     RenderTexture.ReleaseTemporary(rtSuperLow2);
306
307                     
// fg coc blur happens here (after collect!)
308                     
if (nearBlur) {
309                         dofHdrMaterial.SetVector (
"_Offsets", new Vector4 (0.0f, fgBlurDist , 0.0f, fgBlurDist));
310                         Graphics.Blit (rtLow3, rtLow, dofHdrMaterial,
2);
311                         dofHdrMaterial.SetVector (
"_Offsets", new Vector4 (fgBlurDist, 0.0f, 0.0f, fgBlurDist));
312                         Graphics.Blit (rtLow, rtLow3, dofHdrMaterial,
2);
313
314                         
// merge fg coc with bg coc
315                         Graphics.Blit (rtLow3, rtLow2, dofHdrMaterial,
3);
316                     }
317
318                     
// box blur (easier to merge with bokeh buffer)
319                     dofHdrMaterial.SetVector (
"_Offsets", new Vector4 (internalBlurWidth, 0.0f , 0.0f, internalBlurWidth));
320                     Graphics.Blit (rtLow2, rtLow, dofHdrMaterial,
5);
321                     dofHdrMaterial.SetVector (
"_Offsets", new Vector4 (0.0f, internalBlurWidth, 0.0f, internalBlurWidth));
322                     Graphics.Blit (rtLow, rtLow2, dofHdrMaterial,
5);
323
324                     
// apply bokeh candidates
325                     Graphics.SetRenderTarget (rtLow2);
326                     ComputeBuffer.CopyCount (cbPoints, cbDrawArgs,
0);
327                     dx11bokehMaterial.SetBuffer (
"pointBuffer", cbPoints);
328                     dx11bokehMaterial.SetTexture (
"_MainTex", dx11BokehTexture);
329                     dx11bokehMaterial.SetVector (
"_Screen", new Vector3(1.0f/(1.0f*rtLow2.width), 1.0f/(1.0f*rtLow2.height), internalBlurWidth));
330                     dx11bokehMaterial.SetPass (
1);
331                     Graphics.DrawProceduralIndirect (MeshTopology.Points, cbDrawArgs,
0);
332
333                     
// upsample & combine
334                     dofHdrMaterial.SetTexture (
"_LowRez", rtLow2);
335                     dofHdrMaterial.SetTexture (
"_FgOverlap", rtLow3);
336                     dofHdrMaterial.SetVector (
"_Offsets", ((1.0f*source.width)/(1.0f*rtLow2.width)) * internalBlurWidth * Vector4.one);
337                     Graphics.Blit (source, destination, dofHdrMaterial,
9);
338
339                     
if (rtLow3) RenderTexture.ReleaseTemporary(rtLow3);
340                 }
341             }
342             
else
343             {
344
345                 
//
346                 
// 2.
347                 
// poisson disc style blur in low resolution
348                 
//
349                 
//
350
351                 source.filterMode = FilterMode.Bilinear;
352
353                 
if (highResolution) internalBlurWidth *= 2.0f;
354
355                 WriteCoc (source,
true);
356
357                 rtLow = RenderTexture.GetTemporary (source.width >>
1, source.height >> 1, 0, source.format);
358                 rtLow2 = RenderTexture.GetTemporary (source.width >>
1, source.height >> 1, 0, source.format);
359
360                 
int blurPass = (blurSampleCount == BlurSampleCount.High || blurSampleCount == BlurSampleCount.Medium) ? 17 : 11;
361
362                 
if (highResolution) {
363                     dofHdrMaterial.SetVector (
"_Offsets", new Vector4 (0.0f, internalBlurWidth, 0.025f, internalBlurWidth));
364                     Graphics.Blit (source, destination, dofHdrMaterial, blurPass);
365                 }
366                 
else {
367                     dofHdrMaterial.SetVector (
"_Offsets", new Vector4 (0.0f, internalBlurWidth, 0.1f, internalBlurWidth));
368
369                     
// blur
370                     Graphics.Blit (source, rtLow, dofHdrMaterial,
6);
371                     Graphics.Blit (rtLow, rtLow2, dofHdrMaterial, blurPass);
372
373                     
// cheaper blur in high resolution, upsample and combine
374                     dofHdrMaterial.SetTexture(
"_LowRez", rtLow2);
375                     dofHdrMaterial.SetTexture(
"_FgOverlap", null);
376                     dofHdrMaterial.SetVector (
"_Offsets", Vector4.one * ((1.0f*source.width)/(1.0f*rtLow2.width)) * internalBlurWidth);
377                     Graphics.Blit (source, destination, dofHdrMaterial, blurSampleCount == BlurSampleCount.High ?
18 : 12);
378                 }
379             }
380
381             
if (rtLow) RenderTexture.ReleaseTemporary(rtLow);
382             
if (rtLow2) RenderTexture.ReleaseTemporary(rtLow2);
383         }
384     }
385 }


CheckSupport (true); only requires depth, not HDR

capture fg coc

special blur

"merge up" with background COC

fromTo.MarkRestoreExpected(); only touching alpha channel, RT restore expected

capture full coc in alpha channel (fromTo is not read, but bound to detect screen flip)

fromTo.MarkRestoreExpected(); only touching alpha channel, RT restore expected

clamp & prepare values so they make sense

focal & coc calculations

possible render texture helpers

2.

visualize coc

1.

optimized dx11 bokeh scatter

capture COC

blur a bit so we can do a frequency check

capture fg coc

collect bokeh candidates and replace with a darker pixel

fg coc blur happens here (after collect!)

merge fg coc with bg coc

NEW: LAY OUT ALPHA on destination target so we get nicer outlines for the high rez version

box blur (easier to merge with bokeh buffer)

apply bokeh candidates

Graphics.Blit (dest2, destination); hackaround for DX11 high resolution flipfun (OPTIMIZEME)

capture COC & color in low resolution

blur a bit so we can do a frequency check

capture fg coc

collect bokeh candidates and replace with a darker pixel

fg coc blur happens here (after collect!)

merge fg coc with bg coc

box blur (easier to merge with bokeh buffer)

apply bokeh candidates

upsample & combine

2.

poisson disc style blur in low resolution

blur

cheaper blur in high resolution, upsample and combine



Gõ tìm kiếm nhanh...