Statistics
| Branch: | Tag: | Revision:

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
}