您当前的位置: 首页 >  unity

Jave.Lin

暂无认证

  • 2浏览

    0关注

    704博文

    0收益

  • 0浏览

    0点赞

    0打赏

    0留言

私信
关注
热门博文

Unity Shader PostProcessing - 8 - Bloom 泛光

Jave.Lin 发布时间:2020-03-21 18:31:57 ,浏览量:2

文章目录
  • 实现
    • 提取亮度图
    • 将提取的像素模糊
    • 将模糊的像素与原图叠加
  • 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 方法的几种结果: 在这里插入图片描述

不同的提取结果,对最终的叠加结果肯定也是不一样的,根据自己需要来选择或是添加不同的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
  • Direct3D轮回:游戏特效之全屏泛光(Bloom)
  • Unity Shader-后处理:Bloom全屏泛光
关注
打赏
1664331872
查看更多评论
立即登录/注册

微信扫码登录

0.0399s