搜索
 找回密码
 立即注册

简单一步 , 微信登陆

作者:chenfangyu | 时间:2016-12-14 16:52:44 | 阅读:3097| 只看该作者
Glow的基本思路:
对场景渲染为2种纹理,一是正常效果的场景纹理,一是只保留高亮区域的高亮纹理(即辉光源,Glow Source)。把高亮纹理进行模糊处理后,再叠加到场景纹理上,就能产生类似HDR中Glare或Streak的效果。
简单测试效果如下:


主要性能消耗在于:


1,需要2次渲染场景。

trick之一是,把亮度保存到场景纹理的alpha通道里。

vec3 color = texture2D(diffuseMap, gl_TexCoord[0].st);

scene = vec4(color, lum);

在后续处理时,由rgb * a得到高亮纹理,再做模糊处理。

vec4 color = texture2D(scene, gl_TexCoord[0].st);

vec3 glow = color.rgb * color.a;

另一种方法,是同时渲染到2张纹理。比如用OGL的FBO做RenderTarget的话,可以同时为FBO绑定多张纹理,然后在Shader里控制分别写入不同的值到不同的纹理:

vec3 color = texture2D(diffuseMap, gl_TexCoord[0].st).rgb;

glFragData[0] = color; // 场景纹理

glFragData[1] = color * lightValue; // 高亮纹理

2,对高亮纹理的模糊。

通常有2种方式:

- 2D高斯模糊,对像素周围3x3或者5x5进行采样然后模糊。

- 分布模糊:先将整张纹理进行横向的1D模糊,再对其结果进行纵向的1D模糊。

分布模糊在效果上接近2D高斯模糊,而计算量要少很多,故通常使用这种方法。

声明:所用原始图片版权均为其作者所有。

Glow的效果和性能都让我非常满意。但是再进一步研究的话,比如motion blur,depth of field,lens effect(or ghost),这些如果都使用fake方式,那么每个效果都需要一个功能模块,结构会比较复杂。
如果使用HDR的渲染流程,则是;
1,渲染场景。
2,提取高亮区域。
3,对高亮区域应用bloom效果。
4,对高亮区域应用streak效果。
5,对高亮区域应用ghost效果。
……
很直观的逻辑。
另外HDR最吸引我的在于亮度范围: 亮的地方更亮,暗的地方更暗。 —— 真是很好的概括。
说到这里,不得不提及Game Programming Gems 4的一篇文章,介绍了通过动态调整Gamma来改变LDR图像中的色彩,以达到类似曝光调整的效果,性能和效果都十分令人赞赏。
HDR的流程大概为:
1,使用高亮度渲染场景,并保存为浮点数纹理。
- 应用HDR环境贴图。
- 应用高范围的材质,光源和照明模型。(即不必被局限在0~1里)
2,将高亮区域取出,保存为浮点数纹理。
- 在pixel shader里判断该像素的亮度是否大于阀值。
vec3 color = texture2D(scene, gl_TexCoords[0].st);
float lum = dot(vec3(0.3, 0.59, 0.11), color);
gl_FragColor.rgb = (lum > brightThreshold) ? color : vec3(0.0);
3,对高亮区域进行应用bloom滤镜。
4,对高亮区域应用streak滤镜。
5,对高亮区域应用ghost滤镜。
6,将scene,bloom,streak,ghost等合成为一张最终效果纹理。
7,对最终纹理应用tone mapping,及曝光调整。

HDR最广为人知的特征之一就是bloom,以至于不少人看到类似bloom或者glare的效果就高呼HDR,呵呵。
bloom的原理在于,将高亮的区域扩散出去。放在3D实现里则是,模糊高亮区域后叠加到原始图像上。所以,主要技术点在于“模糊”。
正如HDR之一中所提到的,模糊的常用方式有两种:2D高斯模糊和分步模糊。
2D高斯模糊 Multiple Gaussian Filter
2D高斯模糊能根据权重将范围之内的像素进行加权采样,以实现模糊的效果。但是一次高斯模糊并不能达到很好的效果,比如中间高亮,边缘扩散。因此需要对不同范围进行多次高斯模糊。然而大范围的高斯模糊开销极高,比如5x5的高斯模糊,处理每个像素时就需要25次纹理采样,以及更多次的浮点数加法和乘法。

于是有人提出了结合Downscaled Buffer和双线形过滤的方法:对原始纹理应用双线形采样,渲染到缩小为四分之一的纹理上,如此多次,再将它们叠加,就得到了接近多次大范围2D高斯模糊的效果。
1/4 x 1/4
+
1/8 x 1/8
+
1/16 x 1/16
+
1/32 x 1/32
+
1/64 x 1/64
=
最终叠加效果
(令人郁闷的是,我使用双线性过滤+Downsample后的效果并非如此,即便应用了5x52D高斯过滤也未能达到如此程度的扩散。还有待继续研究……)
分步模糊 Separable Filter

分步模糊虽然能够把2D高斯模糊转换成2次1D高斯模糊,但是它在处理高分辨率图像时仍然比较高耗,适合于高精度格式的低分辨率图像处理。可以使用基于双线形过滤的Cone Filter:

其中灰色点为处理的像素,红色点为偏移了半个像素的采样点。
而根据 Masaki Kawase在DOUBLE-S.T.E.A.L中的试验,他应用了一种扩展的Cone Filter:
1st Pass
2nd Pass
3rd Pass

如此在2个RenderTarget之间反复多次,最终达到整体模糊的效果。
streak 即星光效果,将高亮区域沿指定方向进行拉伸得到,本质上仍然是模糊的运用。Kawase同学在他的报告中介绍streak filter,类似于他的bloom filter,也是逐步扩大采样范围,具体参见他在GDC2003 的Presentation:Frame Buffer Postprocessing Effects in DOUBLE-S.T.E.A.L (Wreckless)。
测试用于X方向的streak,处理效果不错,但是用在浮点数纹理上开销很大,因为每个方向都需要进行数个Pass再叠加。而每个pass里又有数次采样再加权合成。
试验的另一种方法,使用two pass的分步模糊,分别沿“/”和“/”方向进行17次采样的1D高斯模糊。开销较小,但是streak的长度比较有限。如果加大采样的间隔,又会影响采样的效果。

Ghost效果,又称之为Sprites,或Lens effect。
传统算法(Sprites):
1,检测光源是否可见。
2,判断可见光源的可见像素有多少。
3,如果可见像素超过阀值,则渲染Sprites。
4,Sprites由多个billboard应用alpha贴图合成。
5,对场景中每个光源做以上处理。
HDR算法:
1,从场景中抽取高亮区域。
2,将高亮纹理进行关于屏幕中心的缩放。公式为:
texCoord = (texCoord-0.5)*(Scale) + 0.5;
Scale的正负和数值决定纹理被缩放的方向和尺寸。数值越大,越靠近中心,尺寸越小。
可以在pixel shader中一次进行4次缩放并叠加,比如{ 0.6, 2.0, -2.0, -0.6 },则一个光源变成共线的,尺寸对称的4个光源。对此再做一次处理,则变成16个。以此类推。
3,因为涉及到缩放,所以纹理被设为CLAMP。为了解决缩小后纹理出现边缘拉扯的情况,还需要引入一张mask纹理,

将缩放后的纹理与其相乘,则可以得到柔和边缘的效果。
两种方法的优缺点比较:


Sprites算法:
·优点
- 渲染质量高。
- 可以指定产生效果的光源。
- 光源数量少时开销很低。
·缺点
- 开销受到光源数量的影响。
- 不易处理任意形状的光源。
- 不易用于间接光源,比如高亮的反光。

HDR算法:
·优点
- 可被应用于反射和折射区域。
- 开销与光源数量无关。
- glare的形状可以通过使用不同的算法改变。
·缺点
- 像素填充率的开销。
- 锯齿
- 很难控制其生成:很亮的光源产生的glare也很亮,而不太亮的光源也可能产生glare。




收藏
收藏0
分享
分享
点赞
点赞0
反对
反对0
回复

使用道具 举报

您需要登录后才可以回帖 登录 | 立即注册
手机版