unityShader屏幕后期处理-Bloom效果

Bloom效果的实现原理:根据一个阈值提取出图像中的较亮区域,把他们存储在渲染纹理中,再利用高斯模糊,对这张渲染纹理进行模糊处理,模拟光线扩散的效果,最后将其与原图像混合。得到最终的效果
C#源码

`using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class Bloom : PostEffectsBase 
{
    
    public Shader bloomShader;
    private Material bloomMaterial=null;
    public Material material
    {
        get
        {
           bloomMaterial=CheckShaderAndCreateMaterial(bloomShader ,bloomMaterial);
           return bloomMaterial;
        }
    }
    //高斯模糊迭代次数
    [Range(0, 4)]
    public int iterations = 3;
    //模糊范围
    [Range(0.2f, 3.0f)]
    public float blurSpread = 0.6f;
    //缩放系数GaussianBlur
    [Range(1, 8)]
    public int downSample = 2;
    //控制提亮较亮区域时使用的阈值大小
    [Range(0.0f, 1.0f)]
    public float lumimanceThreshold = 0.6f;
    void OnRenderImage(RenderTexture source, RenderTexture destination)
    {

        if (material != null)
        {
            //提取图像中的较亮区域,存在buffer0中
            material.SetFloat("_LumimanceThreshold", lumimanceThreshold);
            //缩放图像进行降采样,减少需要处理的像素个数,提高性能
            int rtW = source.width / downSample;
            int rtH = source.height / downSample;
            RenderTexture buffer0 = RenderTexture.GetTemporary(rtW, rtH, 0);
            //把临时渲染纹理的滤波模式设置为双线性,调用第一个pass时需要处理的像素个数是之前的几分之一
            buffer0.filterMode = FilterMode.Bilinear;
            //使用shader中的第一个Pass提取图像中的较亮区域
            Graphics.Blit(source, buffer0,material ,0);
            for (int i = 0; i < iterations; i++)
            {
                material.SetFloat("_BlurSize", 1.0f + i * blurSpread);
                RenderTexture buffer1 = RenderTexture.GetTemporary(rtW, rtH, 0);
                //第一个Pass
                Graphics.Blit(buffer0, buffer1, material, 1);
                RenderTexture.ReleaseTemporary(buffer0);
                buffer0 = buffer1;
                buffer1 = RenderTexture.GetTemporary(rtW, rtH, 0);
                //第二个pass
                Graphics.Blit(buffer0, buffer1, material, 2);
                RenderTexture.ReleaseTemporary(buffer0);
                buffer0 = buffer1;
            }
            //把buffer0传递给_Bloom属性
            material.SetTexture("_Bloom",buffer0);
            Graphics.Blit(source,destination,material,3);
            //释放之前分配的缓存
            RenderTexture.ReleaseTemporary(buffer0);
        }
        else
        {
            Graphics.Blit(source, destination);
        }
    }

}

Shader源码

Shader "Hidden/Bloom"
{
    Properties
    {
		//输入的渲染纹理
        _MainTex ("Texture", 2D) = "white" {}
	//高斯模糊后的较亮区域
	    _Bloom("Bloom(RGB)",2D)="black"{}
		_LumimanceThreshold("lumimanceThreshold",float)=0.5
		_BlurSize("BlurSize",float)=1.0
    }
    SubShader
    {
        // No culling or depth
       
		CGINCLUDE
			   #include "UnityCG.cginc"
				sampler2D _MainTex;
				half4 _MainTex_TexelSize;
				sampler2D _Bloom;
				float _LumimanceThreshold;
				float _BlurSize;
				struct v2f
				{
					half2 uv : TEXCOORD0;
					float4 pos : SV_POSITION;
				};
				v2f vertExtractBright(appdata_img v)
				{
					v2f o;
					o.pos = UnityObjectToClipPos(v.vertex);
					o.uv = v.texcoord;
					return o;
				}
				fixed luminance(fixed4 color)
				{
					return 0.2125*color.r + 0.7154*color.g + 0.0721*color.b;
				}

				fixed4 fragExtractBright(v2f i) : SV_Target
				{
				 	fixed4 c = tex2D(_MainTex, i.uv);
				//把采样得到的亮度值减去阈值
				    fixed val = clamp(luminance(c)- _LumimanceThreshold,0.0,1.0);
				    return c*val;
				}
					//定义混合亮部图像和原图像使用的顶点和片元着色器
					struct v2fBloom
				{
					half4 uv : TEXCOORD0;
					float4 pos : SV_POSITION;
				};
				v2fBloom vertBloom(appdata_img v)
				{
					v2fBloom o;
					o.pos= UnityObjectToClipPos(v.vertex);
					o.uv.xy = v.texcoord;
					o.uv.zw = v.texcoord;
					#if UNITY_UV_STARTS_AT_TOP
						if (_MainTex_TexelSize.y < 0.0)
							o.uv.w = 1.0 - o.uv.w;
                     #endif
						return o;
				}
				fixed4 fragBloom(v2fBloom i) : SV_Target
				{
				 return tex2D(_MainTex,i.uv.xy) + tex2D(_Bloom,i.uv.zw);
				}
	    ENDCG
					ZTest Always	Cull Off ZWrite Off
        Pass
        {
            CGPROGRAM
          
         #pragma vertex vertExtractBright
         #pragma fragment  fragExtractBright
            ENDCG
        }
			UsePass	"Custom/GaussianBlur/GAUSSIAN_BLUR_VERTICAL"
			UsePass	"Custom/GaussianBlur/GAUSSIAN_BLUR_HORIZONTAL"
				Pass
			{
				CGPROGRAM

			 #pragma vertex vertBloom
			 #pragma fragment  fragBloom
				ENDCG
			}
    }
			Fallback Off
}
上一篇:OTSU算法(大津法—最大类间方差法)原理及实现


下一篇:区块链技术与应用【肖臻老师】笔记整理之------17-ETH-交易树和收据树