本文部分参照该文章https://zhuanlan.zhihu.com/p/35974789
1.引言
本章介绍了一种灵活的,广泛应用的草模拟。该方案渲染的草不仅生长得自然,也能够逼真地在风中舞动,而且性能很高。
2.概述
首先,需要意识到,对单个草叶的细节建模意义不大,因为那样大片草地需要的多边形数目会太多。所以,我们必须建立一个符合以下条件的简单而有用的替代方案:
- 许多草的叶片必须由少数多边形表示。
- 草地必须从不同的视线看起来显得密集。
而要做到让场景不依赖于摄像机的位置和方向,可以把一些草叶组合起来,表示在一个纹理中,并将多个纹理组合起来,且在结果中单个的多边形不应该引起注意。当观察者四处活动时,通过将草体加入混合操作或者移除混合操作,以在距离范围内增加或删去草体,来保证整个草地的渲染效果具有稳定的视觉质量。
3.草体的准备
3.1 草的纹理
草的纹理,应该是一些一簇一簇聚集丛生的草,否则,会出现大片的透明区域。需在透明的alpha通道上画实体草茎。在彩色通道中,用深浅不同的绿色和黄色,来较好地区别各个单独的叶片,也应该模拟不同情况的草叶:长得好的和长得差的、老的和嫩的,甚至区别叶片的前面与后面。
下图是一个草地纹理的示例。
3.2 草体
对于线性排布,如果从垂直于多边形的方向观看场景,就会立刻穿帮,看出草地多边形的结构是线性排布的。另外这种情况下草地会看起来非常稀疏。只有在摄像机自动导航,或者渲染无法到达的远距离草地时,才会考虑这样的排布。为了保证独立于当前视线的良好视觉质量,我们必须交叉地排布草地多边形。已证明,使用星型结构是非常好的。下图给出了“草体”可能的两种变体。
他们由3个相交的方块构成。我们必须禁用背面剔除来渲染多边形,以保证双面都可见。为了得到合适的照明度,应该让所有顶点的法线方向与多边形的垂直边平行。这保证了位于斜坡上的所有草体都可以得到正确的光照,不会因为地形的亮度而出现差异。
如果把这些草地物体彼此相当靠近地设置在一个大的区域里,如下图。在运行期间把它们从后向前进行排序,使用alpha混合,并启用DrawCall中的z-testing/writing,那么就会得到自然而茂密的草地渲染效果。
4.草地的动画
关于草地的动画,基本思想是以三角函数(尤其是正弦和余弦)为基础进行计算,且计算应该考虑到移动的位置和当前时间、风向和强度。我们的每种技术都只移动草体较高的定点。在一个顶点shader中,通过检查纹理坐标,区别较高的顶点和较低的顶点是很容易的。对草纹理而言,所有的上面顶点应该有相同的v坐标。本文首先实现一个顶点shader的框架,在所有的3种动画技术实现方案中都使用该框架,只有纯动画的部分有差别。
顶点shader框架如下:
动画部分实现起来有几种方法:
1)每草丛草体的动画(Animation per Cluster of Grass Objects)。
对一丛靠近的草体,上面的多边形顶点统一地发生移动。动画的平移矢量由cpu计算,若在cpu上使用更费时的算法,还可以让我们利用非常复杂的风模拟。因为每丛草体由它自己的平移矢量来支持,所以必须针对每丛草体来改变这个常量,因此不得不经常地打断对整个草地的渲染,而且为每丛草体使用独立的绘图调用。
优点:
- 复杂的动画计算基于cpu算法进行
- 因为一个多边形上顶点的距离是固定的,所以不发生变形。
缺点:
- 需要许多的draw call
- 由于整个草丛的所有顶点同步动画,可能出现聚集成簇的现象。
算法:
- 在cpu上计算一个草丛平移矢量
- 为顶点shader把平移矢量设置为一个常量
- 为该单个草丛执行一个drawcal
- 调用顶点shader,把平移矢量加到上面顶点的位置
2)每顶点的动画(Animation per Vertex)
为了减少绘图调用,我们需要把动画计算移进顶点shader内,shader能够相对于它的位置分别的移动每个顶点。如下图所示:
因为对每个顶点的移动是分别计算的,各顶点移动的距离不再是常数,所以可见的变形会出现,但是通常这些失真不易觉察。
优点:
- drawcall很少,甚至仅仅1个
- 在顶点的shader中改变顶点位置,产生连续的风吹草地引起的波动荡漾
- 不会看出个别的草丛。
缺点:
- 出现变形
- 由于缺少了局部的无序,动画可能显得过于均匀
- 动画计算的复杂性受到限制
算法:
- 为顶点shader设定常量,例如风的基本强度和方向,时间延续性等。
- 为完整的草地或大面积的草场执行一次draw call
- 调用顶点shader,在shader中计算顶点位置的动画
3)每草体的动画(Animation per Grass Object)
吸取前两个方法的各自优点,我们可以计算动画不是基于每个顶点的位置,而是基于草体的中心位置。因为附近的草体现在有不同的动画,我们能表现那种要求的局部混乱,每个草体内的顶点移动相同,又避免了变形。为了做到这一点,每个顶点必须知道它所在草体的中心位置。因为顶点shader必须读取这个值,所以这个信息所需要的草体位置矢量必须在顶点格式中。
优点:
- drawcall很少,甚至仅仅1个
- 没有变形
- 局部多变,画面更自然
缺点:
- 因为每个顶点也包含它的草体的中心位置值,所以在顶点格式中需要附加数据
- 动画计算的复杂性受到限制
算法:
- 为顶点shader设定常量,例如风的基本强度和方向,时间延续性等。
- 为完整的草地或大面积的草场执行一次draw call
- 调用顶点shader,以草体的中心位置为基础在shader中计算顶点位置的动画
【核心要点总结】
1)草的纹理,应选取一簇一簇聚集丛生的草。在透明的alpha通道上画实体草茎。在彩色通道中,用深浅不同的绿色和黄色,区别各个单独的叶片。
2)草体的渲染,适合进行交叉排布,从后向前进行排序,使用alpha混合,并启用Draw
Call中的z-testing/writing,便能得到自然而茂密的草地渲染效果。
3)草地的动画,以三角函数(尤其是正弦和余弦)为基础,且应该考虑到移动的位置和当前时间、风向和强度。实现起来有三种方法:
- 每草丛草体的动画(Animation per Cluster of Grass Objects)
- 每顶点的动画(Animation per Vertex)
- 每草体的动画(Animation per Grass Object)