Bloom 效果

1、Bloom 效果是什么

Bloom效果(中文也可以叫做高光溢出效果),是一种使画面中亮度较高的区域产生一种光晕或发光效果的图像处理技术,Bloom效果的主要目的是模拟现实世界中强光源在相机镜头或人眼中造成的散射和反射现象,使得画面中较亮的区域"扩散"到周围的区域,造成一种朦胧的效果

2、基本原理

三步骤概括Unity Shader中实现Bloom效果的基本原理:

  1. 提取:提取原图像中的亮度区域存储到一张新纹理中
  2. 模糊:将提取出来的纹理进行模糊处理(一般采用高斯模糊)
  3. 合成:将模糊处理后的亮度纹理和源纹理进行颜色叠加

可以在屏幕后处理时,单独调用某个Pass对渲染纹理进行处理,只需要利用Unity中的三个函数即可

  • RenderTexture.GetTemporary(纹理宽,纹理高,0)
  • Graphics.Blit(源纹理,目标纹理,材质,passID)
  • RenderTexture.ReleaseTemporary(渲染纹理对象)

**处理Bloom效果时将使用4个Pass,**他们分别是:

  1. 用于 提取亮度区域 存储到新纹理中的 1 个 Pass
  2. 用于 模糊处理提取出来的纹理 的 高斯模糊的 2 个 Pass(可以复用高斯模糊Shader中写好的Pass)
  3. 用于 与原图像进行合成 的 1 个 Pass

如何提取

需要在Shader中声明一个亮度阈值变量,亮度低于该值的区域不会被提取,主要用于"提取"Pass的片元着色器函数当中,

用当前像素的灰度值 L = 0.2125*R + 0.7154*G + 0.0721*B 与 亮度阈值变量 进行计算

灰度值 -- 亮度阈值变量:是为了仅保留超过阈值的部分,可以提取出图像中亮度较高的地方。
Clamp函数:如果结果小于0则为0,大于1则为1。得到的val表示像素的亮度贡献
颜色*亮度贡献:基于亮度阈值调节颜色的亮度,若val为0则为黑色,越接近1越接近原始颜色
这样做的目的是保留高亮区域的颜色信息,同时衰减低亮区域的颜色。

如果"提取"Pass是Shader中的第一个Pass,可以利用RenderTexture.GetTemporary 和 Graphics.Blit 函数将源纹理提取亮度信息后存储到缓存区中

如何模糊

利用 UsePass 指令使用高斯模糊中的 Pass,需要在Bloom效果的Shader中声明一个纹理属性 _Bloom用于存储模糊处理完毕后的纹理,在C#代码中完成高斯模糊处理后,只需要将缓存区内容,写入材质球中的纹理属性即可

如何合成

在"合成"的Pass 中只需要用主纹理 _MainTex (其中使用的纹理是屏幕原图像)和纹理属性 _Bloom (其中使用的纹理是模糊处理后的亮度纹理信息)进行颜色叠加即可,我们对两张纹理进行采样,将获取到的颜色信息进行加法运算

因为颜色相加带来的效果就是增加亮度,使得原本高亮的部分变得更加显眼从而达到Bloom效果(高光溢出效果)

cs 复制代码
Shader "ShaderProj/11//Bloom"
{
    Properties
    {
        _MainTex ("Texture", 2D) = "white" {}
        _Bloom ("Bloom", 2D) = "white" {}
        _LuminanmceThreshold ("LuminanmceThreshold", Float) = 0.5
        //_BlurSize("BlurSize", Float) = 1
    }
    SubShader
    {
        CGINCLUDE
        #include "UnityCG.cginc"

        sampler2D _MainTex;
        half4 _MainTex_TexelSize;
        sampler2D _Bloom;
        float _LuminanmceThreshold;
        //float _BlurSize;

        struct v2f
        {
            float2 uv : TEXCOORD0;
            float4 vertex : SV_POSITION;
        };

        fixed4 luminance(float4 color)
        {
            return 0.2125 * color.r + 0.7154 * color.g + 0.0721 * color.b;
        }
        ENDCG

        ZTest Always
        Cull Off
        ZWrite Off

        Pass
        {
            CGPROGRAM
            #pragma vertex vert
            #pragma fragment frag

            struct appdata
            {
                float4 vertex : POSITION;
                float2 uv : TEXCOORD0;
            };

            v2f vert (appdata_base v)
            {
                v2f o;

                o.vertex = UnityObjectToClipPos(v.vertex);
                o.uv = v.texcoord;
                return o;
            }

            fixed4 frag (v2f i) : SV_Target
            {
               fixed4 color = tex2D(_MainTex, i.uv);
               fixed4 value = clamp(luminance(color) - _LuminanmceThreshold, 0, 1);
               return color * value;
            }
            ENDCG
        }

        UsePass "ShaderProj/10/GaussianBlur/GAUSSIAN_BLUR_HORIZONTAL"
        UsePass "ShaderProj/10/GaussianBlur/GAUSSIAN_BLUR_VERTICAL"

        Pass
        {
            CGPROGRAM
            #pragma vertex vertBloom
            #pragma fragment fragBloom

            struct v2fBloom
            {
                float4 pos: SV_POSITION;
                //xy主要用于对主纹理进行采样
                //zw主要用于对亮度模糊后的纹理采样
                half4 uv: TEXCOORD0;
            };

            v2fBloom vertBloom(appdata_base v)
            {
                v2fBloom o;

                o.pos = UnityObjectToClipPos(v.vertex);
                o.uv.xy = v.texcoord;
                o.uv.zw = v.texcoord;

                // 注意:亮度纹理的UV坐标需要判断是否进行Y轴翻转
                // 因为使用RENDERTEXTURE写入到SHADER的纹理变量时
                // UNITY可能会对其进行Y轴翻转
                // 用宏去判断uv坐标是否被翻转
                #if UNITY_UV_STARTS_AT_TOP 
                //如果纹素的y小于0 为负数 表示需要对Y轴进行调整
                if (_MainTex_TexelSize.y < 0) 
                { 
                    o.uv.w = 1 - o.uv.w;
                }
                #endif

                return o;
            }

            fixed4 fragBloom(v2fBloom i):SV_TARGET
            {
                return tex2D(_MainTex, i.uv.xy) + tex2D(_Bloom, i.uv.zw);
            }
            ENDCG
        }
    }
    Fallback Off
}
cs 复制代码
using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class Bloom : PostEffectBase
{
    [Range(0, 4)]
    public float luminanceThreshod = .5f;
    [Range(1, 8)]
    public int downSample = 1;
    [Range(1, 16)]
    public int iterations = 1;
    [Range(0, 3)]
    public float blurSpread = .6f;

    protected override void OnRenderImage(RenderTexture source, RenderTexture destination) {
        if (material != null) {
            material.SetFloat("_LuminanmceThreshold", luminanceThreshod);

            int rtW = source.width / downSample;
            int rtH = source.height / downSample;

            RenderTexture buffer = RenderTexture.GetTemporary(rtW, rtH, 0);
            //采用双线性过滤模式来缩放 可以让缩放效果更平滑
            buffer.filterMode = FilterMode.Bilinear;
            // 提取
            Graphics.Blit(source, buffer, material, 0);

            // 模糊
            for (int i = 0; i < iterations; i++) {
                material.SetFloat("_BlurSpread", 1 + i * blurSpread);

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

                Graphics.Blit(buffer, buffer1, material, 1); //Color1
                RenderTexture.ReleaseTemporary(buffer);

                buffer = buffer1;
                buffer1 = RenderTexture.GetTemporary(rtW, rtH, 0);
                Graphics.Blit(buffer, buffer1, material, 2);
                RenderTexture.ReleaseTemporary(buffer);
                buffer = buffer1;
            }
            material.SetTexture("_Bloom", buffer);

            // 合成
            Graphics.Blit(source, destination, material, 3);

            RenderTexture.ReleaseTemporary(buffer);
        } else {
            Graphics.Blit(source, destination);
        }
    }
}
相关推荐
qq 180809515 小时前
从零构建一个多目标多传感器融合跟踪器
unity
平行云6 小时前
实时云渲染支持在网页上运行UE5开发的3A大作Lyra项目
unity·云原生·ue5·webgl·虚拟现实·实时云渲染·像素流送
鹏飞于天6 小时前
Shader compiler initialization error: Failed to read D3DCompiler DLL file
unity
wonder135798 小时前
UGUI重建流程和优化
unity·游戏开发·ugui
那个村的李富贵12 小时前
Unity打包Webgl后 本地运行测试
unity·webgl
nnsix12 小时前
Unity OpenXR开发HTC Vive Cosmos
unity·游戏引擎
nnsix13 小时前
Unity OpenXR,扳机键交互UI时,必须按下扳机才触发
unity·游戏引擎
nnsix13 小时前
Unity XR 编辑器VR设备模拟功能
unity·编辑器·xr
老朱佩琪!13 小时前
Unity访问者模式
unity·游戏引擎·访问者模式
不定时总结的那啥14 小时前
Unity实现点击Console消息自动选中预制体的方法
unity·游戏引擎