大家好,我是阿赵。
继续介绍屏幕后处理效果,这一期讲一下Bloom效果。
一、Bloom效果介绍
还是拿这个模型作为背景。
Bloom效果,就是一种全屏泛光的效果,让模型和特效有一种真的在发光的感觉。
根据参数不一样,可以做出不同的发光效果。
二、原理介绍
之前在介绍模糊效果的时候说过,Bloom效果也是基于模糊效果制作的。
Bloom的原理很简单,先用模糊处理,算出一张模糊后的图片,然后把这张图片的RGB和原始屏幕图片的RGB相加就可以了。由于是RGB颜色叠加,所以本身图片颜色越接近白色的地方,越容易爆掉,所以越接近白色的地方发光的感觉就越明显。如果想Bloom的效果更爆一点,就自己对模糊后的图片进一步做处理吧,最常见的手段就是先乘后加,或者Power后再相加也可以
实现很简单,在原来的模糊效果代码上面,我们应该再加多一个叠加的Shader就可以了。
half4 frag (v2f_img i) : SV_Target
{half4 col = tex2D(_MainTex, i.uv);half4 brightCol = tex2D(_brightTex, i.uv);col.rgb += brightCol.rgb;return col;
}
我这里在处理模糊之前,先加多了一个BrightRange的计算。这是为了控制一下发光的范围。BrightRange的算法很简单,先取原始图片的rgb三个通道颜色值最大的通道的值,然后用这个最大值减去一个我们指定的值。最后把原图的rgb颜色乘以这个值就可以了。
fixed4 frag (v2f_img i) : SV_Target
{fixed4 col = tex2D(_MainTex, i.uv);float br = max(max(col.r, col.g), col.b);br = max(0, (br - _BrightCut)) / max(br, 0.00001);col.rgb *= br;return col;
}
通过这个值,我们就可以更好的控制发光的范围
三、源码
1、C#部分
using System.Collections;
using System.Collections.Generic;
using UnityEngine;public class BloomCtrl : MonoBehaviour
{private Material blurMat;private Material brightMat;private Material bloomMat;public bool isBlur = false;[Range(0, 4)]public float blurSize = 0;[Range(-3, 3)]public float blurOffset = 1;[Range(1, 3)]public int blurType = 3;[Range(0, 1)]public float brightCut = 0.5f;void Start(){}void Update(){}private Material GetBlurMat(int bType){if (bType == 1){return new Material(Shader.Find("Hidden/AzhaoBoxBlur"));}else if (bType == 2){return new Material(Shader.Find("Hidden/AzhaoGaussianBlur"));}else if (bType == 3){return new Material(Shader.Find("Hidden/AzhaoKawaseBlur"));}else{return null;}}private void ReleaseRT(RenderTexture rt){if (rt != null){RenderTexture.ReleaseTemporary(rt);}}private bool CheckNeedCreateBlurMat(Material mat, int bType){if (mat == null){return true;}if (mat.shader == null){return true;}if (bType == 1){if (mat.shader.name != "Hidden/AzhaoBoxBlur"){return true;}else{return false;}}else if (bType == 2){if (mat.shader.name != "Hidden/AzhaoGaussianBlur"){return true;}else{return false;}}else if (bType == 3){if (mat.shader.name != "Hidden/AzhaoKawaseBlur"){return true;}else{return false;}}else{return false;}}private void BlurFun(RenderTexture source, RenderTexture destination, float blurTime, int bType, float offset){if (CheckNeedCreateBlurMat(blurMat, bType) == true){blurMat = GetBlurMat(bType);}if (blurMat == null || blurMat.shader == null || blurMat.shader.isSupported == false){return;}blurMat.SetFloat("_BlurOffset", offset);float width = source.width;float height = source.height;int w = Mathf.FloorToInt(width);int h = Mathf.FloorToInt(height);RenderTexture rt1 = RenderTexture.GetTemporary(w, h);RenderTexture rt2 = RenderTexture.GetTemporary(w, h);Graphics.Blit(source, rt1);for (int i = 0; i < blurTime; i++){ReleaseRT(rt2);width = width / 2;height = height / 2;w = Mathf.FloorToInt(width);h = Mathf.FloorToInt(height);rt2 = RenderTexture.GetTemporary(w, h);Graphics.Blit(rt1, rt2, blurMat, 0);width = width / 2;height = height / 2;w = Mathf.FloorToInt(width);h = Mathf.FloorToInt(height);ReleaseRT(rt1);rt1 = RenderTexture.GetTemporary(w, h);Graphics.Blit(rt2, rt1, blurMat, 1);}for (int i = 0; i < blurTime; i++){ReleaseRT(rt2);width = width * 2;height = height * 2;w = Mathf.FloorToInt(width);h = Mathf.FloorToInt(height);rt2 = RenderTexture.GetTemporary(w, h);Graphics.Blit(rt1, rt2, blurMat, 0);width = width * 2;height = height * 2;w = Mathf.FloorToInt(width);h = Mathf.FloorToInt(height);ReleaseRT(rt1);rt1 = RenderTexture.GetTemporary(w, h);Graphics.Blit(rt2, rt1, blurMat, 1);}Graphics.Blit(rt1, destination);ReleaseRT(rt1);rt1 = null;ReleaseRT(rt2);rt2 = null;return;}private bool BrightRangeFun(RenderTexture source, RenderTexture destination){if (brightMat == null){brightMat = new Material(Shader.Find("Hidden/BrightRange"));}if (brightMat == null || brightMat.shader == null || brightMat.shader.isSupported == false){return false;}brightMat.SetFloat("_BrightCut", brightCut);Graphics.Blit(source, destination, brightMat);return true;}private bool BloomAddFun(RenderTexture source, RenderTexture destination, RenderTexture brightTex){if (bloomMat == null){bloomMat = new Material(Shader.Find("Hidden/AzhaoBloom"));}if (bloomMat == null || bloomMat.shader == null || bloomMat.shader.isSupported == false){return false;}bloomMat.SetTexture("_brightTex", brightTex);Graphics.Blit(source, destination, bloomMat);return true;}private void OnRenderImage(RenderTexture source, RenderTexture destination){if (isBlur == true){RenderTexture finalRt = source;RenderTexture rt2 = RenderTexture.GetTemporary(source.width, source.height);RenderTexture rt3 = RenderTexture.GetTemporary(source.width, source.height);BrightRangeFun(source, rt2);if (blurSize > 0){BlurFun(rt2, rt3, blurSize, blurType, blurOffset);BloomAddFun(source, finalRt, rt3);}Graphics.Blit(finalRt, destination);ReleaseRT(finalRt);ReleaseRT(rt2);ReleaseRT(rt3);}else{Graphics.Blit(source, destination);}}
}
2、Shader
模糊shader就不重复了,参考之前的文章
这里提供一下Bloom和BrightRange的shader
1.Bloom
Shader "Hidden/AzhaoBloom"
{Properties{_MainTex ("Texture", 2D) = "white" {}_brightTex("BrightTex",2D) = "black"}SubShader{// No culling or depthCull Off ZWrite Off ZTest AlwaysPass{CGPROGRAM#pragma vertex vert_img#pragma fragment frag#include "UnityCG.cginc"sampler2D _MainTex;sampler2D _brightTex;half4 frag (v2f_img i) : SV_Target{half4 col = tex2D(_MainTex, i.uv);half4 brightCol = tex2D(_brightTex, i.uv);col.rgb += brightCol.rgb;return col;}ENDCG}}
}
2.BrightRange
Shader "Hidden/BrightRange"
{Properties{_MainTex ("Texture", 2D) = "white" {}_BrightCut("LightVal",Range(0,1)) = 0.5}SubShader{// No culling or depthCull Off ZWrite Off ZTest AlwaysPass{CGPROGRAM#pragma vertex vert_img#pragma fragment frag#include "UnityCG.cginc"sampler2D _MainTex;float _BrightCut;fixed4 frag (v2f_img i) : SV_Target{fixed4 col = tex2D(_MainTex, i.uv);float br = max(max(col.r, col.g), col.b);br = max(0, (br - _BrightCut)) / max(br, 0.00001);col.rgb *= br;return col;}ENDCG}}
}