Unity是怎样实现Bloom Image Effect的

本文介绍了Unity中如何利用OnRenderImage接口实现Bloom图像效果,包括图像缩减采样、颜色切割、模糊处理和放大叠加等步骤,详细解析了Unity自带Bloom效果的实现原理。
摘要由CSDN通过智能技术生成

内容简介

Unity提供的Image Effect开发接口,是通过MonoBehaviour.OnRenderImage (RenderTexture source, RenderTexture destination)提供的,其中source是引擎传入的没有经过本次处理的原始图像,而我们将把经过处理的结果图像绘制到destination上去。通过实现这个函数,在引擎最后把渲染结果显示之前,Unity给了开发者一个机会来对image进行处理。Unity自带的Bloom效果也是通过这种方式实现的,下面我们来一起剖析Bloom的实现原理。

缩减采样(Downsample)

为了提高后面处理过程的效率并且增强bloom的效果,Bloom的OnRenderImage函数首先对原始图像进行了2次缩减采样。关键代码如下:
                Graphics.Blit (source, halfRezColorDown, screenBlend, 2);
                RenderTexture rtDown4 = RenderTexture.GetTemporary (rtW4, rtH4, 0, rtFormat);
                Graphics.Blit (halfRezColorDown, rtDown4, screenBlend, 2);
                Graphics.Blit (rtDown4, quarterRezColor, screenBlend, 6);
                RenderTexture.ReleaseTemporary(rtDown4);

第1行将原始图像source渲染到长、宽各缩为一半的RenderTexture halfRezColorDown中去,渲染时使用BlendForBloom这个shader的pass 2。我们来看一下这个shader的pass 2里做了些什么:

	v2f_mt vertMultiTap( appdata_img v ) {
		v2f_mt o;
		o.pos = mul(UNITY_MATRIX_MVP, v.vertex);
		o.uv[4] = v.texcoord.xy;
		o.uv[0] = v.texcoord.xy + _MainTex_TexelSize.xy * 0.5;
		o.uv[1] = v.texcoord.xy - _MainTex_TexelSize.xy * 0.5;	
		o.uv[2] = v.texcoord.xy - _MainTex_TexelSize.xy * half2(1,-1) * 0.5;	
		o.uv[3] = v.texcoord.xy + _MainTex_TexelSize.xy * half2(1,-1) * 0.5;	
		return o;
	}
	
	half4 fragMultiTapMax (v2f_mt i) : SV_Target {
		half4 outColor = tex2D(_MainTex, i.uv[4].xy);
		outColor = max(outColor, tex2D(_MainTex, i.uv[0].xy));
		outColor = max(outColor, tex2D(_MainTex, i.uv[1].xy));
		outColor = max(outColor, tex2D(_MainTex, i.uv[2].xy));
		outColor = max(outColor, tex2D(_MainTex, i.uv[3].xy));
		return outColor;
	}
vertex shader中,将5个纹理坐标放入了顶点中,以便后继在fragment shader中取得插值来使用。可以看到o.uv[4]里保存的是顶点处的uv坐标,而o.[0]、o.[1]、o.[2]、o.[3]则保存了周围4个u、v各偏移半个像素对应的4个点处的uv值。那么这些uv坐标代表什么含义呢?


如上图所示,假设原始图像是8×8尺寸,图中黄色区域包括了原始图像的4个像素,绿色圆形区域代表像素中心。当我们将它渲染到一半尺寸,即4×4的图像时,每4个原始图像中的像素对应1个目标图像中的像素,如黄色区域所示,图中红色圆形代表目标像素的中心。当fragment shader填充目标图像像素时,(经过插值的)o.uv[4]对应该像素中心处的uv坐标,而o.[0]、o.[1]、o.[2]、o.[3]则正好对应原始图像中距目标像素中心最近的4个原始像素中心处的uv坐标。利用这些uv坐标对原始图形进行采样,就能够通过某种方式决定目标像素。就像 fragment shader中的代码所体现的,它利用经过插值的5个uv坐标对原始图像进行采样,然后取各个通道的最大值,最终输出目标像素。注意这里的downsample并不是常见的取四个相关的原始像素的平均值,而是取包括目标像素中心所在位置颜色的最大值,这样做的目的应该是人为扩大高亮区域。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值