WebGL第四十三课完整代码

192 阅读2分钟
  • index.html
<!doctype html>
<html>

<head>
    <style>
        canvas {
            border: 1px solid #000000;
        }
    </style>

</head>

<body>

    <canvas id="gl" width="300" height="300" style="width:300px; height:300px">
    </canvas>
    <script id="vertex_shader" type="myshader">
        // Vertex Shader
        precision mediump int;
        precision mediump float;

        attribute vec3 a_PointVertex; // 顶点坐标

        uniform mat4 u_Model; // Model 矩阵
        uniform mat4 u_View;  // View 矩阵
        uniform mat4 u_Projection; // Projection 矩阵
        
        varying vec3 va_pos;

        void main() {
          va_pos = a_PointVertex;
          mat4 MVP = u_Projection * u_View * u_Model;
          gl_Position = MVP * vec4(a_PointVertex.xyz, 1.0);
        }
    </script>
    <script id="fragment_shader" type="myshader">
        // Fragment shader
        precision mediump int;
        precision mediump float;

        varying vec3 va_pos;

        void main() {
            vec3 color = (va_pos + 1.0) * 0.5;
            gl_FragColor = vec4(color, 1.0);
        }
    </script>

    <script type="text/javascript" src="math.js"></script>
    <script type="text/javascript" src="logic.js"></script>

</body>

</html>
  • math.js
function vec3_inverse(a) {
    return [-a[0], -a[1], -a[2]];
}
function vec3_minus(a, b) {
    return [a[0] - b[0], a[1] - b[1], a[2] - b[2]];
}
function vec3_add(a, b) {
    return [a[0] + b[0], a[1] + b[1], a[2] + b[2]];
}
function vec3_dot(a, b) {
    return a[0] * b[0] + a[1] * b[1] + a[2] * b[2];
}
function vec3_normalize(a) {
    let l = Math.sqrt(a[0] * a[0] + a[1] * a[1] + a[2] * a[2]);
    return [a[0] / l, a[1] / l, a[2] / l];
}
function vec3_cross(a, b) {
    return [
        a[1] * b[2] - b[1] * a[2],
        a[2] * b[0] - b[2] * a[0],
        a[0] * b[1] - b[0] * a[1]
    ];
}

// 获取单位阵
function mat4_get_identity() {
    return [1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1];
}

// 获取0矩阵
function mat4_get_zero() {
    return [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0];
}

// 获取View矩阵
function mat4_get_lookat(eye, target, up) {
    let f = vec3_normalize(vec3_minus(target, eye));
    let s = vec3_normalize(vec3_cross(f, up));
    let u = vec3_cross(s, f);
    let Result = mat4_get_identity();
    Result[0] = s[0];
    Result[4] = s[1];
    Result[8] = s[2];
    Result[1] = u[0];
    Result[5] = u[1];
    Result[9] = u[2];
    Result[2] = -f[0];
    Result[6] = -f[1];
    Result[10] = -f[2];
    Result[12] = -(vec3_dot(s, eye));
    Result[13] = -(vec3_dot(u, eye));
    Result[14] = vec3_dot(f, eye);
    return Result;
}

// 获取Perspective矩阵
// fov 是角度
function mat4_get_perspective(near, far, whr, fov) {

    let fov_ra = 0.01745329251994329576923690768489 * fov;
    let tanHalfFovy = Math.tan(fov_ra / 2);

    let Result = mat4_get_zero();
    Result[0] = 1 / (whr * tanHalfFovy);
    Result[5] = 1 / (tanHalfFovy);
    Result[10] = - (far + near) / (far - near);
    Result[11] = -1;
    Result[14] = - (2 * far * near) / (far - near);
    return Result;
}
  • logic.js
var pointCanvas = null;
var gl = null;

var u_Model_loc = null;
var u_View_loc = null;
var u_Projection_loc = null;

var program = null;


// 入口函数
function Main() {
    gl_init();
    generateCube(gl);
    gl_draw();
}

/**
 * 生成方块的顶点数据并上传到gl
 * 
 */
function generateCube(gl) {
    // 一个正方体六个面
    // 每个面两个三角形
    // 一共12个三角形
    // 每个三角形三个顶点,所以数据是下面这样的
    let cube_model = [
        1, -1, 1,/**/1, -1, -1,/**/1, 1, 1,/**/1, -1, -1,/**/1, 1, -1/**/, 1, 1, 1,// x正方向的面
        -1, -1, -1,/**/-1, -1, 1,/**/-1, 1, -1,/**/-1, -1, 1,/**/-1, 1, 1/**/, -1, 1, -1,// x负方向的面
        //
        1, 1, -1,/**/-1, 1, -1,/**/1, 1, 1,/**/-1, 1, -1,/**/-1, 1, 1/**/, 1, 1, 1,// y正方向的面
        -1, -1, -1,/**/1, -1, -1,/**/-1, -1, 1,/**/1, -1, -1,/**/1, -1, 1/**/, -1, -1, 1,// y负方向的面
        //
        -1, 1, 1,/**/-1, -1, 1,/**/1, 1, 1,/**/-1, -1, 1,/**/1, -1, 1/**/, 1, 1, 1,// z正方向的面
        -1, -1, -1,/**/-1, 1, -1,/**/1, 1, -1,/**/-1, 1, -1,/**/1, 1, -1/**/, 1, -1, -1,// z负方向的面
    ];
    for (let index = 0; index < cube_model.length; index++) {
        cube_model[index] *= 1;
    }
    let dateArr = new Float32Array(cube_model);
    //
    let glbuffer = gl.createBuffer(); // 创建 buffer
    gl.bindBuffer(gl.ARRAY_BUFFER, glbuffer); // 绑定 buffer
    gl.bufferData(gl.ARRAY_BUFFER, dateArr, gl.STATIC_DRAW); // 上传顶点数据到 gl
    //
    let a_PointVertex_loc = gl.getAttribLocation(program, 'a_PointVertex');
    gl.vertexAttribPointer(a_PointVertex_loc, 3, gl.FLOAT, false, 0, 0); // 坐标
    gl.enableVertexAttribArray(a_PointVertex_loc);
}

function gl_init() {
    pointCanvas = document.getElementById('gl'); // 我们的纸

    gl = pointCanvas.getContext('webgl', { preserveDrawingBuffer: true }); // 我们的笔

    var vertex_shader_code = document.getElementById('vertex_shader').textContent;

    var vertex_shader = gl.createShader(gl.VERTEX_SHADER);
    gl.shaderSource(vertex_shader, vertex_shader_code);
    gl.compileShader(vertex_shader);
    // 检查shader错误
    const v_compiled = gl.getShaderParameter(vertex_shader, gl.COMPILE_STATUS);
    if (!v_compiled) {
        const v_theError = gl.getShaderInfoLog(vertex_shader);
        console.error(v_theError);
        gl.deleteShader(vertex_shader);
    }
    //
    var fragment_shader_code = document.getElementById('fragment_shader').textContent;
    var fragment_shader = gl.createShader(gl.FRAGMENT_SHADER);
    gl.shaderSource(fragment_shader, fragment_shader_code);
    gl.compileShader(fragment_shader);
    // 检查shader错误
    const f_compiled = gl.getShaderParameter(fragment_shader, gl.COMPILE_STATUS);
    if (!f_compiled) {
        const f_theError = gl.getShaderInfoLog(fragment_shader);
        console.error(f_theError);
        gl.deleteShader(fragment_shader);
    }
    //
    program = gl.createProgram();
    gl.attachShader(program, vertex_shader);
    gl.attachShader(program, fragment_shader);
    gl.linkProgram(program);
    gl.useProgram(program);

    uniforms_init(gl);
}

function uniforms_init(gl) {
    // uniforms
    u_Model_loc = gl.getUniformLocation(program, "u_Model");
    u_View_loc = gl.getUniformLocation(program, "u_View");
    u_Projection_loc = gl.getUniformLocation(program, "u_Projection");
}

var model_mat = [
    1, 0, 0, 0,//
    0, 1, 0, 0,//
    0, 0, 1, 0,//
    0, 0, 0, 1,//
];
var view_mat = [];
var projection_mat = [];

function uniforms_update(gl) {
    // model
    gl.uniformMatrix4fv(u_Model_loc, false, new Float32Array(model_mat));
    // view
    view_mat = mat4_get_lookat([-10, 10, 10], [0, 0, 0], [0, 1, 0]);
    gl.uniformMatrix4fv(u_View_loc, false, new Float32Array(view_mat));
    // perspective
    projection_mat = mat4_get_perspective(0.1, 100, 1, 45);
    gl.uniformMatrix4fv(u_Projection_loc, false, new Float32Array(projection_mat));
}

// gl更新逻辑
function gl_draw() {

    gl.enable(gl.CULL_FACE);
    gl.enable(gl.DEPTH_TEST);

    gl.clearColor(0, 0, 0, 1);
    gl.clear(gl.COLOR_BUFFER_BIT | gl.DEPTH_BUFFER_BIT);

    uniforms_update(gl);
    gl.drawArrays(gl.LINES, 0, 12 * 3);
}

Main();