Using Vertex Texture Displacement for Realistic Water Rendering(下)

Using Vertex Texture Displacement for Realistic Water Rendering(下)

作者: Yuri Kryachko

本文版权归原作者所有,仅供个人学习使用,请勿转载,勿用于任何商业用途。
由于本人水平有限,难免出错,不清楚的地方请大家以原著为准。也欢迎大家和我多多交流。
翻译:clayman
Blog:http://blog.csdn.net/soilwork

使用Branching避免不需要的计算

         即使优化了纹理拾取方式,渲染水面时的纹理拾取次数还是很高,将严重影响性能。虽然我们能减少需要渲染的顶点数量,但这会影响视觉效果,并且带来锯齿。

         由于我们渲染了大片的水面,因此有些三角形有可能一直延伸到了屏幕之外。但即使是这些三角形,顶点程序仍然对他们进行了渲染,浪费了宝贵的计算资源。如果我们渲染时跳过那些摄像机视见体(frustum)之外的三角形,则可以节省许多计算量。

         由于顶点程序同一时刻只能处理一个顶点,无法访问拓扑信息,因此,我们只能在顶点层次进行优化,而无法在三角形层次优化。虽然,当三角形中的某些顶点被挑过了,而其他顶点没有时,可能出会一些问题。但是在实践中,我们发现,如果三角形以及顶点纹理置换的位置足够小时,这种效果就不太明显。

         下面的伪代码描述了这个思想:

float4 ClipPos = mul ( ModelViewProj, INP)

float3 b0 = abs(ClipPos.xyz) < (ClipPos.www * C0 + C 1) ;

if ( all (b0))

{

         // vertex belongs to visible triangle,

         //perform texture sampling and displace vertex accordingly

}

         这段伪代码里,我们使用裁减空间的顶点纹理来判断当前顶点是否在视见体之内,之后,对于所需要的顶点,再进行余下复杂的计算操作。

         这里C0C1是特殊的裁减常量,控制了三角形延伸出摄像机视见体多少距离将会触发裁减。这样,就能避免由于裁减了那些顶点在视见体外,但三角形还在视见体内的顶点,而导致的问题。出于效率的考虑,我们的“裁剪”视见体只需比摄像机视见体稍微宽一点就可以了,以保证延屏幕边缘有一定的“安全区域(guard-band)”。因为我们的水体表面镶嵌良好,同时顶点纹理置换也很合理,所以这个简单的方法在实践中效果很好。

 

使用渲染到纹理(Using Render-to-Texture

         可以先使用一个单独的pass,把多张高度图混合为一张浮点纹理,从而进一步提高程序的速度。这样就不必在vertex shader中多次执行昂贵的拾取操作。此外,使用高度压缩的16bit浮点纹理格式储存原来的高度图。另外,使用3D纹理,我们还可以储存一系列的高度图动画序列帧(a sequence of animated height maps),让水面动画更加平滑。

         使用这种优化,需要把渲染循环分为两个pass

1. 用一个单独的pixel shader把多张高度图混合为一张32bit的浮点纹理。这张纹理中的象素元对应了放射状mesh中的顶点。

2. 使用前面描述的方法,置换顶点位置。

 

Back Sides of Waves

         由于在pixar shader中进行的光照计算假设水面是平坦(flat),因此在某些特定的情况下,这种近似会导致一些问题。

         如下图所示,即使背对着观察者的波纹,也会被看到,而实际上,这些波应该是不可见的。这种效果将会对波峰较亮部分产生影响。

Using Vertex Texture Displacement for Realistic Water Rendering(下)_第1张图片

         为了减轻这种效果,需要对用于光照计算的法线进行调整,让它朝观察者的方向“倾斜(tileing)”一点,这样,他们就会靠近波纹的前面。 可以在源码中找到具体代码。以下是使用本章所介绍的技术,渲染的一张水面效果图。

 

1.2.5 渲染局部波纹扰动(Rendering Local Perturbations

         有时候,需要渲染由于物体漂浮或者落入水中,所引起的局部波纹扰动。特别是对游戏来说,这是很有用的,我们通常需要产生爆炸效果,船航行时的轨迹,等等。对基于高度图的水面模型来说,很难引入物理上正确的扰动实现方法,我们将讨论一种简单的方法。

 

形变模型分析(Analytical Deformation Model

         实现局部波纹的扰动,最简单的方法就是根据分析结果,再次改变置换之后的顶点位置,在vertex shader中把重新计算的顶点位置和置换之后的位置进行加和。例如,对于爆炸效果来说,可以使用以下公式:

         这里,r表示水平面上的点到爆炸中心的距离,b是抽样常量(decimation constant)。I0wk的值则根据给定的爆炸参数来确定。

         至于渲染,同样可以使用前面渲染水面时,所用的放射状网格,但网格的中心必须是爆炸点。

 

动态置换贴图(Dynamic Displacement Mapping

         另一种选择是,把局部产生的偏移值直接渲染到顶点纹理中,实际上就是在GPU上实现通用编程(general-purose programming on the GPU)(GPGPU)的方法。使用这种方法,先在第一个pass中产生一张顶点纹理,随后的pass中用它来进行实际渲染。对高度图进行过滤,在pixel shader中,再把所有波形加和到一起,可以大大减少vertex shader的工作量。

         为了计算偏移值,可以使用上面提到的分析模型,也可以使用一钟细胞自动机(cellular-automata)的方法,逐帧展开(evolving)局部偏移。沿着一定的方向对纹理进行模糊处理,还可以实现风吹过水面的效果。

         但是,对于大小为 1km ,分辨率为 50cm 的水面来说,意味着纹理尺寸为2048x2048,这将给纹理内存和shader的执行速度都带来极大压力。此外,想要快速改变观察点也很成问题。

         然而,我们仍然鼓励读者去尝试一下这些方法。

 

泡沫生成Foam Generation

         在波涛汹涌的水面上,我们可以生成一些泡沫来进一步增加真实感。最简单的方法就是对于高度超过值H0的顶点,使用一张预处理过的泡沫纹理进行混合。根据以下公式来计算泡沫的透明度:

         Hmax表示可能出现泡沫的最高位置,H0为基准高度,H表示当前高度。

         泡沫纹理可以是动态的,以表现泡沫的生成和消失。这些动画纹理序列可以由艺术家手动创建,也可以用纹理生成。

 

1.3 结论

        

 

~~~~~~~~~~~~~~~~~~~~~~~~·全文完~~~~~~~~~~~~~~~·~~~~~~

 

译注:

         原文和完整代码都可以在NVIDIA的网站下载:原文 代码

         另外还可以参考NVIDIA SDK中的示例程序Vertex Texture Fetch Water

你可能感兴趣的:(优化,float,GPGPU,shader,generation,网格)