美文网首页
2021-12-21 webgl实现倒影效果

2021-12-21 webgl实现倒影效果

作者: MrSwilder | 来源:发表于2021-12-21 00:54 被阅读0次
    <!DOCTYPE html>
    <html lang="en">
    <head>
        <meta charset="UTF-8">
        <meta name="viewport"
              content="width=device-width, user-scalable=no, initial-scale=1.0, maximum-scale=1.0, minimum-scale=1.0">
        <meta http-equiv="X-UA-Compatible" content="ie=edge">
        <title>Title</title>
        <style>
            body {
                margin: 0;
                overflow: hidden;
            }
    
            #canvas {
                margin: 0;
                display: block;
            }
        </style>
    </head>
    <body onload="main()">
    <canvas id="canvas" height="800" width="800"></canvas>
    </body>
    <script src="/lib/webgl-utils.js"></script>
    <script src="/lib/webgl-debug.js"></script>
    <script src="/lib/cuon-utils.js"></script>
    <script src="/lib/cuon-matrix.js"></script>
    <script>
        //设置WebGL全屏显示
        var canvas = document.getElementById("canvas");
        canvas.width = window.innerWidth;
        canvas.height = window.innerHeight;
    
        //设置顶点着色器
        var vertexShaderSource = "" +
            "attribute vec4 a_Position;\n" +
            "attribute vec2 a_TexCoord;\n" +
            "uniform mat4 u_MvpMatrix;\n" +
            "varying vec2 v_TexCoord;\n" +
            "void main(){\n" +
            "   gl_Position = u_MvpMatrix * a_Position;\n" +
            "   v_TexCoord = a_TexCoord;\n" +
            "}\n";
    
        //设置片元着色器
        var fragmentShaderSource = "" +
            "#ifdef GL_ES\n" +
            "precision mediump float;\n" +
            "#endif\n" +
            "uniform sampler2D u_Sampler;\n" +
            "varying vec2 v_TexCoord;\n" +
            "void main(){\n" +
            "   gl_FragColor = texture2D(u_Sampler, v_TexCoord);\n" +
            "}\n";
    
        //中间平面图形的高和宽
        var offset_width = 512;
        var offset_height = 512;
    
        function main() {
            var canvas = document.getElementById("canvas");
    
            var gl = getWebGLContext(canvas);
    
            if(!gl){
                console.log("无法获取WebGL的上下文");
                return;
            }
    
            //创建并初始化着色器
            if(!initShaders(gl, vertexShaderSource, fragmentShaderSource)){
                console.log("无法初始化着色器");
                return;
            }
    
            //得到attribute变量和uniform变量的存储位置
            var program = gl.program;//获取到程序对象
            program.a_Position = gl.getAttribLocation(program, "a_Position");
            program.a_TexCoord = gl.getAttribLocation(program, "a_TexCoord");
            program.u_MvpMatrix = gl.getUniformLocation(program, "u_MvpMatrix");
            if(program.a_Position < 0 || program.a_TexCoord < 0 || !program.u_MvpMatrix){
                console.log("无法获取到变量的存储位置");
                return;
            }
    
            //设置顶点的位置信息
            var cube = initVertexBuffersForCube(gl);
            var plane = initVertexBuffersForPlane(gl);
    
            if(!cube || !plane){
                console.log("存入缓冲区数据失败");
                return;
            }
    
            //设置纹理
            var texture = initTextures(gl);
            if(!texture){
                console.log("无法创建纹理缓冲区");
                return;
            }
    
            //初始化帧缓冲区
            var fbo = initFramebufferObject(gl);
            if(!fbo){
                console.log("无法初始化帧缓冲区");
                return;
            }
    
            //开启隐藏面消除功能
            gl.enable(gl.DEPTH_TEST);
    
            //设置视图投影矩阵相关信息
            var viewProjectMatrix = new Matrix4();
            viewProjectMatrix.setPerspective(30.0, canvas.width/canvas.height, 1.0, 100.0);
            viewProjectMatrix.lookAt(0.0, 3.0, 5.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0);
    
            //设置帧缓冲区的视图投影矩阵
            var viewProjectMatrixFbo = new Matrix4();
            viewProjectMatrixFbo.setPerspective(30.0, offset_width/offset_height, 1.0, 100.0);
            viewProjectMatrixFbo.lookAt(0.0, -3.0, 5.0,0.0, 0.0, 0.0,0.0,1.0,0.0);
    
            //开始绘制
            var currentAngle = 0.0;
            function tick() {
                currentAngle = animate(currentAngle); //更新旋转角度
                draw(gl, canvas, fbo, plane, cube, currentAngle, texture, viewProjectMatrix, viewProjectMatrixFbo);
                requestAnimationFrame(tick);
            }
    
            tick();
        }
    
        function draw(gl, canvas, fbo, plane, cube, angle, texture, viewProjectMatrix, viewProjectMatrixFbo) {
            gl.bindFramebuffer(gl.FRAMEBUFFER, fbo); //更改绘图的目标为帧缓冲区
            gl.viewport(0,0,offset_width, offset_height); //对帧缓冲区设置视口
    
            gl.clearColor(0.2,0.2,0.4,1.0); //设置背景色
            gl.clear(gl.COLOR_BUFFER_BIT |  gl.DEPTH_BUFFER_BIT); //清除背景和隐藏面消除
    
            //绘制立方体
            drawTexturedCube(gl, gl.program, cube, angle, texture, viewProjectMatrixFbo,false);
    
            gl.bindFramebuffer(gl.FRAMEBUFFER, null); //将绘制的目标修改为颜色缓冲区
            gl.viewport(0,0,canvas.width, canvas.height); //将视口的大小设置为canvas的大小
    
            gl.clearColor(0.0,0.0,0.0,1.0);
            gl.clear(gl.COLOR_BUFFER_BIT | gl.DEPTH_BUFFER_BIT); //清除背景和隐藏面消除
    
            //绘制平面
            drawTexturedPlane(gl, gl.program, plane, 0.0, fbo.texture, viewProjectMatrix);
    
           
            
           
            drawTexturedCube(gl, gl.program, cube, angle, texture, viewProjectMatrix,true);
        }
    
        //声明坐标转换矩阵
    
        var g_mvpMatrix = new Matrix4();
    
        function drawTexturedPlane(gl, program, obj,  angle, texture, viewProjectMatrix) {
            var g_modelMatrix = new Matrix4();
            //计算模型矩阵
            // g_modelMatrix.setTranslate(0.0,0.0,1.0);
            //g_modelMatrix.setRotate(0.0,0.0,1.0,0.0);
            g_modelMatrix.rotate(angle, 0.0, 1.0, 0.0);
            //g_modelMatrix.translate(0.0,0.5,0.0)
            //计算模型视图投影矩阵,并赋值给u_MvpMatrix
            g_mvpMatrix.set(viewProjectMatrix);
            g_mvpMatrix.multiply(g_modelMatrix);
            gl.uniformMatrix4fv(program.u_MvpMatrix,  false, g_mvpMatrix.elements);
    
            drawTexturedObject(gl, program, obj, texture);
        }
    
        function drawTexturedCube(gl, program, obj, angle, texture, viewProjectMatrix,isTrans) {
            var g_modelMatrix = new Matrix4();
           
            //计算模型矩阵
            g_modelMatrix.setRotate(0.0,1.0,0.0,0.0);
            g_modelMatrix.rotate(angle, 0.0,1.0,0.0);
            g_modelMatrix.translate(0.0,1.0,0.0)
            g_modelMatrix.scale(0.5,0.5,0.5)
            if(!isTrans){
               
                
            }else{
                //g_modelMatrix.scale(0.5,0.5,0.5)
            }
            //计算模型视图投影矩阵,并赋值给u_mvpmatrix
            g_mvpMatrix.set(viewProjectMatrix);
            g_mvpMatrix.multiply(g_modelMatrix);
            gl.uniformMatrix4fv(program.u_MvpMatrix,false, g_mvpMatrix.elements);
    
            //绘制
            drawTexturedObject(gl, program, obj, texture);
        }
    
        function drawTexturedObject(gl, program, obj,  texture) {
            //分配缓冲区对象并启用赋值
            initAttributeVariable(gl, program.a_Position, obj.vertexBuffer); //顶点坐标
            initAttributeVariable(gl, program.a_TexCoord, obj.texCoordBuffer); //纹理坐标
    
            //将纹理对象绑定到目标
            gl.activeTexture(gl.TEXTURE0);
            gl.bindTexture(gl.TEXTURE_2D, texture);
    
            //绘制
            gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, obj.indexBuffer);
            gl.drawElements(gl.TRIANGLES, obj.numIndices, obj.indexBuffer.type, 0);
        }
    
        function initAttributeVariable(gl, a_attribute, buffer) {
            gl.bindBuffer(gl.ARRAY_BUFFER, buffer);
            gl.vertexAttribPointer(a_attribute, buffer.num, buffer.type, false, 0, 0);
            gl.enableVertexAttribArray(a_attribute);
        }
    
        var angle_step = 30;
        var last = +new Date();
        function animate(angle) {
            var now = +new Date();
            var elapsed = now - last;
            last = now;
            var newAngle = angle + (angle_step*elapsed)/1000.0;
            return newAngle%360;
        }
    
        function initFramebufferObject(gl) {
            var framebuffer, texture, depthBuffer;
    
            //定义错误函数
            function error() {
                if(framebuffer) gl.deleteFramebuffer(framebuffer);
                if(texture) gl.deleteFramebuffer(texture);
                if(depthBuffer) gl.deleteFramebuffer(depthBuffer);
                return null;
            }
    
            //创建帧缓冲区对象
            framebuffer = gl.createFramebuffer();
            if(!framebuffer){
                console.log("无法创建帧缓冲区对象");
                return error();
            }
    
            //创建纹理对象并设置其尺寸和参数
            texture = gl.createTexture();
            if(!texture){
                console.log("无法创建纹理对象");
                return error();
            }
    
            gl.bindTexture(gl.TEXTURE_2D, texture);
            gl.texImage2D(gl.TEXTURE_2D, 0, gl.RGBA, offset_width, offset_height, 0, gl.RGBA, gl.UNSIGNED_BYTE, null);
            gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, gl.LINEAR);
            framebuffer.texture = texture;//将纹理对象存入framebuffer
    
            //创建渲染缓冲区对象并设置其尺寸和参数
            depthBuffer = gl.createRenderbuffer();
            if(!depthBuffer){
                console.log("无法创建渲染缓冲区对象");
                return error();
            }
    
            gl.bindRenderbuffer(gl.RENDERBUFFER, depthBuffer);
            gl.renderbufferStorage(gl.RENDERBUFFER, gl.DEPTH_COMPONENT16, offset_width, offset_height);
    
            //将纹理和渲染缓冲区对象关联到帧缓冲区对象上
            gl.bindFramebuffer(gl.FRAMEBUFFER, framebuffer);
            gl.framebufferTexture2D(gl.FRAMEBUFFER, gl.COLOR_ATTACHMENT0, gl.TEXTURE_2D, texture, 0);
            gl.framebufferRenderbuffer(gl.FRAMEBUFFER, gl.DEPTH_ATTACHMENT, gl.RENDERBUFFER,depthBuffer);
    
            //检查帧缓冲区对象是否被正确设置
            var e = gl.checkFramebufferStatus(gl.FRAMEBUFFER);
            if(gl.FRAMEBUFFER_COMPLETE !== e){
                console.log("渲染缓冲区设置错误"+e.toString());
                return error();
            }
    
            //取消当前的focus对象
            gl.bindFramebuffer(gl.FRAMEBUFFER, null);
            gl.bindTexture(gl.TEXTURE_2D, null);
            gl.bindRenderbuffer(gl.RENDERBUFFER, null);
    
            return framebuffer;
        }
    
        function initTextures(gl) {
            var texture = gl.createTexture();
            if(!texture){
                console.log("无法创建纹理缓冲区");
                return null;
            }
    
            var u_Sampler = gl.getUniformLocation(gl.program, "u_Sampler");
            if(!u_Sampler){
                console.log("无法获取到缓冲区对象");
                return null;
            }
    
            var img = new Image();
    
            img.onload = function () {
                gl.pixelStorei(gl.UNPACK_FLIP_Y_WEBGL, 1);
                gl.bindTexture(gl.TEXTURE_2D, texture);
                gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, gl.LINEAR);
                gl.texImage2D(gl.TEXTURE_2D, 0, gl.RGBA, gl.RGBA, gl.UNSIGNED_BYTE, img);
    
                gl.uniform1i(u_Sampler, 0);
    
                gl.bindTexture(gl.TEXTURE_2D, null);
            };
    
            img.src = "/image/texture1.jpg";
    
            return texture;
        }
    
        function initVertexBuffersForPlane(gl) {
            // 创建一个面
            //  v1------v0
            //  |        |
            //  |        |
            //  |        |
            //  v2------v3
    
            // 顶点的坐标
            var vertices = new Float32Array([
                1.0, 0.0, 1.0,  -1.0, 0.0, 1.0,  -1.0,0.0, -1.0,   1.0,0.0, -1.0    // v0-v1-v2-v3
            ]);
    
            // 纹理的坐标
            var texCoords = new Float32Array([1.0, 1.0,   0.0, 1.0,   0.0, 0.0,   1.0, 0.0]);
    
            // 顶点的索引
            var indices = new Uint8Array([0, 1, 2,   0, 2, 3]);
    
            //将顶点的信息写入缓冲区对象
            var obj = {};
            obj.vertexBuffer = initArrayBufferForLaterUse(gl, vertices, 3, gl.FLOAT);
            obj.texCoordBuffer = initArrayBufferForLaterUse(gl, texCoords, 2, gl.FLOAT);
            obj.indexBuffer = initElementArrayBufferForLaterUse(gl, indices, gl.UNSIGNED_BYTE);
            if(!obj.vertexBuffer || !obj.texCoordBuffer || !obj.indexBuffer) return null;
    
            obj.numIndices = indices.length;
    
            gl.bindBuffer(gl.ARRAY_BUFFER, null);
            gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, null);
    
            return obj;
        }
    
        function initVertexBuffersForCube(gl) {
            // Create a cube
            //    v6----- v5
            //   /|      /|
            //  v1------v0|
            //  | |     | |
            //  | |v7---|-|v4
            //  |/      |/
            //  v2------v3
    
            // 顶点的数据坐标
            var vertices = new Float32Array([
                1.0, 1.0, 1.0,  -1.0, 1.0, 1.0,  -1.0,-1.0, 1.0,   1.0,-1.0, 1.0,    // v0-v1-v2-v3 front
                1.0, 1.0, 1.0,   1.0,-1.0, 1.0,   1.0,-1.0,-1.0,   1.0, 1.0,-1.0,    // v0-v3-v4-v5 right
                1.0, 1.0, 1.0,   1.0, 1.0,-1.0,  -1.0, 1.0,-1.0,  -1.0, 1.0, 1.0,    // v0-v5-v6-v1 up
                -1.0, 1.0, 1.0,  -1.0, 1.0,-1.0,  -1.0,-1.0,-1.0,  -1.0,-1.0, 1.0,    // v1-v6-v7-v2 left
                -1.0,-1.0,-1.0,   1.0,-1.0,-1.0,   1.0,-1.0, 1.0,  -1.0,-1.0, 1.0,    // v7-v4-v3-v2 down
                1.0,-1.0,-1.0,  -1.0,-1.0,-1.0,  -1.0, 1.0,-1.0,   1.0, 1.0,-1.0     // v4-v7-v6-v5 back
            ]);
    
            // 纹理的数据坐标
            var texCoords = new Float32Array([
                1.0, 1.0,   0.0, 1.0,   0.0, 0.0,   1.0, 0.0,    // v0-v1-v2-v3 front
                0.0, 1.0,   0.0, 0.0,   1.0, 0.0,   1.0, 1.0,    // v0-v3-v4-v5 right
                1.0, 0.0,   1.0, 1.0,   0.0, 1.0,   0.0, 0.0,    // v0-v5-v6-v1 up
                1.0, 1.0,   0.0, 1.0,   0.0, 0.0,   1.0, 0.0,    // v1-v6-v7-v2 left
                0.0, 0.0,   1.0, 0.0,   1.0, 1.0,   0.0, 1.0,    // v7-v4-v3-v2 down
                0.0, 0.0,   1.0, 0.0,   1.0, 1.0,   0.0, 1.0     // v4-v7-v6-v5 back
            ]);
    
            // 顶点的索引数据
            var indices = new Uint8Array([
                0, 1, 2,   0, 2, 3,    // front
                4, 5, 6,   4, 6, 7,    // right
                8, 9,10,   8,10,11,    // up
                12,13,14,  12,14,15,    // left
                16,17,18,  16,18,19,    // down
                20,21,22,  20,22,23     // back
            ]);
    
            //创建一个对象保存数据
            var obj = {};
    
            //将顶点信息写入缓冲区对象
            obj.vertexBuffer = initArrayBufferForLaterUse(gl, vertices, 3, gl.FLOAT);
            obj.texCoordBuffer = initArrayBufferForLaterUse(gl, texCoords, 2, gl.FLOAT);
            obj.indexBuffer = initElementArrayBufferForLaterUse(gl, indices, gl.UNSIGNED_BYTE);
            if(!obj.vertexBuffer || !obj.texCoordBuffer || !obj.indexBuffer) return null;
    
            obj.numIndices = indices.length;
    
            gl.bindBuffer(gl.ARRAY_BUFFER, null);
            gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, null);
    
            return obj;
        }
    
        function initArrayBufferForLaterUse(gl, data, num, type) {
            var buffer = gl.createBuffer();
            if(!buffer){
                console.log("无法创建缓冲区对象");
                return null;
            }
    
            gl.bindBuffer(gl.ARRAY_BUFFER, buffer);
            gl.bufferData(gl.ARRAY_BUFFER, data, gl.STATIC_DRAW);
    
            buffer.num = num;
            buffer.type = type;
    
            return buffer;
        }
    
        function initElementArrayBufferForLaterUse(gl, data, type) {
            var buffer = gl.createBuffer();
            if(!buffer){
                console.log("无法创建着色器");
                return null;
            }
    
            gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, buffer);
            gl.bufferData(gl.ELEMENT_ARRAY_BUFFER, data, gl.STATIC_DRAW);
    
            buffer.type = type;
    
            return buffer;
        }
    </script>
    </html>
    

    效果:


    20211221_005011.gif

    相关文章

      网友评论

          本文标题:2021-12-21 webgl实现倒影效果

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