Unity Shader PostProcessing - 8 - Bloom 泛光

141 篇文章 35 订阅

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

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

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


实现


提取亮度图

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 方法的几种结果:
在这里插入图片描述

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


(这里中途插入一些更新,其实这里的像素帅选算法,按自己的项目美术风格来就好,没有固定的方式,下面是列出一个最简单的筛选方式)

// Clamp HDR value within a safe range
half3 SafeHDR(half3 c) { return min(c, 65000); }
half4 SafeHDR(half4 c) { return min(c, 65000); }

// RGBM encoding/decoding
half4 EncodeHDR(float3 rgb)
{
#if USE_RGBM
    rgb *= 1.0 / 8;
    float m = max(max(rgb.r, rgb.g), max(rgb.b, 1e-6));
    m = ceil(m * 255) / 255;
    return half4(rgb / m, m);
#else
    return half4(rgb, 0);
#endif
}

float3 DecodeHDR(half4 rgba)
{
#if USE_RGBM
    return rgba.rgb * rgba.a * 8;
#else
    return rgba.rgb;
#endif
}
...
	half4 albedo = tex2D(_MainTex, i.uv);
	
#if UNITY_COLORSPACE_GAMMA
    m = GammaToLinearSpace(m);
#endif

    float r = step(_Threshold, albedo.r) * albedo.r;
    float g = step(_Threshold, albedo.g) * albedo.g;
    float b = step(_Threshold, albedo.b) * albedo.b;
    return EncodeHDR(float3(r, g, b));

将提取的像素模糊

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


将模糊的像素与原图叠加

在这里插入图片描述

第三种的提取方式,个人会比较喜欢,如下图:
在这里插入图片描述

我在阅读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);
}

另外 bloom 效果,一般需要他陪 HDR 的 FrameBuffer,那样可以比较好的控制那块像素需要有效果

一般很多我们看到的游戏都会 HDR(FB) + Bloom 来制作各种赛博朋克风


Project

backup : UnityShader_DepthOfFieldTesting_2018.3.0f2


References

  • 2
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值