Unity Shader 从未入门到已放弃(二十一)–高级 Bloom效果

  • Post author:
  • Post category:其他


Bloom.cs:

private void OnRenderImage(RenderTexture source, RenderTexture destination)
    {
        if (material != null)
        {
            material.SetFloat("_LuminanceThreshold", luminanceThreshold);

            int rtW = source.width / downSample;
            int rtH = source.height / downSample;
            //分配一块小于屏幕大小的缓冲区 这样需要处理的像素就为几分之一 
            RenderTexture buffer0 = RenderTexture.GetTemporary(rtW, rtH, 0);
            buffer0.filterMode = FilterMode.Bilinear;

            Graphics.Blit(source, buffer0, material, 0);//提取较亮区域存储于buffer0中

            for (int i = 0; i < iterations; i++)
            {
                material.SetFloat("_BlurSize", 1.0f + i * blurSpread);

                RenderTexture buffer1 = RenderTexture.GetTemporary(rtW, rtH, 0);

                Graphics.Blit(buffer0, buffer1, material, 1);//对应subshader的第二个Pass

                RenderTexture.ReleaseTemporary(buffer0);

                buffer0 = buffer1;
                buffer1 = RenderTexture.GetTemporary(rtW, rtH, 0);

                // Render the horizontal pass
                Graphics.Blit(buffer0, buffer1, material, 2);//对应subshader的第三个Pass

                RenderTexture.ReleaseTemporary(buffer0);
                buffer0 = buffer1;
            }

            material.SetTexture("_Bloom", buffer0);
            Graphics.Blit(source, destination, material, 3);//使用subshader的第四个Pass进行最后的混合,结果存储在目标渲染纹理destination中

            RenderTexture.ReleaseTemporary(buffer0);

        }
        else
        {
            Graphics.Blit(source, destination);
        }
    }

上面的代码和高斯模糊使用的代码基本相同,但进行了一些修改。Bloom效果需要三个步骤:首先,提取图像中较亮的区域,通过Graphics.Blit(source, buffer0, material, 0)来使用shader中的第一个Pass来提取图像中较亮的区域,并存储在buffer0中。然后进行高斯模糊的迭代处理。模糊后较亮的区域会在buffer0中,此时再把buffer0传递给材质中的_Bloom纹理属性,并使用shader中的第四个Pass进行最后的混合。

shader:

SubShader {
		CGINCLUDE

		#include "UnityCG.cginc"

		sampler2D _MainTex;
		half4 _MainTex_TexelSize;//纹理像素的尺寸  x contains 1.0/width    y contains 1.0 / height     z contains width      w contains height
		sampler2D _Bloom;
		float _LuminanceThreshold;
		float _BlurSize;

		struct v2f {
			float4 pos:SV_POSITION;
			half2 uv:TEXCOORD0;
		};

		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) - _LuminanceThreshold, 0.0, 1.0); //结果截取在0~1之间

			return c * val;
		}

		struct v2fBloom {
			float4 pos:SV_POSITION;
			half4 uv:TEXCOORD0;
		};

		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
		}

		//Pass需使用大写
		UsePass "myShader/Gaussian Blur/GAUSSIAN_BLUR_VERTICAL"

		UsePass "myShader/Gaussian Blur/GAUSSIAN_BLUR_HORIZONTAL"

		Pass {
			CGPROGRAM

			#pragma vertex vertBloom
			#pragma fragment fragBloom

			ENDCG
		}
	}

效果图:



版权声明:本文为qq_27467821原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。