summaryrefslogtreecommitdiff
path: root/Client/Assets/Scripts/PostEffect/Bloom.cs
diff options
context:
space:
mode:
Diffstat (limited to 'Client/Assets/Scripts/PostEffect/Bloom.cs')
-rw-r--r--Client/Assets/Scripts/PostEffect/Bloom.cs335
1 files changed, 335 insertions, 0 deletions
diff --git a/Client/Assets/Scripts/PostEffect/Bloom.cs b/Client/Assets/Scripts/PostEffect/Bloom.cs
new file mode 100644
index 00000000..d7c17c40
--- /dev/null
+++ b/Client/Assets/Scripts/PostEffect/Bloom.cs
@@ -0,0 +1,335 @@
+using UnityEngine;
+using System.Collections;
+
+[ExecuteInEditMode]
+[RequireComponent(typeof(Camera))]
+public class Bloom : PostEffectsBase
+{
+ public enum LensFlareStyle {
+ Ghosting = 0,
+ Anamorphic = 1,
+ Combined = 2,
+ }
+
+ public enum TweakMode {
+ Basic = 0,
+ Complex = 1,
+ }
+
+ public enum HDRBloomMode {
+ Auto = 0,
+ On = 1,
+ Off = 2,
+ }
+
+ public enum BloomScreenBlendMode {
+ Screen = 0,
+ Add = 1,
+ }
+
+ public enum BloomQuality {
+ Cheap = 0,
+ High = 1,
+ }
+
+ public TweakMode tweakMode = TweakMode.Basic;
+ public BloomScreenBlendMode screenBlendMode = BloomScreenBlendMode.Add;
+
+ public HDRBloomMode hdr = HDRBloomMode.Auto;
+ private bool doHdr = false;
+ public float sepBlurSpread = 2.5f;
+
+ public BloomQuality quality = BloomQuality.High;
+
+ public float bloomIntensity = 0.5f;
+ public float bloomThreshhold = 0.5f;
+ public Color bloomThreshholdColor = Color.white;
+ public int bloomBlurIterations = 2;
+
+ public int hollywoodFlareBlurIterations = 2;
+ public float flareRotation = 0.0f;
+ public LensFlareStyle lensflareMode = LensFlareStyle.Anamorphic;
+ public float hollyStretchWidth = 2.5f;
+ public float lensflareIntensity = 0.0f;
+ public float lensflareThreshhold = 0.3f;
+ public float lensFlareSaturation = 0.75f;
+ public Color flareColorA = new Color (0.4f, 0.4f, 0.8f, 0.75f);
+ public Color flareColorB = new Color(0.4f, 0.8f, 0.8f, 0.75f);
+ public Color flareColorC = new Color(0.8f, 0.4f, 0.8f, 0.75f);
+ public Color flareColorD = new Color(0.8f, 0.4f, 0.0f, 0.75f);
+ public float blurWidth = 1.0f;
+ public Texture2D lensFlareVignetteMask;
+
+ public Shader lensFlareShader;
+ private Material lensFlareMaterial;
+
+ public Shader screenBlendShader;
+ private Material screenBlend;
+
+ public Shader blurAndFlaresShader;
+ private Material blurAndFlaresMaterial;
+
+ public Shader brightPassFilterShader;
+ private Material brightPassFilterMaterial;
+
+ new bool CheckResources ()
+ {
+ CheckSupport (false);
+
+ screenBlend = CheckShaderAndCreateMaterial (screenBlendShader, screenBlend);
+ lensFlareMaterial = CheckShaderAndCreateMaterial(lensFlareShader,lensFlareMaterial);
+ blurAndFlaresMaterial = CheckShaderAndCreateMaterial (blurAndFlaresShader, blurAndFlaresMaterial);
+ brightPassFilterMaterial = CheckShaderAndCreateMaterial(brightPassFilterShader, brightPassFilterMaterial);
+
+ if(!isSupported)
+ ReportAutoDisable ();
+ return isSupported;
+ }
+
+ void OnRenderImage (RenderTexture source,RenderTexture destination) {
+ if(CheckResources()==false) {
+ Graphics.Blit (source, destination);
+ return;
+ }
+
+ // screen blend is not supported when HDR is enabled (will cap values)
+
+ doHdr = false;
+ if(hdr == HDRBloomMode.Auto)
+ doHdr = source.format == RenderTextureFormat.ARGBHalf && GetComponent<Camera>().hdr;
+ else {
+ doHdr = hdr == HDRBloomMode.On;
+ }
+
+ doHdr = doHdr && supportHDRTextures;
+
+ BloomScreenBlendMode realBlendMode = screenBlendMode;
+ if(doHdr)
+ realBlendMode = BloomScreenBlendMode.Add;
+
+ var rtFormat = (doHdr) ? RenderTextureFormat.ARGBHalf : RenderTextureFormat.Default;
+ var rtW2 = source.width/2;
+ var rtH2 = source.height/2;
+ var rtW4 = source.width/4;
+ var rtH4 = source.height/4;
+
+ float widthOverHeight = (1.0f * source.width) / (1.0f * source.height);
+ float oneOverBaseSize = 1.0f / 512.0f;
+
+ // downsample
+ RenderTexture quarterRezColor = RenderTexture.GetTemporary (rtW4, rtH4, 0, rtFormat);
+ RenderTexture halfRezColorDown = RenderTexture.GetTemporary (rtW2, rtH2, 0, rtFormat);
+ if(quality > BloomQuality.Cheap) {
+ Graphics.Blit (source, halfRezColorDown, screenBlend, 2);
+ RenderTexture rtDown4 = RenderTexture.GetTemporary (rtW4, rtH4, 0, rtFormat);
+ Graphics.Blit (halfRezColorDown, rtDown4, screenBlend, 2);
+ Graphics.Blit (rtDown4, quarterRezColor, screenBlend, 6);
+ RenderTexture.ReleaseTemporary(rtDown4);
+ }
+ else {
+ Graphics.Blit (source, halfRezColorDown);
+ Graphics.Blit (halfRezColorDown, quarterRezColor, screenBlend, 6);
+ }
+ RenderTexture.ReleaseTemporary (halfRezColorDown);
+
+ // cut colors (threshholding)
+ RenderTexture secondQuarterRezColor = RenderTexture.GetTemporary (rtW4, rtH4, 0, rtFormat);
+ BrightFilter (bloomThreshhold * bloomThreshholdColor, quarterRezColor, secondQuarterRezColor);
+
+ // blurring
+
+ if (bloomBlurIterations < 1) bloomBlurIterations = 1;
+ else if (bloomBlurIterations > 10) bloomBlurIterations = 10;
+
+ for (int iter = 0; iter < bloomBlurIterations; iter++ ) {
+ float spreadForPass = (1.0f + (iter * 0.25f)) * sepBlurSpread;
+
+ // vertical blur
+ RenderTexture blur4 = RenderTexture.GetTemporary (rtW4, rtH4, 0, rtFormat);
+ blurAndFlaresMaterial.SetVector ("_Offsets", new Vector4 (0.0f, spreadForPass * oneOverBaseSize, 0.0f, 0.0f));
+ Graphics.Blit (secondQuarterRezColor, blur4, blurAndFlaresMaterial, 4);
+ RenderTexture.ReleaseTemporary(secondQuarterRezColor);
+ secondQuarterRezColor = blur4;
+
+ // horizontal blur
+ blur4 = RenderTexture.GetTemporary (rtW4, rtH4, 0, rtFormat);
+ blurAndFlaresMaterial.SetVector("_Offsets", new Vector4((spreadForPass / widthOverHeight) * oneOverBaseSize, 0.0f, 0.0f, 0.0f));
+ Graphics.Blit (secondQuarterRezColor, blur4, blurAndFlaresMaterial, 4);
+ RenderTexture.ReleaseTemporary (secondQuarterRezColor);
+ secondQuarterRezColor = blur4;
+
+ if (quality > BloomQuality.Cheap) {
+ if (iter == 0)
+ {
+ Graphics.SetRenderTarget(quarterRezColor);
+ GL.Clear(false, true, Color.black); // Clear to avoid RT restore
+ Graphics.Blit (secondQuarterRezColor, quarterRezColor);
+ }
+ else
+ {
+ quarterRezColor.MarkRestoreExpected(); // using max blending, RT restore expected
+ Graphics.Blit (secondQuarterRezColor, quarterRezColor, screenBlend, 10);
+ }
+ }
+ }
+
+ if(quality > BloomQuality.Cheap)
+ {
+ Graphics.SetRenderTarget(secondQuarterRezColor);
+ GL.Clear(false, true, Color.black); // Clear to avoid RT restore
+ Graphics.Blit (quarterRezColor, secondQuarterRezColor, screenBlend, 6);
+ }
+
+ // lens flares: ghosting, anamorphic or both (ghosted anamorphic flares)
+
+ if (lensflareIntensity > Mathf.Epsilon) {
+
+ RenderTexture rtFlares4 = RenderTexture.GetTemporary (rtW4, rtH4, 0, rtFormat);
+
+ if (lensflareMode == 0) {
+ // ghosting only
+
+ BrightFilter (lensflareThreshhold, secondQuarterRezColor, rtFlares4);
+
+ if(quality > BloomQuality.Cheap) {
+ // smooth a little
+ blurAndFlaresMaterial.SetVector("_Offsets", new Vector4(0.0f, (1.5f) / (1.0f * quarterRezColor.height), 0.0f, 0.0f));
+ Graphics.SetRenderTarget(quarterRezColor);
+ GL.Clear(false, true, Color.black); // Clear to avoid RT restore
+ Graphics.Blit (rtFlares4, quarterRezColor, blurAndFlaresMaterial, 4);
+
+ blurAndFlaresMaterial.SetVector("_Offsets", new Vector4((1.5f) / (1.0f * quarterRezColor.width), 0.0f, 0.0f, 0.0f));
+ Graphics.SetRenderTarget(rtFlares4);
+ GL.Clear(false, true, Color.black); // Clear to avoid RT restore
+ Graphics.Blit (quarterRezColor, rtFlares4, blurAndFlaresMaterial, 4);
+ }
+
+ // no ugly edges!
+ Vignette (0.975f, rtFlares4, rtFlares4);
+ BlendFlares (rtFlares4, secondQuarterRezColor);
+ }
+ else {
+
+ //Vignette (0.975f, rtFlares4, rtFlares4);
+ //DrawBorder(rtFlares4, screenBlend, 8);
+
+ float flareXRot = 1.0f * Mathf.Cos(flareRotation);
+ float flareyRot = 1.0f * Mathf.Sin(flareRotation);
+
+ float stretchWidth = (hollyStretchWidth * 1.0f / widthOverHeight) * oneOverBaseSize;
+ //float stretchWidthY = hollyStretchWidth * oneOverBaseSize;
+
+ blurAndFlaresMaterial.SetVector("_Offsets", new Vector4(flareXRot, flareyRot, 0.0f, 0.0f));
+ blurAndFlaresMaterial.SetVector("_Threshhold", new Vector4(lensflareThreshhold, 1.0f, 0.0f, 0.0f));
+ blurAndFlaresMaterial.SetVector("_TintColor", new Vector4(flareColorA.r, flareColorA.g, flareColorA.b, flareColorA.a) * flareColorA.a * lensflareIntensity);
+ blurAndFlaresMaterial.SetFloat ("_Saturation", lensFlareSaturation);
+
+ // "pre and cut"
+ quarterRezColor.DiscardContents();
+ Graphics.Blit (rtFlares4, quarterRezColor, blurAndFlaresMaterial, 2);
+ // "post"
+ rtFlares4.DiscardContents();
+ Graphics.Blit (quarterRezColor, rtFlares4, blurAndFlaresMaterial, 3);
+
+ blurAndFlaresMaterial.SetVector("_Offsets", new Vector4(flareXRot * stretchWidth, flareyRot * stretchWidth, 0.0f, 0.0f));
+ // stretch 1st
+ blurAndFlaresMaterial.SetFloat ("_StretchWidth", hollyStretchWidth);
+ quarterRezColor.DiscardContents();
+ Graphics.Blit (rtFlares4, quarterRezColor, blurAndFlaresMaterial, 1);
+ // stretch 2nd
+ blurAndFlaresMaterial.SetFloat ("_StretchWidth", hollyStretchWidth * 2.0f);
+ rtFlares4.DiscardContents();
+ Graphics.Blit (quarterRezColor, rtFlares4, blurAndFlaresMaterial, 1);
+ // stretch 3rd
+ blurAndFlaresMaterial.SetFloat ("_StretchWidth", hollyStretchWidth * 4.0f);
+ quarterRezColor.DiscardContents();
+ Graphics.Blit (rtFlares4, quarterRezColor, blurAndFlaresMaterial, 1);
+
+ // additional blur passes
+ for (int iter = 0; iter < hollywoodFlareBlurIterations; iter++)
+ {
+ stretchWidth = (hollyStretchWidth * 2.0f / widthOverHeight) * oneOverBaseSize;
+
+ blurAndFlaresMaterial.SetVector("_Offsets", new Vector4(stretchWidth * flareXRot, stretchWidth * flareyRot, 0.0f, 0.0f));
+ rtFlares4.DiscardContents();
+ Graphics.Blit (quarterRezColor, rtFlares4, blurAndFlaresMaterial, 4);
+
+ blurAndFlaresMaterial.SetVector("_Offsets", new Vector4(stretchWidth * flareXRot, stretchWidth * flareyRot, 0.0f, 0.0f));
+ quarterRezColor.DiscardContents();
+ Graphics.Blit (rtFlares4, quarterRezColor, blurAndFlaresMaterial, 4);
+ }
+
+ if (lensflareMode == LensFlareStyle.Anamorphic)
+ // anamorphic lens flares
+ AddTo (1.0f, quarterRezColor, secondQuarterRezColor);
+ else {
+
+ // "combined" lens flares
+
+ Vignette (1.0f, quarterRezColor, rtFlares4);
+ BlendFlares (rtFlares4, quarterRezColor);
+ AddTo (1.0f, quarterRezColor, secondQuarterRezColor);
+ }
+ }
+ RenderTexture.ReleaseTemporary (rtFlares4);
+ }
+
+ int blendPass = (int)realBlendMode;
+ //if(Mathf.Abs(chromaticBloom) < Mathf.Epsilon)
+ // blendPass += 4;
+
+ screenBlend.SetFloat ("_Intensity", bloomIntensity);
+ screenBlend.SetTexture ("_ColorBuffer", source);
+
+ if(quality > BloomQuality.Cheap) {
+ RenderTexture halfRezColorUp = RenderTexture.GetTemporary (rtW2, rtH2, 0, rtFormat);
+ Graphics.Blit (secondQuarterRezColor, halfRezColorUp);
+ Graphics.Blit (halfRezColorUp, destination, screenBlend, blendPass);
+ RenderTexture.ReleaseTemporary (halfRezColorUp);
+ }
+ else
+ Graphics.Blit (secondQuarterRezColor, destination, screenBlend, blendPass);
+
+ RenderTexture.ReleaseTemporary (quarterRezColor);
+ RenderTexture.ReleaseTemporary (secondQuarterRezColor);
+ }
+
+ private void AddTo (float intensity_, RenderTexture from, RenderTexture to) {
+ screenBlend.SetFloat ("_Intensity", intensity_);
+ to.MarkRestoreExpected(); // additive blending, RT restore expected
+ Graphics.Blit (from, to, screenBlend, 9);
+ }
+
+ private void BlendFlares (RenderTexture from,RenderTexture to) {
+ lensFlareMaterial.SetVector("colorA", new Vector4(flareColorA.r, flareColorA.g, flareColorA.b, flareColorA.a) * lensflareIntensity);
+ lensFlareMaterial.SetVector("colorB", new Vector4(flareColorB.r, flareColorB.g, flareColorB.b, flareColorB.a) * lensflareIntensity);
+ lensFlareMaterial.SetVector("colorC", new Vector4(flareColorC.r, flareColorC.g, flareColorC.b, flareColorC.a) * lensflareIntensity);
+ lensFlareMaterial.SetVector ("colorD", new Vector4 (flareColorD.r, flareColorD.g, flareColorD.b, flareColorD.a) * lensflareIntensity);
+ to.MarkRestoreExpected(); // additive blending, RT restore expected
+ Graphics.Blit (from, to, lensFlareMaterial);
+ }
+
+ private void BrightFilter (float thresh,RenderTexture from,RenderTexture to) {
+ brightPassFilterMaterial.SetVector("_Threshhold", new Vector4(thresh, thresh, thresh, thresh));
+ Graphics.Blit (from, to, brightPassFilterMaterial, 0);
+ }
+
+ private void BrightFilter (Color threshColor,RenderTexture from,RenderTexture to) {
+ brightPassFilterMaterial.SetVector ("_Threshhold", threshColor);
+ Graphics.Blit (from, to, brightPassFilterMaterial, 1);
+ }
+
+ private void Vignette (float amount,RenderTexture from,RenderTexture to) {
+ if(lensFlareVignetteMask) {
+ screenBlend.SetTexture ("_ColorBuffer", lensFlareVignetteMask);
+ to.MarkRestoreExpected(); // using blending, RT restore expected
+ Graphics.Blit (from == to ? null : from, to, screenBlend, from == to ? 7 : 3);
+ }
+ else if (from != to)
+ {
+ Graphics.SetRenderTarget (to);
+ GL.Clear(false, true, Color.black); // clear destination to avoid RT restore
+ Graphics.Blit (from, to);
+ }
+ }
+}