Shader后期处理-Bloom

原理

  • 对原场景图进行筛选,所有小于这个阈值的像素都被筛掉
  • 对上一步操作的结果进行模糊操作,达到光溢出的效果
  • 最后将处理过的图像和原图像进行叠加,得到最终效果

参考

代码

  • Post_Bloom.shader
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    63
    64
    65
    66
    67
    68
    69
    70
    71
    72
    73
    74
    75
    76
    77
    78
    79
    80
    81
    82
    83
    84
    85
    86
    87
    88
    89
    90
    91
    92
    93
    94
    95
    96
    97
    98
    99
    100
    101
    102
    103
    104
    105
    106
    107
    108
    109
    110
    111
    112
    113
    114
    115
    116
    117
    118
    119
    120
    121
    122
    123
    124
    125
    126
    127
    128
    129
    130
    131
    132
    133
    134
    135
    136
    137
    138
    139
    140
    141
    142
    143
    144
    145
    146
    147
    148
    149
    150
    151
    152
    153
    154
    155
    156
    157
    158
    159
    160
    161
    162
    163
    164
    165
    166
    167
    168
    169
    170
    171
    172
    173
    174
    175
    176
    Shader "Post/Post_Bloom"
    {
    Properties
    {
    _MainTex("Base (RGB)", 2D) = "white" {}
    _BlurTex("Blur", 2D) = "white"{}
    }

    CGINCLUDE
    #include "UnityCG.cginc"

    struct v2f_threshold
    {
    float4 pos : SV_POSITION;
    float2 uv : TEXCOORD0;
    };

    struct v2f_blur
    {
    float4 pos : SV_POSITION;
    float2 uv : TEXCOORD0;
    float4 uv01 : TEXCOORD1;
    float4 uv23 : TEXCOORD2;
    float4 uv45 : TEXCOORD3;
    };

    struct v2f_bloom
    {
    float4 pos : SV_POSITION;
    float2 uv : TEXCOORD0;
    float2 uv1 : TEXCOORD1;
    };

    sampler2D _MainTex;
    float4 _MainTex_TexelSize;
    sampler2D _BlurTex;
    float4 _BlurTex_TexelSize;
    float4 _offsets;
    float4 _colorThreshold;
    float4 _bloomColor;
    float _bloomFactor;

    v2f_threshold vert_threshold(appdata_img v)
    {
    v2f_threshold o;
    o.pos = UnityObjectToClipPos(v.vertex);
    o.uv = v.texcoord.xy;
    //dx中纹理从左上角为初始坐标,需要反向
    #if UNITY_UV_STARTS_AT_TOP
    if (_MainTex_TexelSize.y < 0)
    o.uv.y = 1 - o.uv.y;
    #endif
    return o;
    }

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

    fixed4 frag_threshold(v2f_threshold i) : SV_Target
    {
    fixed4 color = tex2D(_MainTex, i.uv);

    fixed val = saturate(luminance(color) - luminance(_colorThreshold));
    return color * val;

    // return saturate(color - _colorThreshold);
    }

    v2f_blur vert_blur(appdata_img v)
    {
    v2f_blur o;
    _offsets *= _MainTex_TexelSize.xyxy;
    o.pos = UnityObjectToClipPos(v.vertex);
    o.uv = v.texcoord.xy;

    o.uv01 = v.texcoord.xyxy + _offsets.xyxy * float4(1, 1, -1, -1);
    o.uv23 = v.texcoord.xyxy + _offsets.xyxy * float4(1, 1, -1, -1) * 2.0;
    o.uv45 = v.texcoord.xyxy + _offsets.xyxy * float4(1, 1, -1, -1) * 3.0;

    return o;
    }

    fixed4 frag_blur(v2f_blur i) : SV_Target
    {
    fixed4 color = fixed4(0, 0, 0, 0);
    color += 0.40 * tex2D(_MainTex, i.uv);
    color += 0.15 * tex2D(_MainTex, i.uv01.xy);
    color += 0.15 * tex2D(_MainTex, i.uv01.zw);
    color += 0.10 * tex2D(_MainTex, i.uv23.xy);
    color += 0.10 * tex2D(_MainTex, i.uv23.zw);
    color += 0.05 * tex2D(_MainTex, i.uv45.xy);
    color += 0.05 * tex2D(_MainTex, i.uv45.zw);
    return color;
    }

    v2f_bloom vert_bloom(appdata_img v)
    {
    v2f_bloom o;
    o.pos = UnityObjectToClipPos(v.vertex);

    o.uv.xy = v.texcoord.xy;
    o.uv1.xy = o.uv.xy;
    #if UNITY_UV_STARTS_AT_TOP
    if (_MainTex_TexelSize.y < 0)
    o.uv.y = 1 - o.uv.y;
    #endif
    return o;
    }

    fixed4 frag_bloom(v2f_bloom i) : SV_Target
    {
    fixed4 ori = tex2D(_MainTex, i.uv1);
    fixed4 blur = tex2D(_BlurTex, i.uv);

    fixed4 final = ori + _bloomFactor * blur * _bloomColor;
    return final;
    }
    ENDCG

    SubShader
    {
    //pass 0: 提取高亮部分
    Pass
    {
    ZTest Off
    Cull Off
    ZWrite Off
    Fog
    {
    Mode Off
    }

    CGPROGRAM
    #pragma vertex vert_threshold
    #pragma fragment frag_threshold
    ENDCG
    }

    //pass 1: 高斯模糊
    Pass
    {
    ZTest Off
    Cull Off
    ZWrite Off
    Fog
    {
    Mode Off
    }

    CGPROGRAM
    #pragma vertex vert_blur
    #pragma fragment frag_blur
    ENDCG
    }

    //pass 2: Bloom效果
    Pass
    {

    ZTest Off
    Cull Off
    ZWrite Off
    Fog
    {
    Mode Off
    }

    CGPROGRAM
    #pragma vertex vert_bloom
    #pragma fragment frag_bloom
    ENDCG
    }
    }
    }
  • PostBloom.cs
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    using UnityEngine;

    [ExecuteInEditMode]
    [ImageEffectAllowedInSceneView]
    [RequireComponent(typeof(Camera))]
    public class PostBloom : MonoBehaviour
    {
    [SerializeField] private Shader shader;
    private Material m_material;

    [Range(0.0f, 1.0f)] public float bloomFactor = 0.5f;
    [Range(0, 4)] public int downSample = 1;
    public int samplerScale = 1;
    public Color colorThreshold = Color.gray;
    public Color bloomColor = Color.white;

    void Awake()
    {
    m_material = new Material(shader);
    }

    void OnValidate()
    {
    if (shader)
    m_material = new Material(shader);
    }

    void OnRenderImage(RenderTexture source, RenderTexture destination)
    {
    if (m_material)
    {
    RenderTexture temp1 = RenderTexture.GetTemporary(source.width >> downSample, source.height >> downSample, 0,
    source.format);
    RenderTexture temp2 = RenderTexture.GetTemporary(source.width >> downSample, source.height >> downSample, 0,
    source.format);

    Graphics.Blit(source, temp1);

    m_material.SetVector("_colorThreshold", colorThreshold);
    Graphics.Blit(temp1, temp2, m_material, 0);

    m_material.SetVector("_offsets", new Vector4(0, samplerScale, 0, 0));
    Graphics.Blit(temp2, temp1, m_material, 1);
    m_material.SetVector("_offsets", new Vector4(samplerScale, 0, 0, 0));
    Graphics.Blit(temp1, temp2, m_material, 1);

    m_material.SetTexture("_BlurTex", temp2);
    m_material.SetVector("_bloomColor", bloomColor);
    m_material.SetFloat("_bloomFactor", bloomFactor);

    Graphics.Blit(source, destination, m_material, 2);

    RenderTexture.ReleaseTemporary(temp1);
    RenderTexture.ReleaseTemporary(temp2);
    }
    }
    }

Shader后期处理-Bloom
https://automask.github.io/wild/2021/06/17/lab/S_Unity_Post_Bloom/
作者
Kyle Zhou
发布于
2021年6月17日
许可协议