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);
        }
    }
}
相关推荐
YY-nb5 小时前
Unity Apple Vision Pro 开发教程:物体识别跟踪
unity·游戏引擎·apple vision pro
Cool-浩5 小时前
Unity 开发Apple Vision Pro物体识别追踪ObjectTracking
unity·ar·apple vision pro·mr·物体识别·vision pro教程·objecttracking
向宇it17 小时前
【从零开始入门unity游戏开发之——C#篇23】C#面向对象继承——`as`类型转化和`is`类型检查、向上转型和向下转型、里氏替换原则(LSP)
java·开发语言·unity·c#·游戏引擎·里氏替换原则
Cool-浩1 天前
Unity 开发Apple Vision Pro空间锚点应用Spatial Anchor
unity·游戏引擎·apple vision pro·空间锚点·spatial anchor·visionpro开发
吴梓穆1 天前
unity 最小后监听键盘输入
unity
一个程序员(●—●)1 天前
四元数旋转+四元数和向量相乘+音频相关
unity·游戏引擎
YY-nb1 天前
Apple Vision Pro 开发教程:通过 TestFlight 把开发的程序安装到其他的设备上测试
unity·apple vision pro
Ke-Di1 天前
Unity-URP设置单独渲染UI相机
ui·unity
冒泡P1 天前
【Lua热更新】上篇
开发语言·数据结构·unity·c#·游戏引擎·lua
十画_8241 天前
Unity 6 中的新增功能
unity·游戏引擎