用shader实现流动的水面(webgl)

这段时间一直在看如何用shader绘制一个流动的水面,直接用贴图(高度图、法向贴图)实现的方法,这里就不讨论了。

搜了一大波博客资料,感觉存在如下一些问题

1??大多数资料都是基于opengl实现(或者是unity里的shader),过多关注点在渲染上面而不是水波的mesh实现上,让人没有看下去的欲望

2??有的就直接是照搬别人的博客,公式大段大段地搬,却没有自己的一丝见解,太过敷衍

3??代码不加注释,对前来学习者不太友好

4??针对webgl的实现,网上的资料太少(虽然有了opengl的实现就已经足够了,奈何伸手党太多)

所以在查阅了资料之后,决定写一个webgl版本的实现(three.js + shader)

nvidia官方提供的水波实现方程(其实网上大多数博客里的方程式应该都是源于此处):传送门

-------------------------------------------------------------------华丽的分割线-------------------------------------------------------------------------

一、PlaneGeometry + ShaderMaterial + 正弦波方程式

//1.PlaneGeometry
    this.seaMaterial = new THREE.ShaderMaterial({
      uniforms: { 
        time:{type:‘f‘,value:0},
      },
      vertexShader: seashader.vs,
      fragmentShader: seashader.fs,
      side:THREE.DoubleSide,
      wireframe: true
    });
    this.geometry = new THREE.PlaneGeometry( 500,500,100,20);
    var plane = new THREE.Mesh( this.geometry, this.seaMaterial );
    plane.rotation.x= -Math.PI/2;
    this.scene.add( plane );
const seashader = {
    vs:`
        uniform float time;

        void main(){
            float x = position.x;
            float y = position.y;
            float PI = 3.141592653589;

            float sz = 0.0;
            float ti = 0.06;
            //四条正弦波相加
            for(int i = 0;i<4;i++){
                ti = ti + 0.0005;
                vec2 dir = vec2(1.0,ti);//水波方向
                float l1 = 2.0 * PI / (0.5);//波长
                float s1 = 10.0 * 2.0 / l1;//速度
                float z1 = 1. * sin(dot(normalize(dir),vec2(x,y)) * l1 + time * s1);//正弦波方程式
                sz +=z1;
            }
            gl_Position = projectionMatrix * modelViewMatrix * vec4(x,y,sin(sz) * 10.0,1.0);
        }
    `,
    fs:`
        void main(){
            gl_FragColor = vec4(90./255.,160./255.,248./255.,1.0);      
        }
    `,
}
//animate的时候,shader的time参数递增
if(this.seaMaterial){
    this.seaMaterial.uniforms.time.value += 0.01;
}

参考的水波方程式:

用shader实现流动的水面(webgl)

效果如下:

用shader实现流动的水面(webgl)

温馨提示:

调参很重要,水波方向、波长、波的叠加数量,如果取值不当,生成的波将会很诡异(和plane尺寸以及分割的分数有关,因为这些参数将会直接影响vs接收的顶点坐标)。

二、Gerstner波方程式

接下来只贴shader部分

相关推荐