root / Assets / Standard Assets / Effects / ImageEffects / Scripts / DepthOfField.cs @ 175:f9f5640c2a3a
History | View | Annotate | Download (18 kB)
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 | } |