47 WebGL雾化(大气效果)

案例查看地址:点击这里

在三维图形学中,术语雾化(fog)用来描述远处的物体看上去较为模糊的现象。在现实中,任何介质中的物体都可能表现出雾化现象,比如水下的物体。

如何实现雾化:

实现雾化的方式有很多种,这里使用最简单的一种:线性雾化(linear fog)。在线性雾化中,某一点的雾化程度取决于它与视点之间的距离,距离越远雾化程度越高。线性雾化有起点和终点,起点表示开始雾化之处,终点表示完全雾化之处,两点之间的某一点的雾化程度与该点与视点的距离呈线性关系。注意,比终点更远的点完全雾化了,即完全看不见了。某一点雾化的程度可以被定义为雾化因子(fog factor),并在线性雾化公式中被计算出来。

<雾化因子> = ( <终点> - <当前点与视点间的距离>) / ( <终点> - <起点> )

这里

<起点> 小于等于 <当前点与视点间的距离> 小于等于 <终点>

如果雾化因子为1.0,表示该点完全没有被雾化,可以很清晰地看到此处的物体。如果其为0.0,就表示该点完全雾化了,此处的物体完全看不见,如图10.8所示。在视线上,起点之前的点的雾化因子为1.0,终点之后的点的雾化因子为0.0 。


在片元着色器中根据雾化因子计算片元的颜色:

<片元颜色> = <物体表面颜色> x <雾化因子> + <雾的颜色> x ( 1 - <雾化因子> )

下面是案例:


<!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;
            background: url("lib/banner.jpg");
            background-size: cover;
        }

        #canvas {
            margin: 0;
            display: block;
            position: absolute;
        }

        #canvas {
            z-index: 0;
        }
    </style>
</head>
<body οnlοad="main()">
<canvas id="canvas" height="800" width="1200"></canvas>
</body>
<script src="webgl/webgl-utils.js"></script>
<script src="webgl/webgl-debug.js"></script>
<script src="webgl/cuon-utils.js"></script>
<script src="webgl/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 vec4 a_Color;\n" +
        "uniform mat4 u_MvpMatrix;\n" +
        "uniform mat4 u_ModelMatrix;\n" +
        "uniform vec4 u_Eye;\n" +//世界坐标下的视点的位置
        "varying vec4 v_Color;\n" +
        "varying float v_Dist;\n" +
        "void main(){\n" +
        "   gl_Position = u_MvpMatrix * a_Position;\n" +
        "   v_Color = a_Color;\n" +
        "   v_Dist = distance(u_ModelMatrix * a_Position, u_Eye);\n" +//计算出来顶点和视点的距离
        "}\n";

    //片元着色器
    var fragmentShaderSource = "" +
        "#ifdef GL_ES\n" +
        "precision mediump float;\n" +
        "#endif\n" +
        "uniform vec3 u_FogColor;\n" + //雾的颜色
        "uniform vec2 u_FogDist;\n" + //雾化的起点和终点(starting point, end point)
        "varying vec4 v_Color;\n" +
        "varying float v_Dist;\n" +
        "void main(){\n" +
        //计算雾化因子(当它远离眼睛位置时,系数变小)
        "   float fogFactor = clamp((u_FogDist.y - v_Dist) / (u_FogDist.y - u_FogDist.x), 0.0, 1.0);\n" +
        //越远雾化程度越高 u_FogColor * (1 - fogFactor) + v_Color * fogFactor
        "   vec3 color = mix(u_FogColor, vec3(v_Color), fogFactor);\n" +
        "   gl_FragColor = vec4(color, v_Color.a);\n" +
        "}\n";

    function main() {
        //获取WebGL对象
        var gl = getWebGLContext(canvas);

        //初始化着色器
        initShaders(gl, vertexShaderSource, fragmentShaderSource);

        //将数据存入缓冲区
        var n = initVertexBuffers(gl);
        if (n < 0) {
            console.log("数据存入缓冲区失败");
            return;
        }

        //设置雾的颜色
        var fogColor = new Float32Array([0.15, 0.23, 0.426]);

        //雾化的起点和终点与视点间的距离【起点距离, 终点距离】
        var fogDist = new Float32Array([55, 100]);

        //视点在世界坐标系下的位置
        var eye = new Float32Array([25, 65, 35, 1.0]);

        //获取相关uniform变量的存储位置
        var u_MvpMatrix = gl.getUniformLocation(gl.program, "u_MvpMatrix");
        var u_ModelMatrix = gl.getUniformLocation(gl.program, "u_ModelMatrix");
        var u_Eye = gl.getUniformLocation(gl.program, "u_Eye");
        var u_FogColor = gl.getUniformLocation(gl.program, "u_FogColor");
        var u_FogDist = gl.getUniformLocation(gl.program, "u_FogDist");
        if (!u_MvpMatrix || !u_ModelMatrix || !u_Eye || !u_FogColor || !u_FogDist) {
            console.log("无法获取uniform变量的相关位置");
            return;
        }

        //将雾的颜色,起点与终点,视点坐标传给对应的uniform变量
        gl.uniform3fv(u_FogColor, fogColor); //雾的颜色
        gl.uniform2fv(u_FogDist, fogDist); //起点和终点
        gl.uniform4fv(u_Eye, eye); //视点

        //将雾的颜色设置为背景色
        gl.clearColor(fogColor[0], fogColor[1], fogColor[2], 1.0);
        gl.enable(gl.DEPTH_TEST);

        //设置模型矩阵并赋值
        var modeMatrix = new Matrix4();
        modeMatrix.setScale(10.0, 10.0, 10.0);
        gl.uniformMatrix4fv(u_ModelMatrix, false, modeMatrix.elements);

        //设置视图投影矩阵
        var mvpMatrix = new Matrix4();
        mvpMatrix.setPerspective(30.0, canvas.width/canvas.height, 1.0, 1000.0);
        mvpMatrix.lookAt(eye[0], eye[1], eye[2], 0.0, 2.0, 0.0, 0.0, 1.0, 0.0);
        mvpMatrix.multiply(modeMatrix);
        gl.uniformMatrix4fv(u_MvpMatrix, false, mvpMatrix.elements);

        //绑定一个点击事件
        document.onkeydown = function () {
            keydown(event, gl, n, u_FogDist, fogDist);
        };

        //清除背景色及层级关系
        gl.clear(gl.COLOR_BUFFER_BIT || gl.DEPTH_BUFFER_BIT);

        //绘制
        gl.drawElements(gl.TRIANGLES, n, gl.UNSIGNED_BYTE, 0);

        var modelViewMatrix = new Matrix4();
        modelViewMatrix.setLookAt(eye[0], eye[1], eye[2], 0.0, 2.0, 0.0, 0.0, 1.0, 0.0);
        modelViewMatrix.multiply(modeMatrix);
        modelViewMatrix.multiplyVector4(new Vector4([1.0, 1.0, 1.0, 1.0]));
        mvpMatrix.multiplyVector4(new Vector4([1.0, 1.0, 1.0, 1.0]));
        modelViewMatrix.multiplyVector4(new Vector4([-1.0, 1.0, 1.0, 1.0]));
        mvpMatrix.multiplyVector4(new Vector4([-1.0, 1.0, 1.0, 1.0]));
    }

    function keydown(event, gl, n, u_FogDist, fogDist) {
        switch (event.keyCode){
            case 38:
                fogDist[1] += 1;
                break;
            case 40:
                if(fogDist[1] > fogDist[0]){
                    fogDist[1] -= 1;
                }
                break;
            default:
                return;
        }

        gl.uniform2fv(u_FogDist, fogDist);

        gl.clear(gl.COLOR_BUFFER_BIT | gl.EDPTH_BUFFER_BIT);
        gl.drawElements(gl.TRIANGLES, n, gl.UNSIGNED_BYTE, 0);
    }

    function initVertexBuffers(gl) {
        // Create a cube
        //    v6----- v5
        //   /|      /|
        //  v1------v0|
        //  | |     | |
        //  | |v7---|-|v4
        //  |/      |/
        //  v2------v3

        var vertices = new Float32Array([   // Vertex coordinates 顶点的位置
            1, 1, 1, -1, 1, 1, -1, -1, 1, 1, -1, 1,    // v0-v1-v2-v3 front
            1, 1, 1, 1, -1, 1, 1, -1, -1, 1, 1, -1,    // v0-v3-v4-v5 right
            1, 1, 1, 1, 1, -1, -1, 1, -1, -1, 1, 1,    // v0-v5-v6-v1 up
            -1, 1, 1, -1, 1, -1, -1, -1, -1, -1, -1, 1,    // v1-v6-v7-v2 left
            -1, -1, -1, 1, -1, -1, 1, -1, 1, -1, -1, 1,    // v7-v4-v3-v2 down
            1, -1, -1, -1, -1, -1, -1, 1, -1, 1, 1, -1     // v4-v7-v6-v5 back
        ]);

        var colors = new Float32Array([     // Colors 顶点的颜色
            0.4, 0.4, 1.0, 0.4, 0.4, 1.0, 0.4, 0.4, 1.0, 0.4, 0.4, 1.0,  // v0-v1-v2-v3 front
            0.4, 1.0, 0.4, 0.4, 1.0, 0.4, 0.4, 1.0, 0.4, 0.4, 1.0, 0.4,  // v0-v3-v4-v5 right
            1.0, 0.4, 0.4, 1.0, 0.4, 0.4, 1.0, 0.4, 0.4, 1.0, 0.4, 0.4,  // v0-v5-v6-v1 up
            1.0, 1.0, 0.4, 1.0, 1.0, 0.4, 1.0, 1.0, 0.4, 1.0, 1.0, 0.4,  // 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
            0.4, 1.0, 1.0, 0.4, 1.0, 1.0, 0.4, 1.0, 1.0, 0.4, 1.0, 1.0   // v4-v7-v6-v5 back
        ]);

        var indices = new Uint8Array([       // Indices of the vertices 顶点的索引
            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
        ]);

        //将顶点位置和颜色存入颜色缓冲区
        if (!initArrayBuffer(gl, vertices, 3, gl.FLOAT, 'a_Position')) return -1;
        if (!initArrayBuffer(gl, colors, 3, gl.FLOAT, 'a_Color')) return -1;

        //创建一个索引的缓冲区对象
        var indexBuffer = gl.createBuffer();
        if(!indexBuffer){
            console.log("无法创建缓冲区对象");
            return -1;
        }

        gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, indexBuffer);
        gl.bufferData(gl.ELEMENT_ARRAY_BUFFER, indices, gl.STATIC_DRAW);

        return indices.length;
    }

    function initArrayBuffer(gl, data, num, type, attribute) {
        var buffer = gl.createBuffer();
        if (!buffer) {
            console.log("无法创建缓冲区对象");
            return;
        }
        gl.bindBuffer(gl.ARRAY_BUFFER, buffer);
        gl.bufferData(gl.ARRAY_BUFFER, data, gl.STATIC_DRAW);
        var a_attribute = gl.getAttribLocation(gl.program, attribute);
        if (a_attribute < 0) {
            console.log("无法获取变量的存储位置" + attribute);
            return false;
        }
        gl.vertexAttribPointer(a_attribute, num, type, false, 0, 0);
        gl.enableVertexAttribArray(a_attribute);

        return true;
    }

</script>
</html>

顶点着色器计算了顶点与视点间的距离:首先将顶点坐标转换到世界坐标系下,然后调用内置函数distance()并将视点坐标(也是在世界坐标系下)和顶点坐标作为参数传入,distance()函数算出两者间的距离,并赋值v_Dist变量以传入片元着色器。

片元着色器根据上面的两个式子计算出雾化后的片元颜色。我们分别通过u_FogColor变量和u_FogDist变量来传入雾的颜色和范围,其中u_FogDist.x和u_FogDist.y分别是起点和终点与视点间的距离。


使用w分量

在顶点着色器中计算顶点与视点的距离,会造成较大的开销,也许会影响性能。我们可以使用另外一种方法来近似估算出这个距离,那就是使用顶点经过模型视图投影矩阵变换后的坐标的w分量。在本例中,顶点变换后的坐标就是gl_Position。之前,我们并未显式使用过gl_Psoition的w分量,实际上,这个w分量的值就是顶点的视图坐标的z分量乘以-1.在视图坐标系中,视点是原点,视线沿着Z轴负方向,观察者看到的物体其视图坐标系值z分量都是负的,而gl_Position的w分量值正好是z分量值乘以-1,所以可以直接使用该值来近似顶点与视点的距离。

<!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;
            background: url("lib/banner.jpg");
            background-size: cover;
        }

        #canvas {
            margin: 0;
            display: block;
            position: absolute;
        }

        #canvas {
            z-index: 0;
        }
    </style>
</head>
<body οnlοad="main()">
<canvas id="canvas" height="800" width="1200"></canvas>
</body>
<script src="webgl/webgl-utils.js"></script>
<script src="webgl/webgl-debug.js"></script>
<script src="webgl/cuon-utils.js"></script>
<script src="webgl/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 vec4 a_Color;\n" +
        "uniform mat4 u_MvpMatrix;\n" +
        "varying vec4 v_Color;\n" +
        "varying float v_Dist;\n" +
        "void main(){\n" +
        "   gl_Position = u_MvpMatrix * a_Position;\n" +
        "   v_Color = a_Color;\n" +
        "   v_Dist = gl_Position.w;\n" +//使用视图坐标系的负z值
        "}\n";

    //片元着色器
    var fragmentShaderSource = "" +
        "#ifdef GL_ES\n" +
        "precision mediump float;\n" +
        "#endif\n" +
        "uniform vec3 u_FogColor;\n" + //雾的颜色
        "uniform vec2 u_FogDist;\n" + //雾化的起点和终点(starting point, end point)
        "varying vec4 v_Color;\n" +
        "varying float v_Dist;\n" +
        "void main(){\n" +
        //计算雾化因子(当它远离眼睛位置时,系数变小)
        "   float fogFactor = clamp((u_FogDist.y - v_Dist) / (u_FogDist.y - u_FogDist.x), 0.0, 1.0);\n" +
        //越远雾化程度越高 u_FogColor * (1 - fogFactor) + v_Color * fogFactor
        "   vec3 color = mix(u_FogColor, vec3(v_Color), fogFactor);\n" +
        "   gl_FragColor = vec4(color, v_Color.a);\n" +
        "}\n";

    function main() {
        //获取WebGL对象
        var gl = getWebGLContext(canvas);

        //初始化着色器
        initShaders(gl, vertexShaderSource, fragmentShaderSource);

        //将数据存入缓冲区
        var n = initVertexBuffers(gl);
        if (n < 0) {
            console.log("数据存入缓冲区失败");
            return;
        }

        //设置雾的颜色
        var fogColor = new Float32Array([0.5, 1.0, 1.0]);

        //雾化的起点和终点与视点间的距离【起点距离, 终点距离】
        var fogDist = new Float32Array([55, 200]);

        //视点在世界坐标系下的位置
        var eye = new Float32Array([25, 65, 35, 1.0]);

        //获取相关uniform变量的存储位置
        var u_MvpMatrix = gl.getUniformLocation(gl.program, "u_MvpMatrix");
        var u_FogColor = gl.getUniformLocation(gl.program, "u_FogColor");
        var u_FogDist = gl.getUniformLocation(gl.program, "u_FogDist");
        if (!u_MvpMatrix || !u_FogColor || !u_FogDist) {
            console.log("无法获取uniform变量的相关位置");
            return;
        }

        //将雾的颜色,起点与终点,视点坐标传给对应的uniform变量
        gl.uniform3fv(u_FogColor, fogColor); //雾的颜色
        gl.uniform2fv(u_FogDist, fogDist); //起点和终点
        /*gl.uniform4fv(u_Eye, eye); //视点*/

        //将雾的颜色设置为背景色
        gl.clearColor(fogColor[0], fogColor[1], fogColor[2], 1.0);
        gl.enable(gl.DEPTH_TEST);

        //设置模型矩阵并赋值
        var modeMatrix = new Matrix4();
        modeMatrix.setScale(10.0, 10.0, 10.0);

        //设置视图投影矩阵
        var mvpMatrix = new Matrix4();
        mvpMatrix.setPerspective(30.0, canvas.width/canvas.height, 1.0, 1000.0);
        mvpMatrix.lookAt(eye[0], eye[1], eye[2], 0.0, 2.0, 0.0, 0.0, 1.0, 0.0);
        mvpMatrix.multiply(modeMatrix);
        gl.uniformMatrix4fv(u_MvpMatrix, false, mvpMatrix.elements);

        //绑定一个点击事件
        document.onkeydown = function () {
            keydown(event, gl, n, u_FogDist, fogDist);
        };

        //清除背景色及层级关系
        gl.clear(gl.COLOR_BUFFER_BIT || gl.DEPTH_BUFFER_BIT);

        //绘制
        gl.drawElements(gl.TRIANGLES, n, gl.UNSIGNED_BYTE, 0);

    }

    function keydown(event, gl, n, u_FogDist, fogDist) {
        switch (event.keyCode){
            case 38:
                fogDist[1] += 1;
                break;
            case 40:
                if(fogDist[1] > fogDist[0]){
                    fogDist[1] -= 1;
                }
                break;
            default:
                return;
        }

        gl.uniform2fv(u_FogDist, fogDist);

        gl.clear(gl.COLOR_BUFFER_BIT | gl.EDPTH_BUFFER_BIT);
        gl.drawElements(gl.TRIANGLES, n, gl.UNSIGNED_BYTE, 0);
    }

    function initVertexBuffers(gl) {
        // Create a cube
        //    v6----- v5
        //   /|      /|
        //  v1------v0|
        //  | |     | |
        //  | |v7---|-|v4
        //  |/      |/
        //  v2------v3

        var vertices = new Float32Array([   // Vertex coordinates 顶点的位置
            1, 1, 1, -1, 1, 1, -1, -1, 1, 1, -1, 1,    // v0-v1-v2-v3 front
            1, 1, 1, 1, -1, 1, 1, -1, -1, 1, 1, -1,    // v0-v3-v4-v5 right
            1, 1, 1, 1, 1, -1, -1, 1, -1, -1, 1, 1,    // v0-v5-v6-v1 up
            -1, 1, 1, -1, 1, -1, -1, -1, -1, -1, -1, 1,    // v1-v6-v7-v2 left
            -1, -1, -1, 1, -1, -1, 1, -1, 1, -1, -1, 1,    // v7-v4-v3-v2 down
            1, -1, -1, -1, -1, -1, -1, 1, -1, 1, 1, -1     // v4-v7-v6-v5 back
        ]);

        var colors = new Float32Array([     // Colors 顶点的颜色
            0.4, 0.4, 1.0, 0.4, 0.4, 1.0, 0.4, 0.4, 1.0, 0.4, 0.4, 1.0,  // v0-v1-v2-v3 front
            0.4, 1.0, 0.4, 0.4, 1.0, 0.4, 0.4, 1.0, 0.4, 0.4, 1.0, 0.4,  // v0-v3-v4-v5 right
            1.0, 0.4, 0.4, 1.0, 0.4, 0.4, 1.0, 0.4, 0.4, 1.0, 0.4, 0.4,  // v0-v5-v6-v1 up
            1.0, 1.0, 0.4, 1.0, 1.0, 0.4, 1.0, 1.0, 0.4, 1.0, 1.0, 0.4,  // 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
            0.4, 1.0, 1.0, 0.4, 1.0, 1.0, 0.4, 1.0, 1.0, 0.4, 1.0, 1.0   // v4-v7-v6-v5 back
        ]);

        var indices = new Uint8Array([       // Indices of the vertices 顶点的索引
            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
        ]);

        //将顶点位置和颜色存入颜色缓冲区
        if (!initArrayBuffer(gl, vertices, 3, gl.FLOAT, 'a_Position')) return -1;
        if (!initArrayBuffer(gl, colors, 3, gl.FLOAT, 'a_Color')) return -1;

        //创建一个索引的缓冲区对象
        var indexBuffer = gl.createBuffer();
        if(!indexBuffer){
            console.log("无法创建缓冲区对象");
            return -1;
        }

        gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, indexBuffer);
        gl.bufferData(gl.ELEMENT_ARRAY_BUFFER, indices, gl.STATIC_DRAW);

        return indices.length;
    }

    function initArrayBuffer(gl, data, num, type, attribute) {
        var buffer = gl.createBuffer();
        if (!buffer) {
            console.log("无法创建缓冲区对象");
            return;
        }
        gl.bindBuffer(gl.ARRAY_BUFFER, buffer);
        gl.bufferData(gl.ARRAY_BUFFER, data, gl.STATIC_DRAW);
        var a_attribute = gl.getAttribLocation(gl.program, attribute);
        if (a_attribute < 0) {
            console.log("无法获取变量的存储位置" + attribute);
            return false;
        }
        gl.vertexAttribPointer(a_attribute, num, type, false, 0, 0);
        gl.enableVertexAttribArray(a_attribute);

        return true;
    }

</script>
</html>


参与评论 您还未登录,请先 登录 后发表或查看评论
基本信息 原书名:WebGL Programming Guide: Interactive 3D Graphics Programming with WebGL (OpenGL) 原出版社: Addison-Wesley Professional 作者: (美)Kouichi Matsuda Rodger Lea(松田浩一,罗杰.李) 译者: 谢光磊 出版社:电子工业出版社 ISBN:9787121229428 上架时间:2014-6-11 出版日期:2014 年6月 开本:16开 页码:470 版次:1-1 --------------------- 目录 《WebGL编程指南》 第1 章 WebGL 概述 1 WebGL 的优势 3 使用文本编辑器开发三维应用 3 轻松发布三维图形程序 4 充分利用浏览器的功能 5 学习和使用WebGL 很简单 5 WebGL 的起源 5 WebGL 程序的结构 6 总结 7 第2 章 WebGL 入门 9 Canvas 是什么? 10 使用[canvas] 标签 11 DrawRectangle.js 13 最短的WebGL 程序:清空绘图区 16 HTML 文件(HelloCanvas.html) 16 JavaScript 程序(HelloCanvas.js) 17 用示例程序做实验 22 绘制一个点(版本1) 22 HelloPoint1.html 24 HelloPoint1.js 24 着色器是什么? 25 使用着色器的WebGL 程序的结构 27 初始化着色器 29 顶点着色器 31 片元着色器 33 绘制操作 34 WebGL 坐标系统 35 用示例程序做实验 37 绘制一个点(版本2) 38 使用attribute 变量 38 示例程序(HelloPoint2.js) 39 获取attribute 变量的存储位置 41 向attribute 变量赋值 42 gl.vertexAttrib3f() 的同族函数 44 用示例程序做实验 45 通过鼠标点击绘点 46 示例程序(ClickedPoints.js) 47 注册事件响应函数 48 响应鼠标点击事件 50 用示例程序做实验 53 改变点的颜色 55 示例程序(ColoredPoints.js) 56 uniform 变量 58 获取uniform 变量的存储地址 59 向uniform 变量赋值 60 gl.uniform4f() 的同族函数 61 总结 62 第3 章 绘制和变换三角形 63 绘制多个点 64 示例程序(MultiPoint.js) 66 使用缓冲区对象 69 创建缓冲区对象(gl.createBuffer()) 70 绑定缓冲区(gl.bindBuffer()) 71 向缓冲区对象中写入数据(gl.bufferData()) 72 类型化数组 74 将缓冲区对象分配给attribute 变量(gl.vertexAttribPointer()) 75 开启attribute 变量(gl.enableVertexAttribArray()) 77 gl.drawArrays() 的第2 个和第3 个参数 78 用示例程序做实验 79 Hello Triangle 80 示例程序(HelloTriangle.js) 80 基本图形 82 用示例程序做实验 83 Hello Rectangle(HelloQuad) 84 用示例程序做实验 85 移动、旋转和缩放 86 平移 87 示例程序(TranslatedTriangle.js) 88 旋转 91 示例程序(RotatedTriangle.js) 93 变换矩阵:旋转 97 变换矩阵:平移 100 4×4 的旋转矩阵 101 示例程序(RotatedTriangle_Matrix.js) 102 平移:相同的策略 105 变换矩阵:缩放 106 总结 108 第4 章 高级变换与动画基础 109 平移,然后旋转 109 矩阵变换库:cuon-matrix.js 110 示例程序(RotatedTriangle_Matrix4.js) 111 复合变换 113 示例程序(RotatedTranslatedTriangle.js) 115 用示例程序做实验 117 动画 118 动画基础 119 示例程序(RotatingTriangle.js) 119 反复调用绘制函数(tick()) 123 按照指定的旋转角度绘制三角形(draw()) 123 请求再次被调用(requestAnimationFrame()) 125 更新旋转角(animate()) .126 用示例程序做实验 128 总结 130 第5 章 颜色与纹理 131 将非坐标数据传入顶点着色器 131 示例程序(MultiAttributeSize.js) 133 创建多个缓冲区对象 134 gl.vertexAttribPointer() 的步进和偏移参数 135 示例程序(MultiAttributeSize_Interleaved.js) 136 修改颜色(varying 变量) 140 示例程序(MultiAttributeColor.js) 141 用示例程序做实验 144 彩色三角形(ColoredTriangle.js) 145 几何形状的装配和光栅化 145 调用片元着色器 149 用示例程序做实验 149 varying 变量的作用和内插过程 151 在矩形表面贴上图像 153 纹理坐标 156 将纹理图像粘贴到几何图形上 156 示例程序(TexturedQuad.js) 157 设置纹理坐标(initVertexBuffers()) 160 配置和加载纹理(initTextures()) 160 为WebGL 配置纹理(loadTexture()) 164 图像Y 轴反转 164 激活纹理单元(gl.activeTexture()) 165 绑定纹理对象(gl.bindTexture()) 166 配置纹理对象的参数(gl.texParameteri()) 168 将纹理图像分配给纹理对象(gl.texImage2D()) 171 将纹理单元传递给片元着色器(gl.uniform1i()) 173 从顶点着色器向片元着色器传输纹理坐标 174 在片元着色器中获取纹理像素颜色(texture2D()) 174 用示例程序做试验 175 使用多幅纹理 177 示例程序(MultiTexture.js) 178 总结 183 第6 章 OpenGL ES 着色器语言(GLSL ES) 185 回顾:基本着色器代码 186 GLSL ES 概述 186 你好,着色器! 187 基础 187 执行次序 187 注释 187 数据值类型(数值和布尔值) 188 变量 188 GLSL ES 是强类型语言 189 基本类型 189 赋值和类型转换 190 运算符 191 矢量和矩阵 192 赋值和构造 193 访问元素 195 运算符 197 结构体 200 赋值和构造 200 访问成员 200 运算符 201 数组 201 取样器(纹理) 202 运算符优先级 203 程序流程控制:分支和循环 203 if 语句和if-else 语句 203 for 语句 204 continue、break 和discard 语句 205 函数 205 规范声明 207 参数限定词 207 内置函数 208 全局变量和局部变量 209 存储限定字 209 const 变量 209 Attribute 变量 210 uniform 变量 211 varying 变量 211 精度限定字 211 预处理指令 213 总结 215 第7 章 进入三维世界 217 立方体由三角形构成 217 视点和视线 218 视点、观察目标点和上方向 219 示例程序(LookAtTriangles.js) 221 LookAtTriangles.js 与RotatedTriangle_Matrix4.js 224 从指定视点观察旋转后的三角形 225 示例程序(LookAtRotatedTriangles.js) 227 用示例程序做实验 228 利用键盘改变视点 230 示例程序(LookAtTrianglesWithKeys.js) 230 独缺一角 232 可视范围(正射类型) 233 可视空间 234 定义盒状可视空间 235 示例程序(OrthoView.html) 236 示例程序(OrthoView.js) 237 JavaScript 修改HTML 元素 239 顶点着色器的执行流程 239 修改near 和far 值 241 补上缺掉的角(LookAtTrianglesWithKeys_ViewVolume.js) 243 用示例程序做实验 245 可视空间(透视投影) 246 定义透视投影可视空间 247 示例程序(perspectiveview.js) 249 投影矩阵的作用 251 共冶一炉(模型矩阵、视图矩阵和投影矩阵) 252 示例程序(PerspectiveView_mvp.js) 254 用示例程序做实验 257 正确处理对象的前后关系 258 隐藏面消除 260 示例程序(DepthBuffer.js) 262 深度冲突 263 立方体 266 通过顶点索引绘制物体 268 示例程序(HelloCube.js) 268 向缓冲区中写入顶点的坐标、颜色与索引 271 为立方体的每个表面指定颜色 274 示例程序(ColoredCube.js) 275 用示例程序做实验 277 总结 279 第8 章 光照 281 光照原理 281 光源类型 283 反射类型 284 平行光下的漫反射 286 根据光线和表面的方向计算入射角 287 法线:表面的朝向 288 示例程序(LightedCube.js) 291 环境光下的漫反射 296 示例程序(LightedCube_ambient.js) 298 运动物体的光照效果 299 魔法矩阵:逆转置矩阵 301 示例程序(LightedTranslatedRotatedCube.js) 302 点光源光 304 示例程序(PointLightedCube.js) 305 更逼真:逐片元光照 308 示例程序(PointLightedCube_perFragment.js) 309 总结 310 第9 章 层次模型 311 多个简单模型组成的复杂模型 311 层次结构模型 313 单关节模型 314 示例程序(JointMode.js) 315 绘制层次模型(draw()) 319 多节点模型 321 示例程序(MultiJointModel.js) 323 绘制部件(drawBox()) 326 绘制部件(drawSegments()) 327 着色器和着色器程序对象:initShaders() 函数的作用 332 创建着色器对象(gl.createShader()) 333 指定着色器对象的代码(gl.shaderSource()) 334 编译着色器(gl.compileShader()) 334 创建程序对象(gl.createProgram()) 336 为程序对象分配着色器对象(gl.attachShader()) 337 连接程序对象(gl.linkProgram()) 337 告知WebGL 系统所使用的程序对象(gl.useProgram()) 339 initShaders() 函数的内部流程 339 总结 342 第10 章 高级技术 343 用鼠标控制物体旋转 343 如何实现物体旋转 344 示例程序(RotateObject.js) 344 选中物体 347 如何实现选中物体 347 示例程序(PickObject.js) 348 选中一个表面 351 示例程序(PickFace.js) 352 HUD(平视显示器) 355 如何实现HUD 355 示例程序(HUD.html) 356 示例程序(HUD.js) 357 在网页上方显示三维物体 359 雾化大气效果) 359 如何实现雾化 360 示例程序(Fog.js) 361 使用w 分量(Fog_w.js) 363 绘制圆形的点 364 如何实现圆形的点 364 示例程序(RoundedPoint.js) 366 α 混合 367 如何实现α 混合 367 示例程序(LookAtBlendedTriangles.js) 369 混合函数 369 半透明的三维物体(BlendedCube.js) 371 透明与不透明物体共存 372 切换着色器 373 如何实现切换着色器 374 示例程序(ProgramObject.js) 375 渲染到纹理 379 帧缓冲区对象和渲染缓冲区对象 380 如何实现渲染到纹理 381 示例程序(FramebufferObject.js) 382 创建帧缓冲区对象(gl.createFramebuffer()) 385 创建纹理对象并设置其尺寸和参数 385 创建渲染缓冲区对象(gl.createRenderbuffer()) 386 绑定渲染缓冲区并设置其尺寸(gl.bindRenderbuffer(), gl.renderbufferStorage()) 386 将纹理对象关联到帧缓冲区对象(gl.bindFramebuffer(), gl.framebufferTexture2D()) 388 将渲染缓冲区对象关联到帧缓冲区对象(gl.framebufferRenderbuffer()) 389 检查帧缓冲区的配置(gl.checkFramebufferStatus()) 390 在帧缓冲区进行绘图 390 绘制阴影 392 如何实现阴影 392 示例程序(Shadow.js) 393 提高精度 399 示例程序(Shadow_highp.js) 400 加载三维模型 401 OBJ 文件格式 404 MTL 文件格式 405 示例程序(OBJViewer.js) 406 自定义类型对象 409 示例程序(OBJViewer.js 解析数据部分) 411 响应上下文丢失 418 如何响应上下文丢失 419 示例程序(RotatingTriangle_contextLost.js) 420 总结 422 附录A WebGL 中无须交换缓冲区 423 附录B GLSL ES 1.0 内置函数 427 角度和三角函数 428 指数函数 429 通用函数 430 几何函数 433 矩阵函数 434 矢量函数 435 纹理查询函数 436 附录C 投影矩阵 437 正射投影矩阵 437 透视投影矩阵 437 附录D WebGL/OpenGL :左手还是右手坐标系? 439 示例程序(CoordinateSystem.js) 440 隐藏面消除和裁剪坐标系统 443 裁剪坐标系和可视空间 444 什么是对的? 446 总结 448 附录E 逆转置矩阵 449 附录F 从文件中加载着色器 453 附录G 世界坐标系和本地坐标系 . 457 本地坐标系 458 世界坐标系 459 变换与坐标系 461 附录H WebGL 的浏览器设置 . 463
WebGL 是一项在网页上渲染三维图形的技术,也是HTML5 草案的一部分。   《WebGL编程指南》的主要篇幅讲解了WebGL 原生API 和三维图形学的基础知识,包括渲染管线、着色器、矩阵变换、着色器编程语言(GLSL ES)等等,也讲解了使用WebGL 渲染三维场景的一般技巧,如光照、阴影、雾化等等。《WebGL编程指南》提供了丰富的示例程序供读者钻研,也提供了极具价值的附录供读者参考。   《WebGL编程指南》适合有一定前端开发基础,希望学习WebGL,但对三维图形学缺乏了解的程序员们阅读。 作者简介   关于作者   Kouichi Matsuda 博士是多媒体产品用户界面和用户体验设计方面的专家。他先后供职于日本电气(NEC)、索尼(Sony) 研发中心、索尼(Sony) 计算机科学实验室,曾经做过产品研发,也做过科学研究,最终回到产品研发的岗位。目前,他是用户体验和人机交互领域的首席研究员,负责多款消费类电子产品的设计。他曾经设计了社交三维虚拟世界“PAW”,也曾经参与过VRML97(ISO/IEC 14772-1:1997) 标准的开发工作,在VRML和X3D(WebGL 的前身) 社区中仍然非常活跃。他撰写过15 本计算机技术 的书籍,并翻译过25 本相关书籍。他专长于用户体验、用户界面、人机交互、自然语言处理和面向娱乐的网络设备,以及接口代理系统等领域。他不仅对技术领域的新鲜事物充满热情,还热衷于温泉、夏季的海滩、红酒和漫画(为此他已经沉迷于绘制插画一段时间了)。他在东京大学工程系获得了博士学位,你可以通过WebGL.prog.guide@gmail.com 联系他。   Rodger Lea 博士是卑诗大学媒体与图像跨学科中心的兼职教授,对多媒体和分布式计算等领域很感兴趣。他和他带领的研究小组在学术和工业领域耕耘超过20 年,参与制定了VRML97 标准,开发了多媒体操作系统、可交互数字电视原型,并领导了家用多媒体网络标准的制定工作。他发表了60 多篇学术论文,著有3 本技术书籍,并拥有12 项专利。目前,他的研究集中在探索发展中的互联网,但他仍然对有关多媒体和图形学的一切抱有热情。   使用WebGL,你可以在浏览器中,不依赖任何插件创建出精美的可交互三维图形。WebGL技术使得创建新一代3D网页游戏、用户界面、数据可视化方案成为可能,这些程序能够运行任何支持标准浏览器的PC、智能手机、平板电脑、家用游戏机或其他设备上。《WebGL编程指南》将会帮助你快速入门学习可交互的WebGL 3D编程,即使你还不了解HTML5、JavaScript、三维图形学理论、数学基础和OpenGL也没有关系。   你将会一步一步地学习真实的示例程序。随着示例程序从简单变复杂,你也将逐渐掌握使用WebGL开发虚拟逼真的网页和三维图形的技能。多媒体、三维图形学和WebGL领域的先驱者Kouichi Matsuda博士和Rodger Lea博士在这本书中提供了易于上手、重点清晰的WebGL教程,以及共计100个可下载的示例程序,每个程序都讨论了一个具体的WebGL话题。   你将从基本的技术比如渲染、动画、为三角形贴上纹理开始,一路学习到高级的WebGL技术,比如雾化、阴影、切换着色器、显示由Blender等建模工具创建的三维模型。这本书并不仅仅向你传授实践方法,同时也会向你提供一个小型的代码库,方便你在学习完本书后,开始编写自己的程序。   本书的内容包括:   √ WebGL的起源、核心概念、特性、优势以及与其他Web标准的结合;   √ canvas和基本的WebGL函数如何协作以显示三维图形;   √ 使用OpenGL ES着色器语言(GLSL ES)编写着色器代码;   √ 三维场景渲染:表示用户视野、控制可视空间、裁剪、三维对象创建、透视;   √ 通过光照和层次结构模型产生更真实的效果;   √ 高级技巧:对象操作,HUD、混合、着色器切换等等;   √ 极具价值的附录,涵盖了从坐标系统到矩阵、从着色器加载到浏览器设置等诸多关键知识点。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
©️2022 CSDN 皮肤主题:技术黑板 设计师:CSDN官方博客 返回首页

打赏作者

暮志未晚Webgl

你的鼓励将是我创作的最大动力

¥2 ¥4 ¥6 ¥10 ¥20
输入1-500的整数
余额支付 (余额:-- )
扫码支付
扫码支付:¥2
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、C币套餐、付费专栏及课程。

余额充值