美文网首页
2022-10-18 实现有倒影的水

2022-10-18 实现有倒影的水

作者: MrSwilder | 来源:发表于2022-10-18 11:37 被阅读0次

一、原理
1.实现环境贴图和漫反射
2.利用法线贴图对环境贴图进行干扰,让环境贴图有扭曲的效果
3.利用环境贴图代替漫反射的基础色
二、效果


20221018_113415 (1).gif

三、代码

 //顶点着色器
    var skyBox_VS = /*glsl*/ `
      attribute vec4 a_Position;
      uniform mat4 u_ModelMatrix; 
      uniform mat4 u_ViewMatrix; 
      uniform mat4 u_ProjectMatrix; 
    
      varying vec3 v_Position;
      void main(){
        mat4 relativeViewMatrix=u_ViewMatrix;
        relativeViewMatrix[3].x=0.0; 
        relativeViewMatrix[3].y=0.0; 
        relativeViewMatrix[3].z=0.0; 
        vec4 clipPosition=u_ProjectMatrix*relativeViewMatrix*u_ModelMatrix * a_Position;
      
    
         gl_Position =clipPosition;
         v_Position=a_Position.rgb;

      }`;

    //片元着色器
    var skyBox_FS = /*glsl*/ `
      #ifdef GL_ES
      precision mediump float;
      #endif
     
      uniform samplerCube u_CubeMapTexture;
       uniform vec3 u_AmbitionColor;
      varying vec3 v_Position;


      void main(){
        gl_FragColor=textureCube(u_CubeMapTexture, v_Position);

      }`;

    var v_shader =/*glsl*/`
    attribute vec4 a_Position;
        attribute vec2 a_Uv;
        attribute vec3 a_Normal;

       uniform mat4 u_ModelMatrix; 
      uniform mat4 u_ViewMatrix; 
      uniform mat4 u_ProjectMatrix; 
      uniform mat4 u_NormalMatrix;
      varying vec2 v_Uv;
      varying vec3 v_Normal;
      varying vec3 v_Position;
      varying mat3 v_TBN;
      void main(){
        gl_Position=u_ProjectMatrix*u_ViewMatrix*u_ModelMatrix*a_Position;
        v_Uv=a_Uv;
        v_Normal=(u_NormalMatrix*vec4(a_Normal,1.0)).xyz;
        v_Position=(u_ModelMatrix*a_Position).xyz;

       
        vec3 tanVec=normalize((u_ModelMatrix*vec4(1.0,0.0,0.0,1.0)).xyz);
        vec3 bitTan=normalize(cross(tanVec,v_Normal));
        v_TBN=mat3(tanVec,bitTan,normalize(v_Normal));
      }
    `

    var f_shader =/*glsl*/`
     #ifdef GL_ES
      precision mediump float;
      #endif
        varying vec2 v_Uv;
         varying vec3 v_Normal;
         varying vec3 v_Position;
        uniform sampler2D u_Texture;
        uniform vec3 u_ViewPosition;
         uniform samplerCube u_CubeMapTexture;
         uniform float u_Number;
         varying mat3 v_TBN;

        void main(){

              vec3 lightdir=vec3(1.0,-1.0,0.0);
            // vec3 lightColor=vec3(19.0/255.0,133.0/255.0,53.0/255.0);
            vec3 lightColor=vec3(1.0);
         

            //获取切线空间法线
            vec4 normalColor1=texture2D(u_Texture,vec2(v_Uv.x,3.0*fract(u_Number)+v_Uv.y));
            vec4 normalColor2=texture2D(u_Texture,vec2(v_Uv.x,2.0*fract(u_Number)+v_Uv.y));
             vec4 normalColor=mix(normalColor1,normalColor2,0.5);
            //转化为-1到1
            vec3 normal=normalize(normalColor.rgb*2.0-1.0);
            vec3 worldNormal=normalize(v_TBN*normal);

            //计算反射向量
            vec3 viewDir=normalize(v_Position-u_ViewPosition);

             float dotL=max(0.0,dot(normalize(-lightdir),worldNormal));

            //调整法线,让法线贴图对环境纹理影像有限
            worldNormal=mix(worldNormal,v_Normal,0.99);
            // worldNormal=vec3(0.0,0.0,1.0);
            //计算反射颜色
            vec3 reflectDir=reflect(viewDir,worldNormal);
            vec3 reflectColor=textureCube(u_CubeMapTexture,reflectDir).rgb;

            //计算折射颜色
            vec3 refractDir=refract(viewDir,worldNormal,1.0/1.55);
            vec3 refractColor=textureCube(u_CubeMapTexture,refractDir).rgb;

           

            // vec3 baseColor=vec3(0.0/255.0,112.0/255.0,192.0/255.0);
          vec3 envColor=mix(reflectColor,refractColor,0.3);
            //计算漫反射
          
            vec3 diffcuseColor=lightColor*dotL*envColor;
               

          
            gl_FragColor=vec4(diffcuseColor,0.8);
            // gl_FragColor=vec4(envColor,1.0);
        }

    `


    //声明js需要的相关变量
    var canvas = document.getElementById("canvas");
    var gl = getWebGLContext(canvas);
    var boxProgram;
    var skyboxProgram
    var planeModelMatrix;
    var frameNumber = 0
    async function main() {
        if (!gl) {
            console.log("你的浏览器不支持WebGL");
            return;
        }

        skyboxProgram = createProgram(gl, skyBox_VS, skyBox_FS);
        if (!skyboxProgram) {
            console.warn("创建程序失败!");
            return;
        }

        boxProgram = createProgram(gl, v_shader, f_shader)
        if (!boxProgram) {
            console.warn("创建立方体程序失败!");
            return;
        }



        //设置透视投影矩阵
        var projMatrix = new Matrix4();
        projMatrix.setPerspective(30, canvas.width / canvas.height, 0.1, 100);

        //设置视角矩阵的相关信息(视点,视线,上方向)
        var viewMatrix = new Matrix4();
        viewMatrix.setLookAt(0, 1.5, 6, 0, 0, 0, 0, 1, 0);

        planeModelMatrix = new Matrix4()
        planeModelMatrix.setScale(2, 1, 2)


        //开启隐藏面清除
        gl.enable(gl.DEPTH_TEST);
        // gl.enable(gl.CULL_FACE)



        gl.program = skyboxProgram;
        gl.useProgram(skyboxProgram);
        //获取内置变量的信息
        getVariableLocation();

        const cube = createCube(gl);


        await initCubeTexture(
            [
                "./image/skybox1/posx.jpg",
                "./image/skybox1/negx.jpg",
                "./image/skybox1/posy.jpg",
                "./image/skybox1/negy.jpg",

                "./image/skybox1/posz.jpg",
                "./image/skybox1/negz.jpg",
            ]
        )


        // await initCubeTexture(
        //     [
        //         "./image/skybox/right.jpg",
        //         "./image/skybox/left.jpg",
        //         "./image/skybox/top.jpg",
        //         "./image/skybox/bottom.jpg",

        //         "./image/skybox/front.jpg",
        //         "./image/skybox/back.jpg",
        //     ]
        // )



        gl.useProgram(boxProgram)
        gl.program = boxProgram

        //获取内置变量的信息
        getVariableLocation();
        const plane = createPlane(gl);

        //初始化纹理
        await initTexture(gl, "./image/waterNormals.jpg", 1);





        // await draw(projMatrix, viewMatrix, cube, plane)
        //设置底色


        // gl.depthFunc(gl.LEQUAL);
        //根据时间绘制
        var tick = function () {
            frameNumber += 0.001
            draw(projMatrix, viewMatrix, cube, plane)

            //重复请求
            requestAnimationFrame(tick)
        }
        tick()

        document.addEventListener("keydown", (e) => {

            if (e.key === "ArrowUp") {
                planeModelMatrix.rotate(1, 1, 0, 0)
            } else if (e.key === "ArrowDown") {
                planeModelMatrix.rotate(-1, 1, 0, 0)
            } else if (e.key === "ArrowLeft") {
                planeModelMatrix.rotate(-1, 0, 1, 0)
            } else if (e.key === "ArrowRight") {
                planeModelMatrix.rotate(1, 0, 1, 0)
            }


        });




    }

    function draw(projMatrix, viewMatrix, cube, plane) {
        //清空颜色和深度缓冲区
        gl.clearColor(0.0, 0.0, 0.0, 1.0);
        gl.clear(gl.COLOR_BUFFER_BIT | gl.DEPTH_BUFFER_BIT);

        gl.depthMask(false);
        gl.useProgram(skyboxProgram)
        gl.program = skyboxProgram


        //绘制三角形
        drawSkyBox(projMatrix, viewMatrix, cube);
        gl.depthMask(true);
        gl.useProgram(boxProgram)
        gl.program = boxProgram



        drawBox(projMatrix, viewMatrix, plane)


    }





    function drawSkyBox(projMatrix, viewMatrix, cube) {
        const program = gl.program;
        //设置视角矩阵的相关信息(视点,视线,上方向)






        //将试图矩阵传给u_ViewMatrix变量
        gl.uniformMatrix4fv(program.projectMatrix, false, projMatrix.elements);


        //设置模型矩阵的相关信息
        var modelMatrix = new Matrix4();
        gl.uniformMatrix4fv(program.modelMatrix, false, modelMatrix.elements);


        gl.uniformMatrix4fv(program.viewMatrix, false, viewMatrix.elements);


        const arrayBuffers = cube.arrayBuffers

        //写入缓冲区
        arrayBuffers.forEach(arrayBuffer => {
            if (arrayBuffer) {
                writeAttributeVariable(gl, arrayBuffer.attribute, arrayBuffer)
            }
        });


        gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, cube.indexBuffer);

        //绘制图形
        gl.drawElements(gl.TRIANGLES, cube.length, gl.UNSIGNED_BYTE, 0);

        gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, null);
    }


    function drawBox(projMatrix, viewMatrix, plane) {
        const program = gl.program;



        //设置模型矩阵的相关信息
        // var modelMatrix = new Matrix4();
        gl.uniformMatrix4fv(program.modelMatrix, false, planeModelMatrix.elements);


        gl.uniformMatrix4fv(program.viewMatrix, false, viewMatrix.elements);


        //设置透视投影矩阵
        var projMatrix = new Matrix4();
        projMatrix.setPerspective(30, canvas.width / canvas.height, 0.1, 100);
        //将试图矩阵传给u_ViewMatrix变量
        gl.uniformMatrix4fv(program.projectMatrix, false, projMatrix.elements);


        //传入眼睛位置
        const viewPosition = gl.getUniformLocation(program, 'u_ViewPosition')

        gl.uniform3fv(viewPosition, [0, 1.5, 6]);


        const number = gl.getUniformLocation(program, "u_Number");
        gl.uniform1f(number, frameNumber);


        var normalMatrix = new Matrix4()

        normalMatrix.transpose(normalMatrix.setInverseOf(planeModelMatrix))
        gl.uniformMatrix4fv(program.normalMatrix, false, normalMatrix.elements);


        const arrayBuffers = plane.arrayBuffers
        arrayBuffers.forEach(arrayBuffer => {
            if (arrayBuffer) {
                writeAttributeVariable(gl, arrayBuffer.attribute, arrayBuffer)
            }
        });


        gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, plane.indexBuffer);
        //绘制图形
        gl.drawElements(gl.TRIANGLES, plane.length, gl.UNSIGNED_BYTE, 0);
        gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, null);
    }```

相关文章

网友评论

      本文标题:2022-10-18 实现有倒影的水

      本文链接:https://www.haomeiwen.com/subject/eobjzrtx.html