1 using System;
2 using UnityEngine;
3
4 namespace UnityStandardAssets.ImageEffects
5 {
6 [ExecuteInEditMode]
7 [RequireComponent (typeof(Camera))]
8 [AddComponentMenu ("Image Effects/Bloom and Glow/Bloom")]
9 public class Bloom : PostEffectsBase
10 {
11 public enum LensFlareStyle
12 {
13 Ghosting = 0,
14 Anamorphic = 1,
15 Combined = 2,
16 }
17
18 public enum TweakMode
19 {
20 Basic = 0,
21 Complex = 1,
22 }
23
24 public enum HDRBloomMode
25 {
26 Auto = 0,
27 On = 1,
28 Off = 2,
29 }
30
31 public enum BloomScreenBlendMode
32 {
33 Screen = 0,
34 Add = 1,
35 }
36
37 public enum BloomQuality
38 {
39 Cheap = 0,
40 High = 1,
41 }
42
43 public TweakMode tweakMode = 0;
44 public BloomScreenBlendMode screenBlendMode = BloomScreenBlendMode.Add;
45
46 public HDRBloomMode hdr = HDRBloomMode.Auto;
47 private bool doHdr = false;
48 public float sepBlurSpread = 2.5f;
49
50 public BloomQuality quality = BloomQuality.High;
51
52 public float bloomIntensity = 0.5f;
53 public float bloomThreshold = 0.5f;
54 public Color bloomThresholdColor = Color.white;
55 public int bloomBlurIterations = 2;
56
57 public int hollywoodFlareBlurIterations = 2;
58 public float flareRotation = 0.0f;
59 public LensFlareStyle lensflareMode = (LensFlareStyle) 1;
60 public float hollyStretchWidth = 2.5f;
61 public float lensflareIntensity = 0.0f;
62 public float lensflareThreshold = 0.3f;
63 public float lensFlareSaturation = 0.75f;
64 public Color flareColorA = new Color (0.4f, 0.4f, 0.8f, 0.75f);
65 public Color flareColorB = new Color (0.4f, 0.8f, 0.8f, 0.75f);
66 public Color flareColorC = new Color (0.8f, 0.4f, 0.8f, 0.75f);
67 public Color flareColorD = new Color (0.8f, 0.4f, 0.0f, 0.75f);
68 public Texture2D lensFlareVignetteMask;
69
70 public Shader lensFlareShader;
71 private Material lensFlareMaterial;
72
73 public Shader screenBlendShader;
74 private Material screenBlend;
75
76 public Shader blurAndFlaresShader;
77 private Material blurAndFlaresMaterial;
78
79 public Shader brightPassFilterShader;
80 private Material brightPassFilterMaterial;
81
82
83 public override bool CheckResources ()
84 {
85 CheckSupport (false);
86
87 screenBlend = CheckShaderAndCreateMaterial (screenBlendShader, screenBlend);
88 lensFlareMaterial = CheckShaderAndCreateMaterial(lensFlareShader,lensFlareMaterial);
89 blurAndFlaresMaterial = CheckShaderAndCreateMaterial (blurAndFlaresShader, blurAndFlaresMaterial);
90 brightPassFilterMaterial = CheckShaderAndCreateMaterial(brightPassFilterShader, brightPassFilterMaterial);
91
92 if (!isSupported)
93 ReportAutoDisable ();
94 return isSupported;
95 }
96
97 public void OnRenderImage (RenderTexture source, RenderTexture destination)
98 {
99 if (CheckResources()==false)
100 {
101 Graphics.Blit (source, destination);
102 return;
103 }
104
105 // screen blend is not supported when HDR is enabled (will cap values)
106
107 doHdr = false;
108 if (hdr == HDRBloomMode.Auto)
109 doHdr = source.format == RenderTextureFormat.ARGBHalf && GetComponent<Camera>().hdr;
110 else {
111 doHdr = hdr == HDRBloomMode.On;
112 }
113
114 doHdr = doHdr && supportHDRTextures;
115
116 BloomScreenBlendMode realBlendMode = screenBlendMode;
117 if (doHdr)
118 realBlendMode = BloomScreenBlendMode.Add;
119
120 var rtFormat= (doHdr) ? RenderTextureFormat.ARGBHalf : RenderTextureFormat.Default;
121 var rtW2= source.width/2;
122 var rtH2= source.height/2;
123 var rtW4= source.width/4;
124 var rtH4= source.height/4;
125
126 float widthOverHeight = (1.0f * source.width) / (1.0f * source.height);
127 float oneOverBaseSize = 1.0f / 512.0f;
128
129 // downsample
130 RenderTexture quarterRezColor = RenderTexture.GetTemporary (rtW4, rtH4, 0, rtFormat);
131 RenderTexture halfRezColorDown = RenderTexture.GetTemporary (rtW2, rtH2, 0, rtFormat);
132 if (quality > BloomQuality.Cheap) {
133 Graphics.Blit (source, halfRezColorDown, screenBlend, 2);
134 RenderTexture rtDown4 = RenderTexture.GetTemporary (rtW4, rtH4, 0, rtFormat);
135 Graphics.Blit (halfRezColorDown, rtDown4, screenBlend, 2);
136 Graphics.Blit (rtDown4, quarterRezColor, screenBlend, 6);
137 RenderTexture.ReleaseTemporary(rtDown4);
138 }
139 else {
140 Graphics.Blit (source, halfRezColorDown);
141 Graphics.Blit (halfRezColorDown, quarterRezColor, screenBlend, 6);
142 }
143 RenderTexture.ReleaseTemporary (halfRezColorDown);
144
145 // cut colors (thresholding)
146 RenderTexture secondQuarterRezColor = RenderTexture.GetTemporary (rtW4, rtH4, 0, rtFormat);
147 BrightFilter (bloomThreshold * bloomThresholdColor, quarterRezColor, secondQuarterRezColor);
148
149 // blurring
150
151 if (bloomBlurIterations < 1) bloomBlurIterations = 1;
152 else if (bloomBlurIterations > 10) bloomBlurIterations = 10;
153
154 for (int iter = 0; iter < bloomBlurIterations; iter++)
155 {
156 float spreadForPass = (1.0f + (iter * 0.25f)) * sepBlurSpread;
157
158 // vertical blur
159 RenderTexture blur4 = RenderTexture.GetTemporary (rtW4, rtH4, 0, rtFormat);
160 blurAndFlaresMaterial.SetVector ("_Offsets", new Vector4 (0.0f, spreadForPass * oneOverBaseSize, 0.0f, 0.0f));
161 Graphics.Blit (secondQuarterRezColor, blur4, blurAndFlaresMaterial, 4);
162 RenderTexture.ReleaseTemporary(secondQuarterRezColor);
163 secondQuarterRezColor = blur4;
164
165 // horizontal blur
166 blur4 = RenderTexture.GetTemporary (rtW4, rtH4, 0, rtFormat);
167 blurAndFlaresMaterial.SetVector ("_Offsets", new Vector4 ((spreadForPass / widthOverHeight) * oneOverBaseSize, 0.0f, 0.0f, 0.0f));
168 Graphics.Blit (secondQuarterRezColor, blur4, blurAndFlaresMaterial, 4);
169 RenderTexture.ReleaseTemporary (secondQuarterRezColor);
170 secondQuarterRezColor = blur4;
171
172 if (quality > BloomQuality.Cheap)
173 {
174 if (iter == 0)
175 {
176 Graphics.SetRenderTarget(quarterRezColor);
177 GL.Clear(false, true, Color.black); // Clear to avoid RT restore
178 Graphics.Blit (secondQuarterRezColor, quarterRezColor);
179 }
180 else
181 {
182 quarterRezColor.MarkRestoreExpected(); // using max blending, RT restore expected
183 Graphics.Blit (secondQuarterRezColor, quarterRezColor, screenBlend, 10);
184 }
185 }
186 }
187
188 if (quality > BloomQuality.Cheap)
189 {
190 Graphics.SetRenderTarget(secondQuarterRezColor);
191 GL.Clear(false, true, Color.black); // Clear to avoid RT restore
192 Graphics.Blit (quarterRezColor, secondQuarterRezColor, screenBlend, 6);
193 }
194
195 // lens flares: ghosting, anamorphic or both (ghosted anamorphic flares)
196
197 if (lensflareIntensity > Mathf.Epsilon)
198 {
199
200 RenderTexture rtFlares4 = RenderTexture.GetTemporary (rtW4, rtH4, 0, rtFormat);
201
202 if (lensflareMode == 0)
203 {
204 // ghosting only
205
206 BrightFilter (lensflareThreshold, secondQuarterRezColor, rtFlares4);
207
208 if (quality > BloomQuality.Cheap)
209 {
210 // smooth a little
211 blurAndFlaresMaterial.SetVector ("_Offsets", new Vector4 (0.0f, (1.5f) / (1.0f * quarterRezColor.height), 0.0f, 0.0f));
212 Graphics.SetRenderTarget(quarterRezColor);
213 GL.Clear(false, true, Color.black); // Clear to avoid RT restore
214 Graphics.Blit (rtFlares4, quarterRezColor, blurAndFlaresMaterial, 4);
215
216 blurAndFlaresMaterial.SetVector ("_Offsets", new Vector4 ((1.5f) / (1.0f * quarterRezColor.width), 0.0f, 0.0f, 0.0f));
217 Graphics.SetRenderTarget(rtFlares4);
218 GL.Clear(false, true, Color.black); // Clear to avoid RT restore
219 Graphics.Blit (quarterRezColor, rtFlares4, blurAndFlaresMaterial, 4);
220 }
221
222 // no ugly edges!
223 Vignette (0.975f, rtFlares4, rtFlares4);
224 BlendFlares (rtFlares4, secondQuarterRezColor);
225 }
226 else
227 {
228
229 //Vignette (0.975ff, rtFlares4, rtFlares4);
230 //DrawBorder(rtFlares4, screenBlend, 8);
231
232 float flareXRot = 1.0f * Mathf.Cos(flareRotation);
233 float flareyRot = 1.0f * Mathf.Sin(flareRotation);
234
235 float stretchWidth = (hollyStretchWidth * 1.0f / widthOverHeight) * oneOverBaseSize;
236
237 blurAndFlaresMaterial.SetVector ("_Offsets", new Vector4 (flareXRot, flareyRot, 0.0f, 0.0f));
238 blurAndFlaresMaterial.SetVector ("_Threshhold", new Vector4 (lensflareThreshold, 1.0f, 0.0f, 0.0f));
239 blurAndFlaresMaterial.SetVector ("_TintColor", new Vector4 (flareColorA.r, flareColorA.g, flareColorA.b, flareColorA.a) * flareColorA.a * lensflareIntensity);
240 blurAndFlaresMaterial.SetFloat ("_Saturation", lensFlareSaturation);
241
242 // "pre and cut"
243 quarterRezColor.DiscardContents();
244 Graphics.Blit (rtFlares4, quarterRezColor, blurAndFlaresMaterial, 2);
245 // "post"
246 rtFlares4.DiscardContents();
247 Graphics.Blit (quarterRezColor, rtFlares4, blurAndFlaresMaterial, 3);
248
249 blurAndFlaresMaterial.SetVector ("_Offsets", new Vector4 (flareXRot * stretchWidth, flareyRot * stretchWidth, 0.0f, 0.0f));
250 // stretch 1st
251 blurAndFlaresMaterial.SetFloat ("_StretchWidth", hollyStretchWidth);
252 quarterRezColor.DiscardContents();
253 Graphics.Blit (rtFlares4, quarterRezColor, blurAndFlaresMaterial, 1);
254 // stretch 2nd
255 blurAndFlaresMaterial.SetFloat ("_StretchWidth", hollyStretchWidth * 2.0f);
256 rtFlares4.DiscardContents();
257 Graphics.Blit (quarterRezColor, rtFlares4, blurAndFlaresMaterial, 1);
258 // stretch 3rd
259 blurAndFlaresMaterial.SetFloat ("_StretchWidth", hollyStretchWidth * 4.0f);
260 quarterRezColor.DiscardContents();
261 Graphics.Blit (rtFlares4, quarterRezColor, blurAndFlaresMaterial, 1);
262
263 // additional blur passes
264 for (int iter = 0; iter < hollywoodFlareBlurIterations; iter++)
265 {
266 stretchWidth = (hollyStretchWidth * 2.0f / widthOverHeight) * oneOverBaseSize;
267
268 blurAndFlaresMaterial.SetVector ("_Offsets", new Vector4 (stretchWidth * flareXRot, stretchWidth * flareyRot, 0.0f, 0.0f));
269 rtFlares4.DiscardContents();
270 Graphics.Blit (quarterRezColor, rtFlares4, blurAndFlaresMaterial, 4);
271
272 blurAndFlaresMaterial.SetVector ("_Offsets", new Vector4 (stretchWidth * flareXRot, stretchWidth * flareyRot, 0.0f, 0.0f));
273 quarterRezColor.DiscardContents();
274 Graphics.Blit (rtFlares4, quarterRezColor, blurAndFlaresMaterial, 4);
275 }
276
277 if (lensflareMode == (LensFlareStyle) 1)
278 // anamorphic lens flares
279 AddTo (1.0f, quarterRezColor, secondQuarterRezColor);
280 else
281 {
282 // "combined" lens flares
283
284 Vignette (1.0f, quarterRezColor, rtFlares4);
285 BlendFlares (rtFlares4, quarterRezColor);
286 AddTo (1.0f, quarterRezColor, secondQuarterRezColor);
287 }
288 }
289 RenderTexture.ReleaseTemporary (rtFlares4);
290 }
291
292 int blendPass = (int) realBlendMode;
293 //if (Mathf.Abs(chromaticBloom) < Mathf.Epsilon)
294 // blendPass += 4;
295
296 screenBlend.SetFloat ("_Intensity", bloomIntensity);
297 screenBlend.SetTexture ("_ColorBuffer", source);
298
299 if (quality > BloomQuality.Cheap)
300 {
301 RenderTexture halfRezColorUp = RenderTexture.GetTemporary (rtW2, rtH2, 0, rtFormat);
302 Graphics.Blit (secondQuarterRezColor, halfRezColorUp);
303 Graphics.Blit (halfRezColorUp, destination, screenBlend, blendPass);
304 RenderTexture.ReleaseTemporary (halfRezColorUp);
305 }
306 else
307 Graphics.Blit (secondQuarterRezColor, destination, screenBlend, blendPass);
308
309 RenderTexture.ReleaseTemporary (quarterRezColor);
310 RenderTexture.ReleaseTemporary (secondQuarterRezColor);
311 }
312
313 private void AddTo (float intensity_, RenderTexture from, RenderTexture to)
314 {
315 screenBlend.SetFloat ("_Intensity", intensity_);
316 to.MarkRestoreExpected(); // additive blending, RT restore expected
317 Graphics.Blit (from, to, screenBlend, 9);
318 }
319
320 private void BlendFlares (RenderTexture from, RenderTexture to)
321 {
322 lensFlareMaterial.SetVector ("colorA", new Vector4 (flareColorA.r, flareColorA.g, flareColorA.b, flareColorA.a) * lensflareIntensity);
323 lensFlareMaterial.SetVector ("colorB", new Vector4 (flareColorB.r, flareColorB.g, flareColorB.b, flareColorB.a) * lensflareIntensity);
324 lensFlareMaterial.SetVector ("colorC", new Vector4 (flareColorC.r, flareColorC.g, flareColorC.b, flareColorC.a) * lensflareIntensity);
325 lensFlareMaterial.SetVector ("colorD", new Vector4 (flareColorD.r, flareColorD.g, flareColorD.b, flareColorD.a) * lensflareIntensity);
326 to.MarkRestoreExpected(); // additive blending, RT restore expected
327 Graphics.Blit (from, to, lensFlareMaterial);
328 }
329
330 private void BrightFilter (float thresh, RenderTexture from, RenderTexture to)
331 {
332 brightPassFilterMaterial.SetVector ("_Threshhold", new Vector4 (thresh, thresh, thresh, thresh));
333 Graphics.Blit (from, to, brightPassFilterMaterial, 0);
334 }
335
336 private void BrightFilter (Color threshColor, RenderTexture from, RenderTexture to)
337 {
338 brightPassFilterMaterial.SetVector ("_Threshhold", threshColor);
339 Graphics.Blit (from, to, brightPassFilterMaterial, 1);
340 }
341
342 private void Vignette (float amount, RenderTexture from, RenderTexture to)
343 {
344 if (lensFlareVignetteMask)
345 {
346 screenBlend.SetTexture ("_ColorBuffer", lensFlareVignetteMask);
347 to.MarkRestoreExpected(); // using blending, RT restore expected
348 Graphics.Blit (from == to ? null : from, to, screenBlend, from == to ? 7 : 3);
349 }
350 else if (from != to)
351 {
352 Graphics.SetRenderTarget (to);
353 GL.Clear(false, true, Color.black); // clear destination to avoid RT restore
354 Graphics.Blit (from, to);
355 }
356 }
357 }
358 }