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


Xem tìm kiếm...