【GPU精粹与Shader编程】(四) 《GPU Gems 2》全书核心内容提炼总结 · 上篇


                        本文由@浅墨_毛星云 出品,首发于知乎专栏,转载请注明出处  

文章链接: https://zhuanlan.zhihu.com/p/38411575




《GPU Gems 2》这本书除了丰富的内容之外,还有两个特点。
  • 首先,《GPU Gems 2》是虚幻引擎之父Tim Sweeney作序。作为Epic Games的创始人,Unreal Engine早期主要开发者,Tim也在序中展示了《GPU Gems 2》出版伊始(2005年3月)时开发完成的Unreal Engine 3。UE3可谓是开创了一个时代。随后包括《新鬼泣》在内的100+款大作(2005年~2015年),都是基于UE3开发。具体列表可见:https://en.wikipedia.org/wiki/List_of_Unreal_Engine_games
  • 然后,《GPU Gems 2》的中文版是龚大@叛逆者2005年开始翻译的,距今已13年。13年前龚大就已经是图形学业界一线大牛,实在是让人佩服不已。

另外,虽然本书出版于2005年,但可以不夸张地说,书中介绍的很多方法技巧trick,哪怕是放到现在,依然非常值得学习和借鉴。
ok,篇幅原因,开场话就不多说了,我们直接开始正题。


本文的GitHub版

 

不少朋友们喜欢看GitHub版本的文章,我也很喜欢。

首先,MarkDown可以很方便地插入快捷导航目录,能进行瞬间跳转到指定子章节。其次,GitHub版本的文章中没有单篇文章的字数限制,少了很多篇幅方面的桎梏。而且因为Git的便利性,版本管理的优势,最新的勘误和修订第一时间会在GitHub的Repo中进行。

【本文的GitHub版本传送门】:

https://github.com/QianMo/Game-Programmer-Study-Notes



目录 · 本文核心内容Highlight


本文将进行重点提炼总结的主核心内容有:
  • 一、实现照片级真实感的虚拟植物(Toward Photorealism in Virtual Botany)
  • 二、GPU通用计算:流式编程与存储体系(General-Purpose Computation on GPU)

本文将进行提炼总结的次核心内容有:
  • 三、使用基于GPU几何体裁剪图的地形渲染(Terrain Rendering Using GPU-Based Geometry Clipmaps)
  • 四、几何体实例化的内幕(Inside Geometry Instancing)
  • 五、分段缓冲(Segment Buffering)
  • 六、用多流来优化资源管理(Optimizing Resource Management with Multistreaming)
  • 七、让硬件遮挡查询发挥作用(Hardware Occlusion Queries Made Useful)
  • 八、带位移映射的细分表面自适应镶嵌(Adaptive Tessellation of Subdivision Surfaces with Displacement Mapping)
  • 九、使用距离函数的逐像素位移贴图(Per-Pixel Displacement Mapping with Distance Functions)
  • 十、S.T.A.L.K.E.R.中的延迟着色(Deferred Shading in S.T.A.L.K.E.R.)
  • 十一、动态辐照度环境映射实时计算(Real-Time Computation of Dynamic Irradiance Environment Maps)
  • 十二、近似的双向纹理函数(Approximate Bidirectional Texture Functions)
  • 十三、基于贴面的纹理映射(Tile-Based Texture Mapping)
  • 十四、动态环境光遮蔽与间接光照(Dynamic Ambient Occlusion and Indirect Lighting)
  • 十五、精确的大气散射(Accurate Atmospheric Scattering)

I、核心章节提炼篇


一、实现照片级真实感的虚拟植物(Toward Photorealism in Virtual Botany)

图 真实感植物渲染 @UE4


【内容概览】


众所周知,植物的渲染需要很多的视觉深度和细节才能令人信服。
本章即关于渲染逼真自然场景的技术,描述了对实时游戏引擎友好的、用于渲染更真实的自然场景的策略。讲述了在不需要大量CPU或GPU占用的前提下渲染出包含大量植物和树组成的绿色植物场景。
内容安排方面,这章从管理大型户外环境场景数据这一基础开始描述。然后,提供一些细节,例如关于如何最大化GPU吞吐量,以便可以看到密集的草丛。接下来扩展这些技术,增加地面杂物和大型植物,如树,将阴影和环境影响组合进去。
一些真实感植物渲染的效果图:

图 真实感植物渲染 @UE4


图 真实感植物渲染 @UE4

图 真实感植物渲染 @UE4

【核心内容提炼】


1.1 场景管理(Scene Management)


任何3D游戏引擎都应该有环境相关渲染技术的管理和组织。
游戏引擎必须管理其渲染技术,以适合于它们希望看到的环境范围。以自然场景为主的游戏由上千棵树,灌木和可能上百万片草叶组成。直接分开渲染会出现数据管理问题,只有解决了这一问题才能以交互的帧率实时渲染。
我们的目标是在一个逼真的室外场景中大范围地移动游戏相机,而不需要在任务管理上花费过多的存储器资源。

1.1.1 种植栅格(The Planting Grid)

场景管理方面,首先是使用了虚拟栅格的思路。
我们在相机周围建立一个世界空间固定的栅格,来管理每一层的植物和其他自然物体的种植数据。每个栅格单元包含渲染它所在物理空间层的所有数据。特别是,单元数据结构存储了对应的顶点、索引缓冲区和材质信息来再现需要绘制的内容。
对植物的每个层,建立相机到层的距离,层需要用它来产生视觉效果,这决定了虚拟栅格的大小。相机移动,虚拟栅格也随之移动。当一个栅格单元不再在虚拟栅格中时,丢弃它,并在需要维护完整栅格结构的地方添加新的单元。在添加每个单元格时,用一种种植算法把渲染所需的数据填充到层。如下图。


图 一个虚拟栅格
图注:每层有一个世界空间对齐的固定大小的栅格。深绿的单元表现为活动单元。当相机向前移动时,丢弃标记为X的单元,添加新的单元(显示为亮绿色)以维持虚拟栅格的大小,实现过程中有用的改进是使用栅格单元池且循环使用,因为当一个旧单元被丢弃时,总会增加一个新单元。

1.1.2 种植策略(Planting Strategy)

对于充满自然物体的每个单元,需要在地面上选择要放置物体的适当位置。采用试探的方法根据被放置对象的类型来选择这些点。通常,需要的密度随机选点,然后看地面上的对应点是否适合于要种植的东西。而地面多边形的材质决定了一个层是否适用。
最显然的方式是在单元体中随机发射光线,直达地面,每当击中一个多边形,检查它是否适合种植(判断:草能种在这里吗?斜度会不会太大?),如果成功,那么就得到了一个种植点,继续这个过程,直到到达合适的密度。
这种方法不能处理重叠地形,且在少数栅格单元中,可能会花费过多的CPU时间。
比较好的方法是,选择所有与单元相交的多边形,丢弃所有不合适种植的多边形,然后扫描并转换它们来寻找合适的种植点。这与渲染管线中的光栅化一个多边形类似。

1.1.3 实时优化(Real-Time Optimization)

实时优化种植策略的方法包括,选择一个栅格单元中的多边形可以通过使用AABB树或类似的数据结构来快速完成。而由于相机的连续运动,许多单元可能要突然种植,所以它也可以高效地让这个任务排队,使任务在每帧中只占用相对固定的CPU资源。而通过扩大栅格,可以确保在单元的内容进入视野之前,所有的种植就已完成。

1.2 草地层(The Grass Layer)


实时渲染出无边的草地需要GPU技术和算法的细心平衡,主要的挑战是在相对低的计算和渲染开销下产生高度复杂的视觉外观。
这章的这一节中介绍了一种和[ Pelzer 2004]“渲染无数波动的草叶”相似的技术,且这章的技术以更低的GPU和CPU负载产生更高质量和更稳定的结果。
图 真实感草地渲染

首先,需要保证批次的最大化。该技术的目标是如何用相对较少的渲染API调用来绘制出尽可能多的草地,合理的方式是基于公告板。但其实更好的方式是在一次绘制调用中渲染尽可能多的内容(即一次drawcall渲染多个公告板)。
为实现这个目的,草的每一层(即使用相同纹理和其他参数的所有草)的每个栅格单元由一个顶点和一个索引缓冲区对表现。如下图。
图:绘制每个栅格的单元结构
对种植的每个草丛(或公告板),将其位置写入顶点缓冲区并更新对应的索引缓冲区。每个公告板需要4个顶点和6个索引。对每个顶点,将位置设置为已经种植草丛的点。
一旦顶点缓冲区建立并发送到显存,就可以用单次调用画出每个栅格单元的植物。
与Pelzer的方法不同的是,这里使用面向相机的公告板代替每丛3个方形,而且其方法没有进行屏幕对齐。面向屏幕的公告板在所有的视角下(即便向下看)创建一个固定的深度。而相机越是由上往下看草丛,3个方形丛的方法就越会失效。所以本文提到的方法,更加灵活,适用更多相机角度的情况。

1.2.1 通过溶解模拟Alpha透明(Simulating Alpha Transparency via Dissolve)


在渲染草的时候,想要使用透明来改善视觉混合和在接近虚拟栅格边界时的淡出。然而,基于Alpha的透明并不理想,因为它需要排序且速度很慢。虽然可以利用草较为杂乱的性质最小化一些排序技术,但实际上可以完全忽略这种做法。
为此,采取溶解效应(dissolve effect),也称纱门效应(screen-door effect)的方法,代替Alpha混合来模拟透明。首先,用一个噪音纹理调制草纹理的Alpha通道,然后使用Alpha测试从渲染中去除像素,通过从0到1调节Alpha测试数值,纹理表现出溶解的现象。这一过程如下图所示。
图 草纹理的构成
(a)漫反射纹理; (b)美工创建的alpha通道; (c)Perlin噪音纹理;(d)Perlin噪音与Alpha相乘的结果。这可以在像素着色器,或固定的Alpha测试值产生淡出。
这项技术的有点是Alpha测试的速度快而且与顺序无关。我们不再需要排序,草依然可以在远处淡出。虽然溶解在正常的情况下看起来不像真实的Alpha透明那么好,但可以利用自然的分形属性来完全掩饰任何溶解技术的视觉失真。
而实验表明,使用Perlin噪音纹理(Perlin 2002)代替随机的噪音纹理,则溶解效应与环境的适配程度几乎与Alpha透明一样好。

1.2.2 变化

为增加真实感,需引入一些变化。一种方式是使用多种草的图像,但分批方法限制我们在每个绘制调用中只能用一张纹理。好在可以使用大纹理,把多种草排布在上面,在建立顶点的时候,可以调整UV坐标以旋转纹理的不同子区域(即可以建立一个纹理图集)。
每个公告板也能带有颜色信息。如果在种植时也为每个草丛建立一种颜色,那么对渲染灰度纹理或在顶点着色器中做细微的颜色偏移非常有用。Perlin噪声在这里也可以使用,而且很容易,例如,草可以从健康的颜色过渡到垂死的褐色染色,以获得宽广的颜色变化并减少草的重复性。

图 使用RGB信息来增加草地的真实感 @ GeNa @Unity5
图 使用RGB信息来增加草地的真实 @ GeNa @Unity5


图 使用RGB信息来增加草地的真实感 @ GAIA @Unity 5
【注:每颗草的顶点中都包含RGB的信息。在此场景中,颜色值来自Perlin噪声函数,模拟了比较绿的草,并修补了不太健康的褐色】

1.2.3 光照

光照在草的外观上扮演了重要的角色。对于公告板草,要确保草和下面的地面一样受光。而地面自然起伏,并因此获得了不同角度的光照。我们需要通过减弱草的亮度来模拟这点,因此,需要知道草所在的地面角度,一个简单方法是在顶点定义中通过另一个向量传递这一信息。
在种植的时候,确定正在种植的草的多边形法线并把它带入公告板定义中。通过这种方式,顶点着色器就可以进行和草下多边形一样的光照计算、从而减弱它的彩色。在多丘陵的地形上,这会导致草和地面一样也有细微的到光的角度信息变化。
遗憾的是,这种方式导致草有一面一面的着色现象,即使地面的多边形是几乎平滑着色(如Gouraud着色)。为了避免这个问题,在种植处理期间必须平滑地插值通过顶点着色器的法线。
而如果太阳的角度是动态的,可以假设地面法线都大致向上,然后基于此法线和光的角度来计算光照。这样,就不一定要将地面的多边形法线带入顶点的定义和后续计算。这是一个画质的权衡,但这种方式对于应用程序来说已经完全足够。

1.2.4 风

当风吹过,草地泛起涟漪,草变得鲜活起来了。
通过每一帧偏移草方形顶部的两个顶点,可以使方形在风中摇摆。可以使用一个正弦近似的和计算这个偏移,类似计算水表面的波动[Finch 2004]。这个技巧是在顶点定义中带一个混合权重,草方形的顶部两个顶点被设为1,底部两个顶点为0,然后把这一数值乘以风的缩放系数,底部的顶点仍然牢牢地依附在地上。
  • 10
    点赞
  • 21
    收藏
    觉得还不错? 一键收藏
  • 6
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 6
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值