Bloom效果

相关概念

显示器能显示的亮度是有限的,反映到RGB值上即0~1这个范围,被称为LDR(低动态范围,low dynamic range)。

然而现实世界则不局限于LDR,现实中的亮度是无限的。为了实现“更亮”的光照,出现了HDR(high dynamic range,高动态范围)这一技术,HDR图像的亮度范围更广,可以真实地显示人眼所见的现实中的画面,解决了LDR下图像明暗对比区分不明显的问题。

HDR的颜色值可以大于1,但由于显示器存在亮度上限,最终HDR输出的颜色还是要映射到LDR限定亮度范围内,也就是色调映射(tonemapping)。

Bloom的出现就是为了达成在LDR标准下显示拟真光照效果的目的。Bloom有点类似Blur,只不过Bloom是基于亮度混合相邻像素而非基于颜色。先混合亮度形成亮度模糊,再叠加该模糊图片到原图上,制造过亮效果。

Unity的camera可以设置是否开启HDR…开启HDR(右)会有外发光,比较朦胧,更接近真实发光的物体。

shaderlab实现

模糊

像素越多,采样次数也愈多,给GPU造成更大负担(这个可以看之前的Blur篇,使用高斯模糊就有这个问题)。这次使用一种更快的方法。通过降低临时纹理的分辨率和GPU内置的双线性过滤(bilinear filtering)来达到模糊目的。

Downsampling

首先需要将画面模糊(blur)。可以通过降采样达成。

Downsampling的实现不需要在着色器加东西,直接在cs文件中进行——

void OnRenderImage (RenderTexture source, RenderTexture destination) {

		int width = source.width / 2;
		int height = source.height / 2;
		RenderTextureFormat format = source.format;

		RenderTexture currentDestination = RenderTexture.GetTemporary(width, height, 0, format);

		Graphics.Blit(source, currentDestination);
		RenderTexture currentSource = currentDestination;
		Graphics.Blit(currentSource, destination);
		RenderTexture.ReleaseTemporary(currentSource);

    //downsampling
		for (int i = 1; i < iterations; i++)
		{
			width /= 2;
			height /= 2;
			if (height < 2)
			{
				break;
			}
			currentDestination = RenderTexture.GetTemporary(width, height, 0, format);
			Graphics.Blit(currentSource, currentDestination);
			RenderTexture.ReleaseTemporary(currentSource);
			currentSource = currentDestination;
		}
}

改进后的模糊

上述的模糊效果还是有明显的方块边界,接下来对其进行改进。

通过SampleBox


		half3 Sample (float2 uv) {
			return tex2D(_MainTex, uv).rgb;
		}

		half3 SampleBox (float2 uv, float delta) {
			float4 o = _MainTex_TexelSize.xyzw * float2(-delta, delta).xxyy;
			half3 s =
				Sample(uv + o.xy) + Sample(uv + o.zy) +
				Sample(uv + o.xw) + Sample(uv + o.zw);
			return s * 0.25f;
		}

参考

  1. Catlike Coding·Bloom