Unity Shader PostProcessing - 8 - Bloom 泛光

文章目录

  • 实现
    • 提取亮度图
    • 将提取的像素模糊
    • 将模糊的像素与原图叠加
  • Project
  • References

事情一大堆,要拿快递,又要寄快递,还要帮人板家具,还要去买菜,还要偶尔做饭,还要做包子,拖地洗碗,等等,疫情期间可是点了好多其他的新技能,让我手动哭笑一下,T^T。QAQ。

好不容易挤出时间来学习,得千万别浪费了,而且最近看到十几年,几十年的图形专业大佬,真的感叹,人外有人天外有天。

OK,如题,这次实现的是比较简单大众都了解的:Bloom,泛光效果。

实现

  • 先按某个指定的图像亮度阈值,提取出高于阈值的亮度像素。
  • 将提取出来的亮度图做模糊,可以均值或是高斯模糊,均值我就不提了,高斯模糊可以参考之前写的一篇:Unity Shader PostProcessing - 6 - GaussianBlur 高斯模糊+CommandBuffer使用做一些其他的特效。
  • 然后将模糊后的亮度图与原始图像做叠加。

提取亮度图

CSharp叫传入Shader阈值:

[Header("Pickup luminance")]
[Range(0f, 1f)]
public float luminanceThreshold_hash = 0.5f;        // 提取泛光亮度的赋值

...

RenderTexture luminanceRT = RenderTexture.GetTemporary(Screen.width, Screen.height, 0);
luminanceRT.filterMode = FilterMode.Bilinear;
luminanceRT.name = "luminanceRT";
mat.SetFloat(_LuminanceThreshold_hash, luminanceThreshold_hash);
Graphics.Blit(source, destination, mat, 0);
RenderTexture.ReleaseTemporary(luminanceRT);

Shader处理:只要大于阈值的都标1,否则0。

fixed4 frag_pickupLuminance (v2f_common i) : SV_Target {
      fixed4 col = tex2D(_MainTex, i.uv);
      #if _PICKUP__LUMINANACE_0
          return step(_LuminanceThreshold, LinearRgbToLuminance(col.rgb));
      #elif _PICKUP__LUMINANACE_1
          float luminance = LinearRgbToLuminance(col.rgb);
          return step(_LuminanceThreshold, luminance) * col;
      #elif _PICKUP__LUMINANACE_2
          return _LuminanceThreshold == 1 ? 0 : saturate((col - _LuminanceThreshold) / (1 - _LuminanceThreshold));
      #else // _PICKUP__LUMINANACE_3
          return saturate(col - _ColorThreshold);
      #endif
  }

下面是不同pickup luminance 方法的几种结果:
Unity Shader PostProcessing - 8 - Bloom 泛光_第1张图片

不同的提取结果,对最终的叠加结果肯定也是不一样的,根据自己需要来选择或是添加不同的pickup luminance 方法。

将提取的像素模糊

这里我还是懒得再写,直接用之前的高斯模糊(也可以使用其他模糊方式,如:均值模糊,等),结果如下:
在这里插入图片描述

将模糊的像素与原图叠加

Unity Shader PostProcessing - 8 - Bloom 泛光_第2张图片

第三种的提取方式,个人会比较喜欢,如下图:
Unity Shader PostProcessing - 8 - Bloom 泛光_第3张图片

我在阅读References中的Direct3D轮回:游戏特效之全屏泛光(Bloom),里面引用了MS的三个Shader中,有还对原图的饱和度用调整的。这里我就不添加了,因为效果的切确需要是因人而异的来改动Shader就好。

下面是调整饱和度的代码:

float BloomIntensity;
float BaseIntensity;

float BloomSaturation;
float BaseSaturation;

// 减缓颜色的饱和度
float4 AdjustSaturation(float4 color, float saturation)
{
    // 人眼更喜欢绿光,因此选取0.3, 0.59, 0.11三个值
    float grey = dot(color, float3(0.3, 0.59, 0.11));
    return lerp(grey, color, saturation);
}

float4 ThePixelShader(float2 texCoord : TEXCOORD0) : COLOR0
{
    // 提取原始场景贴图及模糊场景贴图的像素颜色
    float4 bloom = tex2D(BloomSampler, texCoord);
    float4 base = tex2D(BaseSampler, texCoord);
    
    // 柔化原有像素颜色
    bloom = AdjustSaturation(bloom, BloomSaturation) * BloomIntensity;
    base = AdjustSaturation(base, BaseSaturation) * BaseIntensity;
    
    // 结合模糊像素值微调原始像素值
    base *= (1 - saturate(bloom));
    
    // 叠加原始场景贴图及模糊场景贴图,即在原有像素基础上叠加模糊后的像素,实现发光效果
    return base + bloom;
}

而我的混合提取的模糊图 + 原图的方式就很简单:

sampler2D _GlowTex;
float _BloomIntensity;
fixed4 frag_merge_and_output(v2f_common i) : SV_Target {
    fixed4 srcCol = tex2D(_MainTex, i.uv);
    fixed4 glowCol = tex2D(_GlowTex, i.uv);
    return lerp(srcCol, saturate(srcCol + glowCol), _BloomIntensity);
}

Project

backup : UnityShader_DepthOfFieldTesting_2018.3.0f2

References

  • Direct3D轮回:游戏特效之全屏泛光(Bloom)
  • Unity Shader-后处理:Bloom全屏泛光

你可能感兴趣的:(unity,unity-shader)