UnityMol  0.9.6-875
UnityMol viewer / In developement
DepthOfField.cs
Go to the documentation of this file.
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 
85  if (cbDrawArgs != null) cbDrawArgs.Release();
86  cbDrawArgs = null;
87  if (cbPoints != null) cbPoints.Release();
88  cbPoints = null;
89  }
90 
92  if (cbDrawArgs == null)
93  {
94  cbDrawArgs = new ComputeBuffer (1, 16, ComputeBufferType.DrawIndirect);
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 }
void OnRenderImage(RenderTexture source, RenderTexture destination)
void WriteCoc(RenderTexture fromTo, bool fgDilate)