GLSL 效果示例
可交互水波:点击水面,让多圈波纹相遇
点击两处,波纹叠加、相消并逐渐平息。
在线示例
修改右侧代码,左侧预览会实时更新。
观察什么
点击两处,波纹叠加、相消并逐渐平息。
实现原理
R/G 两字节存当前高度,B/A 两字节存上一时刻高度;四邻域拉普拉斯推进离散波动方程。点击施加扰动,每个高度编码为 16 位,以减轻小波量化误差。
找到控制效果的代码
float unpackHeight(vec2 bytes){return ((bytes.x*255.0*256.0+bytes.y*255.0)/65535.0-0.5)*2.0;}
vec2 px=1./u_resolution;float dx=unpackHeight(texture2D(u_water,uv+vec2(px.x,0)).rg)-unpackHeight(texture2D(u_water,uv-vec2(px.x,0)).rg);float dy=unpackHeight(texture2D(u_water,uv+vec2(0,px.y)).rg)-unpackHeight(texture2D(u_water,uv-vec2(0,px.y)).rg);vec3 n=normalize(vec3(dx*30.,dy*30.,1.));c=vec3(.03,.25,.4)+max(dot(n,normalize(vec3(.5,.8,1.))),0.)*.4;
u_water 把当前高度打包到 R/G,上一高度打包到 B/A,因此原始颜色是编码数据。在 Fragment 中使用 c=vec3(unpackHeight(texture2D(u_water,uv).rg)*.5+.5),可将高度显示为灰度,而非带光照的法线效果。
动手修改
在 u_water 中把 (2.*h-prev+lap*.24)*.99 的阻尼系数从 .99 降到 .97。运行时点击水面,波纹会更快衰减,而拉普拉斯系数与传播规则仍保持原值。
调试与成本
u_water 读取中心与四个邻居,显示阶段再读四个高度来求法线。在 Fragment 中把 dx*30.、dy*30. 都改成 *15.,光照起伏会变平,但保存的波高不会改变。