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 (deprecated)") ]
9 public class DepthOfFieldDeprecated : PostEffectsBase
10 {
11 public enum Dof34QualitySetting
12 {
13 OnlyBackground = 1,
14 BackgroundAndForeground = 2,
15 }
16
17 public enum DofResolution
18 {
19 High = 2,
20 Medium = 3,
21 Low = 4,
22 }
23
24 public enum DofBlurriness
25 {
26 Low = 1,
27 High = 2,
28 VeryHigh = 4,
29 }
30
31 public enum BokehDestination
32 {
33 Background = 0x1,
34 Foreground = 0x2,
35 BackgroundAndForeground = 0x3,
36 }
37
38 static private int SMOOTH_DOWNSAMPLE_PASS = 6;
39 static private float BOKEH_EXTRA_BLUR = 2.0f;
40
41 public Dof34QualitySetting quality = Dof34QualitySetting.OnlyBackground;
42 public DofResolution resolution = DofResolution.Low;
43 public bool simpleTweakMode = true;
44
45 public float focalPoint = 1.0f;
46 public float smoothness = 0.5f;
47
48 public float focalZDistance = 0.0f;
49 public float focalZStartCurve = 1.0f;
50 public float focalZEndCurve = 1.0f;
51
52 private float focalStartCurve = 2.0f;
53 private float focalEndCurve = 2.0f;
54 private float focalDistance01 = 0.1f;
55
56 public Transform objectFocus = null;
57 public float focalSize = 0.0f;
58
59 public DofBlurriness bluriness = DofBlurriness.High;
60 public float maxBlurSpread = 1.75f;
61
62 public float foregroundBlurExtrude = 1.15f;
63
64 public Shader dofBlurShader;
65 private Material dofBlurMaterial = null;
66
67 public Shader dofShader;
68 private Material dofMaterial = null;
69
70 public bool visualize = false;
71 public BokehDestination bokehDestination = BokehDestination.Background;
72
73 private float widthOverHeight = 1.25f;
74 private float oneOverBaseSize = 1.0f / 512.0f;
75
76 public bool bokeh = false;
77 public bool bokehSupport = true;
78 public Shader bokehShader;
79 public Texture2D bokehTexture;
80 public float bokehScale = 2.4f;
81 public float bokehIntensity = 0.15f;
82 public float bokehThresholdContrast = 0.1f;
83 public float bokehThresholdLuminance = 0.55f;
84 public int bokehDownsample = 1;
85 private Material bokehMaterial;
86
87 private Camera _camera;
88
89 void CreateMaterials () {
90 dofBlurMaterial = CheckShaderAndCreateMaterial (dofBlurShader, dofBlurMaterial);
91 dofMaterial = CheckShaderAndCreateMaterial (dofShader,dofMaterial);
92 bokehSupport = bokehShader.isSupported;
93
94 if (bokeh && bokehSupport && bokehShader)
95 bokehMaterial = CheckShaderAndCreateMaterial (bokehShader, bokehMaterial);
96 }
97
98
99 public override bool CheckResources () {
100 CheckSupport (true);
101
102 dofBlurMaterial = CheckShaderAndCreateMaterial (dofBlurShader, dofBlurMaterial);
103 dofMaterial = CheckShaderAndCreateMaterial (dofShader,dofMaterial);
104 bokehSupport = bokehShader.isSupported;
105
106 if (bokeh && bokehSupport && bokehShader)
107 bokehMaterial = CheckShaderAndCreateMaterial (bokehShader, bokehMaterial);
108
109 if (!isSupported)
110 ReportAutoDisable ();
111 return isSupported;
112 }
113
114 void OnDisable () {
115 Quads.Cleanup ();
116 }
117
118 void OnEnable () {
119 _camera = GetComponent<Camera>();
120 _camera.depthTextureMode |= DepthTextureMode.Depth;
121 }
122
123 float FocalDistance01 ( float worldDist) {
124 return _camera.WorldToViewportPoint((worldDist-_camera.nearClipPlane) * _camera.transform.forward + _camera.transform.position).z / (_camera.farClipPlane-_camera.nearClipPlane);
125 }
126
127 int GetDividerBasedOnQuality () {
128 int divider = 1;
129 if (resolution == DofResolution.Medium)
130 divider = 2;
131 else if (resolution == DofResolution.Low)
132 divider = 2;
133 return divider;
134 }
135
136 int GetLowResolutionDividerBasedOnQuality ( int baseDivider) {
137 int lowTexDivider = baseDivider;
138 if (resolution == DofResolution.High)
139 lowTexDivider *= 2;
140 if (resolution == DofResolution.Low)
141 lowTexDivider *= 2;
142 return lowTexDivider;
143 }
144
145 private RenderTexture foregroundTexture = null;
146 private RenderTexture mediumRezWorkTexture = null;
147 private RenderTexture finalDefocus = null;
148 private RenderTexture lowRezWorkTexture = null;
149 private RenderTexture bokehSource = null;
150 private RenderTexture bokehSource2 = null;
151
152 void OnRenderImage (RenderTexture source, RenderTexture destination) {
153 if (CheckResources()==false) {
154 Graphics.Blit (source, destination);
155 return;
156 }
157
158 if (smoothness < 0.1f)
159 smoothness = 0.1f;
160
161 // update needed focal & rt size parameter
162
163 bokeh = bokeh && bokehSupport;
164 float bokehBlurAmplifier = bokeh ? BOKEH_EXTRA_BLUR : 1.0f;
165
166 bool blurForeground = quality > Dof34QualitySetting.OnlyBackground;
167 float focal01Size = focalSize / (_camera.farClipPlane - _camera.nearClipPlane);;
168
169 if (simpleTweakMode) {
170 focalDistance01 = objectFocus ? (_camera.WorldToViewportPoint (objectFocus.position)).z / (_camera.farClipPlane) : FocalDistance01 (focalPoint);
171 focalStartCurve = focalDistance01 * smoothness;
172 focalEndCurve = focalStartCurve;
173 blurForeground = blurForeground && (focalPoint > (_camera.nearClipPlane + Mathf.Epsilon));
174 }
175 else {
176 if (objectFocus) {
177 var vpPoint= _camera.WorldToViewportPoint (objectFocus.position);
178 vpPoint.z = (vpPoint.z) / (_camera.farClipPlane);
179 focalDistance01 = vpPoint.z;
180 }
181 else
182 focalDistance01 = FocalDistance01 (focalZDistance);
183
184 focalStartCurve = focalZStartCurve;
185 focalEndCurve = focalZEndCurve;
186 blurForeground = blurForeground && (focalPoint > (_camera.nearClipPlane + Mathf.Epsilon));
187 }
188
189 widthOverHeight = (1.0f * source.width) / (1.0f * source.height);
190 oneOverBaseSize = 1.0f / 512.0f;
191
192 dofMaterial.SetFloat ("_ForegroundBlurExtrude", foregroundBlurExtrude);
193 dofMaterial.SetVector ("_CurveParams", new Vector4 (simpleTweakMode ? 1.0f / focalStartCurve : focalStartCurve, simpleTweakMode ? 1.0f / focalEndCurve : focalEndCurve, focal01Size * 0.5f, focalDistance01));
194 dofMaterial.SetVector ("_InvRenderTargetSize", new Vector4 (1.0f / (1.0f * source.width), 1.0f / (1.0f * source.height),0.0f,0.0f));
195
196 int divider = GetDividerBasedOnQuality ();
197 int lowTexDivider = GetLowResolutionDividerBasedOnQuality (divider);
198
199 AllocateTextures (blurForeground, source, divider, lowTexDivider);
200
201 // WRITE COC to alpha channel
202 // source is only being bound to detect y texcoord flip
203 Graphics.Blit (source, source, dofMaterial, 3);
204
205 // better DOWNSAMPLE (could actually be weighted for higher quality)
206 Downsample (source, mediumRezWorkTexture);
207
208 // BLUR A LITTLE first, which has two purposes
209 // 1.) reduce jitter, noise, aliasing
210 // 2.) produce the little-blur buffer used in composition later
211 Blur (mediumRezWorkTexture, mediumRezWorkTexture, DofBlurriness.Low, 4, maxBlurSpread);
212
213 if ((bokeh) && ((BokehDestination.Foreground & bokehDestination) != 0))
214 {
215 dofMaterial.SetVector ("_Threshhold", new Vector4(bokehThresholdContrast, bokehThresholdLuminance, 0.95f, 0.0f));
216
217 // add and mark the parts that should end up as bokeh shapes
218 Graphics.Blit (mediumRezWorkTexture, bokehSource2, dofMaterial, 11);
219
220 // remove those parts (maybe even a little tittle bittle more) from the regurlarly blurred buffer
221 //Graphics.Blit (mediumRezWorkTexture, lowRezWorkTexture, dofMaterial, 10);
222 Graphics.Blit (mediumRezWorkTexture, lowRezWorkTexture);//, dofMaterial, 10);
223
224 // maybe you want to reblur the small blur ... but not really needed.
225 //Blur (mediumRezWorkTexture, mediumRezWorkTexture, DofBlurriness.Low, 4, maxBlurSpread);
226
227 // bigger BLUR
228 Blur (lowRezWorkTexture, lowRezWorkTexture, bluriness, 0, maxBlurSpread * bokehBlurAmplifier);
229 }
230 else {
231 // bigger BLUR
232 Downsample (mediumRezWorkTexture, lowRezWorkTexture);
233 Blur (lowRezWorkTexture, lowRezWorkTexture, bluriness, 0, maxBlurSpread);
234 }
235
236 dofBlurMaterial.SetTexture ("_TapLow", lowRezWorkTexture);
237 dofBlurMaterial.SetTexture ("_TapMedium", mediumRezWorkTexture);
238 Graphics.Blit (null, finalDefocus, dofBlurMaterial, 3);
239
240 // we are only adding bokeh now if the background is the only part we have to deal with
241 if ((bokeh) && ((BokehDestination.Foreground & bokehDestination) != 0))
242 AddBokeh (bokehSource2, bokehSource, finalDefocus);
243
244 dofMaterial.SetTexture ("_TapLowBackground", finalDefocus);
245 dofMaterial.SetTexture ("_TapMedium", mediumRezWorkTexture); // needed for debugging/visualization
246
247 // FINAL DEFOCUS (background)
248 Graphics.Blit (source, blurForeground ? foregroundTexture : destination, dofMaterial, visualize ? 2 : 0);
249
250 // FINAL DEFOCUS (foreground)
251 if (blurForeground) {
252 // WRITE COC to alpha channel
253 Graphics.Blit (foregroundTexture, source, dofMaterial, 5);
254
255 // DOWNSAMPLE (unweighted)
256 Downsample (source, mediumRezWorkTexture);
257
258 // BLUR A LITTLE first, which has two purposes
259 // 1.) reduce jitter, noise, aliasing
260 // 2.) produce the little-blur buffer used in composition later
261 BlurFg (mediumRezWorkTexture, mediumRezWorkTexture, DofBlurriness.Low, 2, maxBlurSpread);
262
263 if ((bokeh) && ((BokehDestination.Foreground & bokehDestination) != 0))
264 {
265 dofMaterial.SetVector ("_Threshhold", new Vector4(bokehThresholdContrast * 0.5f, bokehThresholdLuminance, 0.0f, 0.0f));
266
267 // add and mark the parts that should end up as bokeh shapes
268 Graphics.Blit (mediumRezWorkTexture, bokehSource2, dofMaterial, 11);
269
270 // remove the parts (maybe even a little tittle bittle more) that will end up in bokeh space
271 //Graphics.Blit (mediumRezWorkTexture, lowRezWorkTexture, dofMaterial, 10);
272 Graphics.Blit (mediumRezWorkTexture, lowRezWorkTexture);//, dofMaterial, 10);
273
274 // big BLUR
275 BlurFg (lowRezWorkTexture, lowRezWorkTexture, bluriness, 1, maxBlurSpread * bokehBlurAmplifier);
276 }
277 else {
278 // big BLUR
279 BlurFg (mediumRezWorkTexture, lowRezWorkTexture, bluriness, 1, maxBlurSpread);
280 }
281
282 // simple upsample once
283 Graphics.Blit (lowRezWorkTexture, finalDefocus);
284
285 dofMaterial.SetTexture ("_TapLowForeground", finalDefocus);
286 Graphics.Blit (source, destination, dofMaterial, visualize ? 1 : 4);
287
288 if ((bokeh) && ((BokehDestination.Foreground & bokehDestination) != 0))
289 AddBokeh (bokehSource2, bokehSource, destination);
290 }
291
292 ReleaseTextures ();
293 }
294
295 void Blur ( RenderTexture from, RenderTexture to, DofBlurriness iterations, int blurPass, float spread) {
296 RenderTexture tmp = RenderTexture.GetTemporary (to.width, to.height);
297 if ((int)iterations > 1) {
298 BlurHex (from, to, blurPass, spread, tmp);
299 if ((int)iterations > 2) {
300 dofBlurMaterial.SetVector ("offsets", new Vector4 (0.0f, spread * oneOverBaseSize, 0.0f, 0.0f));
301 Graphics.Blit (to, tmp, dofBlurMaterial, blurPass);
302 dofBlurMaterial.SetVector ("offsets", new Vector4 (spread / widthOverHeight * oneOverBaseSize, 0.0f, 0.0f, 0.0f));
303 Graphics.Blit (tmp, to, dofBlurMaterial, blurPass);
304 }
305 }
306 else {
307 dofBlurMaterial.SetVector ("offsets", new Vector4 (0.0f, spread * oneOverBaseSize, 0.0f, 0.0f));
308 Graphics.Blit (from, tmp, dofBlurMaterial, blurPass);
309 dofBlurMaterial.SetVector ("offsets", new Vector4 (spread / widthOverHeight * oneOverBaseSize, 0.0f, 0.0f, 0.0f));
310 Graphics.Blit (tmp, to, dofBlurMaterial, blurPass);
311 }
312 RenderTexture.ReleaseTemporary (tmp);
313 }
314
315 void BlurFg ( RenderTexture from, RenderTexture to, DofBlurriness iterations, int blurPass, float spread) {
316 // we want a nice, big coc, hence we need to tap once from this (higher resolution) texture
317 dofBlurMaterial.SetTexture ("_TapHigh", from);
318
319 RenderTexture tmp = RenderTexture.GetTemporary (to.width, to.height);
320 if ((int)iterations > 1) {
321 BlurHex (from, to, blurPass, spread, tmp);
322 if ((int)iterations > 2) {
323 dofBlurMaterial.SetVector ("offsets", new Vector4 (0.0f, spread * oneOverBaseSize, 0.0f, 0.0f));
324 Graphics.Blit (to, tmp, dofBlurMaterial, blurPass);
325 dofBlurMaterial.SetVector ("offsets", new Vector4 (spread / widthOverHeight * oneOverBaseSize, 0.0f, 0.0f, 0.0f));
326 Graphics.Blit (tmp, to, dofBlurMaterial, blurPass);
327 }
328 }
329 else {
330 dofBlurMaterial.SetVector ("offsets", new Vector4 (0.0f, spread * oneOverBaseSize, 0.0f, 0.0f));
331 Graphics.Blit (from, tmp, dofBlurMaterial, blurPass);
332 dofBlurMaterial.SetVector ("offsets", new Vector4 (spread / widthOverHeight * oneOverBaseSize, 0.0f, 0.0f, 0.0f));
333 Graphics.Blit (tmp, to, dofBlurMaterial, blurPass);
334 }
335 RenderTexture.ReleaseTemporary (tmp);
336 }
337
338 void BlurHex ( RenderTexture from, RenderTexture to, int blurPass, float spread, RenderTexture tmp) {
339 dofBlurMaterial.SetVector ("offsets", new Vector4 (0.0f, spread * oneOverBaseSize, 0.0f, 0.0f));
340 Graphics.Blit (from, tmp, dofBlurMaterial, blurPass);
341 dofBlurMaterial.SetVector ("offsets", new Vector4 (spread / widthOverHeight * oneOverBaseSize, 0.0f, 0.0f, 0.0f));
342 Graphics.Blit (tmp, to, dofBlurMaterial, blurPass);
343 dofBlurMaterial.SetVector ("offsets", new Vector4 (spread / widthOverHeight * oneOverBaseSize, spread * oneOverBaseSize, 0.0f, 0.0f));
344 Graphics.Blit (to, tmp, dofBlurMaterial, blurPass);
345 dofBlurMaterial.SetVector ("offsets", new Vector4 (spread / widthOverHeight * oneOverBaseSize, -spread * oneOverBaseSize, 0.0f, 0.0f));
346 Graphics.Blit (tmp, to, dofBlurMaterial, blurPass);
347 }
348
349 void Downsample ( RenderTexture from, RenderTexture to) {
350 dofMaterial.SetVector ("_InvRenderTargetSize", new Vector4 (1.0f / (1.0f * to.width), 1.0f / (1.0f * to.height), 0.0f, 0.0f));
351 Graphics.Blit (from, to, dofMaterial, SMOOTH_DOWNSAMPLE_PASS);
352 }
353
354 void AddBokeh ( RenderTexture bokehInfo, RenderTexture tempTex, RenderTexture finalTarget) {
355 if (bokehMaterial) {
356 var meshes = Quads.GetMeshes (tempTex.width, tempTex.height); // quads: exchanging more triangles with less overdraw
357
358 RenderTexture.active = tempTex;
359 GL.Clear (false, true, new Color (0.0f, 0.0f, 0.0f, 0.0f));
360
361 GL.PushMatrix ();
362 GL.LoadIdentity ();
363
364 // point filter mode is important, otherwise we get bokeh shape & size artefacts
365 bokehInfo.filterMode = FilterMode.Point;
366
367 float arW = (bokehInfo.width * 1.0f) / (bokehInfo.height * 1.0f);
368 float sc = 2.0f / (1.0f * bokehInfo.width);
369 sc += bokehScale * maxBlurSpread * BOKEH_EXTRA_BLUR * oneOverBaseSize;
370
371 bokehMaterial.SetTexture ("_Source", bokehInfo);
372 bokehMaterial.SetTexture ("_MainTex", bokehTexture);
373 bokehMaterial.SetVector ("_ArScale",new Vector4 (sc, sc * arW, 0.5f, 0.5f * arW));
374 bokehMaterial.SetFloat ("_Intensity", bokehIntensity);
375 bokehMaterial.SetPass (0);
376
377 foreach(Mesh m in meshes)
378 if (m) Graphics.DrawMeshNow (m, Matrix4x4.identity);
379
380 GL.PopMatrix ();
381
382 Graphics.Blit (tempTex, finalTarget, dofMaterial, 8);
383
384 // important to set back as we sample from this later on
385 bokehInfo.filterMode = FilterMode.Bilinear;
386 }
387 }
388
389
390 void ReleaseTextures () {
391 if (foregroundTexture) RenderTexture.ReleaseTemporary (foregroundTexture);
392 if (finalDefocus) RenderTexture.ReleaseTemporary (finalDefocus);
393 if (mediumRezWorkTexture) RenderTexture.ReleaseTemporary (mediumRezWorkTexture);
394 if (lowRezWorkTexture) RenderTexture.ReleaseTemporary (lowRezWorkTexture);
395 if (bokehSource) RenderTexture.ReleaseTemporary (bokehSource);
396 if (bokehSource2) RenderTexture.ReleaseTemporary (bokehSource2);
397 }
398
399 void AllocateTextures ( bool blurForeground, RenderTexture source, int divider, int lowTexDivider) {
400 foregroundTexture = null;
401 if (blurForeground)
402 foregroundTexture = RenderTexture.GetTemporary (source.width, source.height, 0);
403 mediumRezWorkTexture = RenderTexture.GetTemporary (source.width / divider, source.height / divider, 0);
404 finalDefocus = RenderTexture.GetTemporary (source.width / divider, source.height / divider, 0);
405 lowRezWorkTexture = RenderTexture.GetTemporary (source.width / lowTexDivider, source.height / lowTexDivider, 0);
406 bokehSource = null;
407 bokehSource2 = null;
408 if (bokeh) {
409 bokehSource = RenderTexture.GetTemporary (source.width / (lowTexDivider * bokehDownsample), source.height / (lowTexDivider * bokehDownsample), 0, RenderTextureFormat.ARGBHalf);
410 bokehSource2 = RenderTexture.GetTemporary (source.width / (lowTexDivider * bokehDownsample), source.height / (lowTexDivider * bokehDownsample), 0, RenderTextureFormat.ARGBHalf);
411 bokehSource.filterMode = FilterMode.Bilinear;
412 bokehSource2.filterMode = FilterMode.Bilinear;
413 RenderTexture.active = bokehSource2;
414 GL.Clear (false, true, new Color(0.0f, 0.0f, 0.0f, 0.0f));
415 }
416
417 // to make sure: always use bilinear filter setting
418
419 source.filterMode = FilterMode.Bilinear;
420 finalDefocus.filterMode = FilterMode.Bilinear;
421 mediumRezWorkTexture.filterMode = FilterMode.Bilinear;
422 lowRezWorkTexture.filterMode = FilterMode.Bilinear;
423 if (foregroundTexture)
424 foregroundTexture.filterMode = FilterMode.Bilinear;
425 }
426 }
427 }