关于一般水体渲染的技术总结

水体渲染一半的技术节点在于波纹、水体边缘与折射。

波纹笔者现已知的方法有 凹凸纹理贴图、正弦波、FFT这三种,其中最为简单的是纹理贴图只要对其法线进行采样,然后制作UV动画,在制作UV动画的时候,有一个小trick,同一张Normal图可以采样两次,然后分别做主动与扰动。其次是正弦波,正弦波更多的是进行顶点动画,改变定点数据的值来得到,一般的伪代码为 WaveValue = Sin(_Time.y*_Speed+v.vertex.x*_Frequency)*_Amplitude.。期间可以叠加一些常见的sin波或者cos波来进行扰动,他的特点是平滑圆润,适合表达像池塘一样平静的水面。而正弦波的进化版则是Gerstner波,Gerstner波是将水平位置进行挤压,使得波峰变尖,波谷变宽,适合模拟海洋,该公式在《GPU Gems 1》出现过

Gerstner公式

而FTT海洋则是我接下来要研究的对象。之后会另出一篇文章来详解。

水体边缘检测,也就是海浪。海浪我之前有做过两种,一种是描出水体与山体的接触边缘,利用通道区分海浪与海面,相当于做一个mask然后再mask上进行叠加noise图造成扰动效果。另外一种是用深度检测,直接检测出边缘,类似边缘检测的方法。顺带边缘检测一般有几种方法,最基础的方法是用Sobel算子对屏幕图像进行边缘检测,但这种方法会得到许多不希望得到的边缘线而且挺受光源的影响。还有一种卷积检测的方法是Roberts算子,本质就是计算左上角核右下角的差值,乘上右上角和左下角的插值,作为评估依据。取对角方向的深度或者法线值,比较他们之间的插值,如果超过某个阈值,就认为有一条边。而Sobel检测算子是利用相邻像素之间的差值用梯度表示,梯度的绝对值越大,则越有可能是边缘处。这种方法叫做基于图像处理的轮廓渲染。无论怎么改变算子还是其他的,这种方法的劣势是一些深度和法线变化很小的轮廓无法被检出,其他的算法还有

1.基于观察角度和表面法线的轮廓线渲染;这种方法是用视角方向和表面法线的点乘结果得到轮廓信息。可以在一个PASS中得到渲染结果,但局限性很大。

2.过程式几何轮廓渲染;这种方法的核心是用两个PASS渲染,一个剔除正面渲染背面然后沿着法线向外拓展形成轮廓线,还有一个PASS就正常渲染。

3.基于轮廓边检测的轮廓线渲染,这个方法,我们只需要检查和这条边相邻的两个三角面片是否满足 (n0·v>0)≠(n1·v>0),n0与n1分别表示两个相邻三角面片的法向,v是从视角到该边上任意一个顶点的方向。这个条件主要是检车两个相邻的三角面片是否一个正面一个背面。我们可以在几何着色器中完成这个操作,缺点是实现复杂,而且会出现动画连贯性的问题,由于逐帧单独提取轮廓,所以在帧与帧之间会出现条约性。

之前所作的海浪则是通过深度图,需要在摄像机开启深度渲染,基本思路是用摄像机距离地形的距离减去摄像机距离平面的距离,取绝对值,越接近0则越可能是边缘。但有些低端设备不支持深度图渲染,所以用的时候要比较慎用。而且在开启深度纹理的时候需要在FallBack设置为Diffuse才能够体现深度。

接下来是折射

WaterDepth=SceneDepth(Eye)-Screen Position

DepthFade
Movement
Water Color
Water Refraction
Foam
Combine_Color Output

发表回复

您的邮箱地址不会被公开。 必填项已用 * 标注