暴米花 发表于 2006-12-7 10:36:00

Using Vertex Texture Displacement for Realistic Water Render

<strong><br/><br/></strong>此教程版权原作者所有,仅供个人学习使用,请勿转载,勿用于任何商业用途。<br/>由于本人水平有限,难免出错,不清楚的地方请大家以原著为准。也欢迎大家和我多多交流。<br/>翻译:clayman<br/>Blog:<a href="http://blog.csdn.net/soilwork" target="_blank">http://blog.csdn.net/soilwork</a><br/>clayman_joe@yahoo.com.cn <p></p><p>使用Branching避免不需要的计算<br/>即使优化了纹理拾取方式,渲染水面时的纹理拾取次数还是很高,将严重影响性能。虽然我们能减少需要渲染的顶点数量,但这会影响视觉效果,并且带来锯齿。<br/>由于我们渲染了大片的水面,因此有些三角形有可能一直延伸到了屏幕之外。但即使是这些三角形,顶点程序仍然对他们进行了渲染,浪费了宝贵的计算资源。如果我们渲染时跳过那些摄像机视见体(frustum)之外的三角形,则可以节省许多计算量。<br/>由于顶点程序同一时刻只能处理一个顶点,无法访问拓扑信息,因此,我们只能在顶点层次进行优化,而无法在三角形层次优化。虽然,当三角形中的某些顶点被挑过了,而其他顶点没有时,可能出会一些问题。但是在实践中,我们发现,如果三角形以及顶点纹理置换的位置足够小时,这种效果就不太明显。<br/>下面的伪代码描述了这个思想:<br/>float4&nbsp;ClipPos&nbsp;=&nbsp;mul&nbsp;(&nbsp;ModelViewProj,&nbsp;INP)<br/>float3&nbsp;b0&nbsp;=&nbsp;abs(ClipPos.xyz)&nbsp;&lt;&nbsp;(ClipPos.www&nbsp;*&nbsp;C0&nbsp;+&nbsp;C&nbsp;1)&nbsp;;<br/>if&nbsp;(&nbsp;all&nbsp;(b0))<br/>{<br/>//&nbsp;vertex&nbsp;belongs&nbsp;to&nbsp;visible&nbsp;triangle,<br/>//perform&nbsp;texture&nbsp;sampling&nbsp;and&nbsp;displace&nbsp;vertex&nbsp;accordingly<br/>}<br/>这段伪代码里,我们使用裁减空间的顶点纹理来判断当前顶点是否在视见体之内,之后,对于所需要的顶点,再进行余下复杂的计算操作。<br/>这里C0和C1是特殊的裁减常量,控制了三角形延伸出摄像机视见体多少距离将会触发裁减。这样,就能避免由于裁减了那些顶点在视见体外,但三角形还在视见体内的顶点,而导致的问题。出于效率的考虑,我们的“裁剪”视见体只需比摄像机视见体稍微宽一点就可以了,以保证延屏幕边缘有一定的“安全区域(guard-band)”。因为我们的水体表面镶嵌良好,同时顶点纹理置换也很合理,所以这个简单的方法在实践中效果很好。</p><p>使用渲染到纹理(Using&nbsp;Render-to-Texture)<br/>可以先使用一个单独的pass,把多张高度图混合为一张浮点纹理,从而进一步提高程序的速度。这样就不必在vertex&nbsp;shader中多次执行昂贵的拾取操作。此外,使用高度压缩的16-bit浮点纹理格式储存原来的高度图。另外,使用3D纹理,我们还可以储存一系列的高度图动画序列帧(a&nbsp;sequence&nbsp;of&nbsp;animated&nbsp;height&nbsp;maps),让水面动画更加平滑。<br/>使用这种优化,需要把渲染循环分为两个pass:<br/>1.&nbsp;用一个单独的pixel&nbsp;shader把多张高度图混合为一张32-bit的浮点纹理。这张纹理中的象素元对应了放射状mesh中的顶点。<br/>2.&nbsp;使用前面描述的方法,置换顶点位置。</p><p>Back&nbsp;Sides&nbsp;of&nbsp;Waves<br/>由于在pixar&nbsp;shader中进行的光照计算假设水面是平坦(flat),因此在某些特定的情况下,这种近似会导致一些问题。<br/>如下图所示,即使背对着观察者的波纹,也会被看到,而实际上,这些波应该是不可见的。这种效果将会对波峰较亮部分产生影响。<br/>&nbsp;<img src="http://blog.csdn.net/images/blog_csdn_net/soilwork/BSoW.jpg" border="0" alt=""/><br/>为了减轻这种效果,需要对用于光照计算的法线进行调整,让它朝观察者的方向“倾斜(tileing)”一点,这样,他们就会靠近波纹的前面。&nbsp;可以在源码中找到具体代码。以下是使用本章所介绍的技术,渲染的一张水面效果图。<br/>&nbsp;<img src="http://blog.csdn.net/images/blog_csdn_net/soilwork/water%20face.jpg" border="0" alt=""/></p><p>1.2.5&nbsp;渲染局部波纹扰动(Rendering&nbsp;Local&nbsp;Perturbations)<br/>有时候,需要渲染由于物体漂浮或者落入水中,所引起的局部波纹扰动。特别是对游戏来说,这是很有用的,我们通常需要产生爆炸效果,船航行时的轨迹,等等。对基于高度图的水面模型来说,很难引入物理上正确的扰动实现方法,我们将讨论一种简单的方法。</p><p>形变模型分析(Analytical&nbsp;Deformation&nbsp;Model)<br/>实现局部波纹的扰动,最简单的方法就是根据分析结果,再次改变置换之后的顶点位置,在vertex&nbsp;shader中把重新计算的顶点位置和置换之后的位置进行加和。例如,对于爆炸效果来说,可以使用以下公式:<br/>&nbsp;<img src="http://blog.csdn.net/images/blog_csdn_net/soilwork/deform%20eqt.jpg" border="0" alt=""/><br/>这里,r表示水平面上的点到爆炸中心的距离,b是抽样常量(decimation&nbsp;constant)。I0、w和k的值则根据给定的爆炸参数来确定。<br/>至于渲染,同样可以使用前面渲染水面时,所用的放射状网格,但网格的中心必须是爆炸点。</p><p>动态置换贴图(Dynamic&nbsp;Displacement&nbsp;Mapping)<br/>另一种选择是,把局部产生的偏移值直接渲染到顶点纹理中,实际上就是在GPU上实现通用编程(general-purose&nbsp;programming&nbsp;on&nbsp;the&nbsp;GPU)(GPGPU)的方法。使用这种方法,先在第一个pass中产生一张顶点纹理,随后的pass中用它来进行实际渲染。对高度图进行过滤,在pixel&nbsp;shader中,再把所有波形加和到一起,可以大大减少vertex&nbsp;shader的工作量。<br/>为了计算偏移值,可以使用上面提到的分析模型,也可以使用一钟细胞自动机(cellular-automata)的方法,逐帧展开(evolving)局部偏移。沿着一定的方向对纹理进行模糊处理,还可以实现风吹过水面的效果。<br/>但是,对于大小为1km,分辨率为50cm的水面来说,意味着纹理尺寸为2048x2048,这将给纹理内存和shader的执行速度都带来极大压力。此外,想要快速改变观察点也很成问题。<br/>然而,我们仍然鼓励读者去尝试一下这些方法。</p><p>泡沫生成(Foam&nbsp;Generation)<br/>在波涛汹涌的水面上,我们可以生成一些泡沫来进一步增加真实感。最简单的方法就是对于高度超过值H0的顶点,使用一张预处理过的泡沫纹理进行混合。根据以下公式来计算泡沫的透明度:<br/>&nbsp;<img src="http://blog.csdn.net/images/blog_csdn_net/soilwork/foam.jpg" border="0" alt=""/><br/>Hmax表示可能出现泡沫的最高位置,H0为基准高度,H表示当前高度。<br/>泡沫纹理可以是动态的,以表现泡沫的生成和消失。这些动画纹理序列可以由艺术家手动创建,也可以用纹理生成。</p><p>1.3&nbsp;结论<br/>略</p><p>~~~~~~~~~~~~~~~~~~~·全文完~~~~~~~~~~~~~~~~~~~</p>
页: [1]
查看完整版本: Using Vertex Texture Displacement for Realistic Water Render