三十一课代码(WebGL课程代码专用)

310 阅读3分钟

文件列表

  • index.html
  • grid_object.js
  • logic.js

index.html

<!doctype html>
<html>

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

</head>

<body>
    <p>
        <b>格子的x方向拉伸:</b>
        <input id="gridscalex" type="range" min="0.1" max="1" value="1" step="0.01" oninput="gl_draw()" />
        <b id="gridscalexvalue">0</b>
    </p>

    <p>
        <b>格子的y方向拉伸:</b>
        <input id="gridscaley" type="range" min="0.1" max="1" value="1" step="0.01" oninput="gl_draw()" />
        <b id="gridscaleyvalue">0</b>
    </p>

    <p>
        <b>格子的x方向位移:</b>
        <input id="gridposx" type="range" min="-1" max="1" value="0" step="0.01" oninput="gl_draw()" />
        <b id="gridposxvalue">0</b>
    </p>

    <p>
        <b>格子的y方向位移:</b>
        <input id="gridposy" type="range" min="-1" max="1" value="0" step="0.01" oninput="gl_draw()" />
        <b id="gridposyvalue">0</b>
    </p>

    <p>
        <b>格子的旋转(角度):</b>
        <input id="gridrotate" type="range" min="0" max="360" value="0" step="10" oninput="gl_draw()" />
        <b id="gridrotatevalue">0</b>
    </p>
    <p>
        <b>选取第几个格子</b>
        <select id="chosen" oninput="chosen_selected()">
            <option value="none">none</option>
            <option value="0">0</option>
            <option value="1">1</option>
            <option value="2">2</option>
            <option value="3">3</option>
            <option value="4">4</option>
            <option value="5">5</option>
            <option value="6">6</option>
        </select>
    </p>
    <p>
        <b>显示什么数字</b>
        <select id="digit" oninput="">
            <option value="0">0</option>
            <option value="1">1</option>
            <option value="2">2</option>
            <option value="3">3</option>
            <option value="4">4</option>
            <option value="5">5</option>
            <option value="6">6</option>
            <option value="7">7</option>
            <option value="8">8</option>
            <option value="9">9</option>
        </select>
    </p>


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

        attribute vec2 a_PointVertex; // 顶点坐标

        void main() {
          vec3 coord = u_all * vec3(a_PointVertex, 1.0);
          gl_Position = vec4(coord.x, coord.y, 0.0, 1.0);
        }
    </script>
    <script id="fragment_shader" type="myshader">
        // Fragment shader
        precision mediump int;
        precision mediump float;

        uniform vec3 u_color;

        void main() {
          gl_FragColor = vec4(u_color, 1.0);
        }
    </script>
    <script type="text/javascript" src="grid_object.js"></script>
    <script type="text/javascript" src="logic.js"></script>
</body>

</html>

grid_object.js


class GridObject {
    // 宽 高 x坐标 y坐标
    // 中心点是基准点
    constructor(scalex, scaley, posx, posy) {
        this.scalex = scalex;
        this.scaley = scaley;
        this.posx = posx;
        this.posy = posy;
        this.modelUpdated = false; // 模型是否更新,也就是说,是否需要重新绘制
        this.glbuffer = null;
        this.a_PointVertex = null;
        this.color = { R: 0, G: 0, B: 0 };
        this.rotate = 0;
    }
    // 生成模型数据
    // 六个点 两个三角形
    genData(gl) {
        this.data = [
            // 第一个三角形
            -1, -1, // 左下角点
            1, -1, // 右下角点
            1, 1, // 右上角点
            // 第二个三角形
            1, 1,  // 右上角点
            -1, 1,  // 左上角点
            -1, -1,  // 左下角点
        ];
        this.dataArr = new Float32Array(this.data);
        this.pointCount = 6; // 一个格子固定六个点 两个三角形

        if (this.glbuffer != null) { // 先删掉原来的buffer
            gl.deleteBuffer(this.glbuffer);
            this.a_PointVertex = null;
            this.a_Color = null;
        }
        this.glbuffer = gl.createBuffer(); // 在创建新的buffer
        gl.bindBuffer(gl.ARRAY_BUFFER, this.glbuffer);
        gl.bufferData(gl.ARRAY_BUFFER, this.dataArr, gl.STATIC_DRAW);
        this.modelUpdated = true;
    }
    render(gl, program) {
        gl.bindBuffer(gl.ARRAY_BUFFER, this.glbuffer);
        if (this.modelUpdated) {
            this.modelUpdated = false;
            if (this.a_PointVertex == null) {
                this.a_PointVertex = gl.getAttribLocation(program, 'a_PointVertex');
            }
        }
        //////////////////////////
        gl.vertexAttribPointer(this.a_PointVertex, 2, gl.FLOAT, false, 0, 0);
        gl.enableVertexAttribArray(this.a_PointVertex);
        gl.uniform3f(u_color, 1 - this.color.R, 1 - this.color.R, 1 - this.color.R);
        //
        let rad = ((2 * Math.PI) / 360) * this.rotate;
        gl.uniformMatrix3fv(u_all_loc, false, genMat3ForGL(this.scalex,
            this.scaley, rad, this.posx, this.posy
        ));
        gl.drawArrays(gl.TRIANGLES, 0, this.pointCount);
    }
}


logic.js

var pointCanvas = null;
var gl = null;

var u_all_loc = null;
var u_color = null;

var gridscalexDom = null;
var gridscalexvalueDom = null;

var gridscaleyDom = null;
var gridscaleyvalueDom = null;

var gridposxDom = null;
var gridposxvalueDom = null;

var gridposyDom = null;
var gridposyvalueDom = null;

var gridrotateDom = null;
var gridrotatevalueDom = null;

var digitDom = null;

var gridList = [];

var program = null;


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

function genMat3ForGL(a, b, alpha, A, B) {
    let mat3 = [
        a * Math.cos(alpha), a * Math.sin(alpha), 0,
        -b * Math.sin(alpha), b * Math.cos(alpha), 0,
        A, B, 1,
    ];
    return new Float32Array(mat3);
}

// 生成数码管的7个格子
function generateDigitGrid(gl) {
    //////////////////////////
    let idx = 0;
    for (; idx <= 6; idx++) {
        let digit0 = new GridObject(0.3, 0.1, 0, 0, 0);
        gridList.push(digit0);
    }
    gridList.forEach(element => {
        element.genData(gl);
    });
}

function gl_init() {
    pointCanvas = document.getElementById('tri'); // 我们的纸
    gl = pointCanvas.getContext('webgl', { preserveDrawingBuffer: true }); // 我们的笔

    generateDigitGrid(gl);

    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);
    // attributes
    // var a_PointVertex = gl.getAttribLocation(program, 'a_PointVertex');

    // gl.vertexAttribPointer(a_PointVertex, 2, gl.FLOAT, false, 16, 0);
    // gl.enableVertexAttribArray(a_PointVertex);

    // uniforms
    u_all_loc = gl.getUniformLocation(program, "u_all");
    u_color = gl.getUniformLocation(program, "u_color");

    gridscalexDom = document.getElementById("gridscalex");
    gridscalexvalueDom = document.getElementById("gridscalexvalue");
    gridscaleyDom = document.getElementById("gridscaley");
    gridscaleyvalueDom = document.getElementById("gridscaleyvalue");

    gridposxDom = document.getElementById("gridposx");
    gridposxvalueDom = document.getElementById("gridposxvalue");
    gridposyDom = document.getElementById("gridposy");
    gridposyvalueDom = document.getElementById("gridposyvalue");
    gridlightDom = document.getElementById("gridlight");
    gridlightvalueDom = document.getElementById("gridlightvalue");



    gridrotateDom = document.getElementById("gridrotate");
    gridrotatevalueDom = document.getElementById("gridrotatevalue");

    chosenDom = document.getElementById("chosen");

    digitDom = document.getElementById("digit");

}


function chosen_selected() {
    console.log(chosenDom.value);
    if (chosenDom.value === "none") {
        return;
    }
    //////////////////////////////////
    gridscalexDom.value = gridList[chosenDom.value].scalex;
    gridscaleyDom.value = gridList[chosenDom.value].scaley;
    gridposxDom.value = gridList[chosenDom.value].posx;
    gridposyDom.value = gridList[chosenDom.value].posy;

    gridrotateDom.value = gridList[chosenDom.value].rotate;

    gridscalexvalueDom.innerText = gridscalexDom.value;
    gridscaleyvalueDom.innerText = gridscaleyDom.value;

    gridposxvalueDom.innerText = gridposxDom.value;
    gridposyvalueDom.innerText = gridposyDom.value;

    gridrotatevalueDom.innerText = gridrotateDom.value;


}

// 根据要显示的数字,决定数码管的每一位的亮度
function digitEncode(digit) {
    if (digit == 0) {
        gridList[0].color.R = 1;
        gridList[1].color.R = 1;
        gridList[2].color.R = 1;
        gridList[3].color.R = 1;
        gridList[4].color.R = 1;
        gridList[5].color.R = 1;
        gridList[6].color.R = 0;
        return;
    }
    if (digit == 1) {
        gridList[0].color.R = 0;
        gridList[1].color.R = 1;
        gridList[2].color.R = 1;
        gridList[3].color.R = 0;
        gridList[4].color.R = 0;
        gridList[5].color.R = 0;
        gridList[6].color.R = 0;
        return;
    }
    if (digit == 2) {
        gridList[0].color.R = 1;
        gridList[1].color.R = 0;
        gridList[2].color.R = 1;
        gridList[3].color.R = 1;
        gridList[4].color.R = 0;
        gridList[5].color.R = 1;
        gridList[6].color.R = 1;
        return;
    }
    if (digit == 3) {
        gridList[0].color.R = 1;
        gridList[1].color.R = 1;
        gridList[2].color.R = 1;
        gridList[3].color.R = 1;
        gridList[4].color.R = 0;
        gridList[5].color.R = 0;
        gridList[6].color.R = 1;
        return;
    }
    if (digit == 4) {
        gridList[0].color.R = 0;
        gridList[1].color.R = 1;
        gridList[2].color.R = 1;
        gridList[3].color.R = 0;
        gridList[4].color.R = 1;
        gridList[5].color.R = 0;
        gridList[6].color.R = 1;
        return;
    }
    if (digit == 5) {
        gridList[0].color.R = 1;
        gridList[1].color.R = 1;
        gridList[2].color.R = 0;
        gridList[3].color.R = 1;
        gridList[4].color.R = 1;
        gridList[5].color.R = 0;
        gridList[6].color.R = 1;
        return;
    }
    if (digit == 6) {
        gridList[0].color.R = 1;
        gridList[1].color.R = 1;
        gridList[2].color.R = 0;
        gridList[3].color.R = 1;
        gridList[4].color.R = 1;
        gridList[5].color.R = 1;
        gridList[6].color.R = 1;
        return;
    }
    if (digit == 7) {
        gridList[0].color.R = 0;
        gridList[1].color.R = 1;
        gridList[2].color.R = 1;
        gridList[3].color.R = 1;
        gridList[4].color.R = 0;
        gridList[5].color.R = 0;
        gridList[6].color.R = 0;
        return;
    }
    if (digit == 8) {
        gridList[0].color.R = 1;
        gridList[1].color.R = 1;
        gridList[2].color.R = 1;
        gridList[3].color.R = 1;
        gridList[4].color.R = 1;
        gridList[5].color.R = 1;
        gridList[6].color.R = 1;
        return;
    }
    if (digit == 9) {
        gridList[0].color.R = 1;
        gridList[1].color.R = 1;
        gridList[2].color.R = 1;
        gridList[3].color.R = 1;
        gridList[4].color.R = 1;
        gridList[5].color.R = 0;
        gridList[6].color.R = 1;
        return;
    }
    //////////////////////////////

}

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

    gridscalexvalueDom.innerText = gridscalexDom.value;
    gridscaleyvalueDom.innerText = gridscaleyDom.value;

    gridposxvalueDom.innerText = gridposxDom.value;
    gridposyvalueDom.innerText = gridposyDom.value;

    gridrotatevalueDom.innerText = gridrotateDom.value;


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

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

    if (chosenDom.value !== "none") {

        gridList[chosenDom.value].scalex = gridscalexDom.value;
        gridList[chosenDom.value].scaley = gridscaleyDom.value;
        gridList[chosenDom.value].posx = gridposxDom.value;
        gridList[chosenDom.value].posy = gridposyDom.value;
        gridList[chosenDom.value].rotate = gridrotateDom.value;
    }


    digitEncode(digitDom.value);

    gridList.forEach(element => {
        element.render(gl, program);
    });

}

Main();