Demo地址:http://www.ibiblio.org/e-notes/webgl/gpu/flat_wave.htm,源码自己扒
效果就像是从上往下俯瞰水面中的涟漪。
实现这种效果用到了数学物理方程的一些概念,如有需要,推荐阅读梁昆淼所编写的《数学物理方法(第四版)》。
计算机可以通过计算一些特定点的方程来计算水面的波动效果。例如下图的Gerstner Wave,点的运动符合某个方程。
在本章的2d水波中,这些点使用的方程为如下公式。每个点的颜色与这个点的xy坐标以及时间t有关,式子中的(r - r0)^2当然就算某一点到原点距离的平方啦。
这是海洋科学中使用了基于经验的统计学模型。
编写程序时,不必每次都计算一遍这个方程,可以根据上次计算的结果与这次计算的结果来计算下一次的结果。
程序103行给出了具体的计算方式。虽然每个像素都有RGBA四个通道,但现在只需要将初步计算的结果放在r通道中。
var n1 = n-1, h = 1/n1, t = 0;
pix = new Float32Array(4*n*n);
for(var i = 0; i<n; i++)
for(var j = 0; j<n; j++){
var x = h*(j-n/2), y = h*(i-n/2);
pix[t++] = 50*Math.exp(-5000*(x*x + y*y));
pix[t++] = 0; pix[t++] = 0; pix[t++] = 0;
}
在第一个片元着色器计算偏微分方程。
<script id="shader-fs" type="x-shader/x-fragment">
precision highp float;
uniform sampler2D samp;
uniform sampler2D samp1;
varying vec2 vTexCoord;
const float d = 1./512., dth2 = .2;
void main(void) {
float u = texture2D(samp, vTexCoord).r;
float u1 = texture2D(samp1, vTexCoord).r;
u = 2.*u1 - u +
(texture2D(samp1, vec2(vTexCoord.x, vTexCoord.y + d) ).r +
texture2D(samp1, vec2(vTexCoord.x, vTexCoord.y - d) ).r +
texture2D(samp1, vec2(vTexCoord.x + d, vTexCoord.y) ).r +
texture2D(samp1, vec2(vTexCoord.x - d, vTexCoord.y) ).r +
- 4.*u1)*dth2;
gl_FragColor = vec4(u, 0., 0., 0. );
}
</script>
第二个片元着色器将结果打印到屏幕上
<script id="shader-fs-show" type="x-shader/x-fragment">
precision highp float;
uniform sampler2D samp;
varying vec2 vTexCoord;
void main(void) {
float c = texture2D(samp, vTexCoord).r;
if (c < 0.) gl_FragColor = vec4(0., 0., -c, 1.);
else gl_FragColor = vec4(c, 0., 0., 1.);
}
</script>