demo实例是在前面立方体的纹理贴图的基础上修改的。不过这里用到了一些别人写好的库。库文件都放在我的github里面,有需要的可以自行下载。所以这里就只列出了跟立方体的纹理贴图demo不一样的地方。这个demo中用到了正射投影及矩阵运算。

# 1、顶点着色器代码

在这里是传入一个已经通过矩阵运算后的矩阵proj

<script id="vertexShader" type="x-shader/x-vertex">
    //浮点数设置为中等精度
    precision mediump float;
    attribute vec3 apos;
    uniform mat4 proj;
    attribute vec2 inUV;
    letying vec2 outUV;
    void main() {
        //两个旋转矩阵、顶点齐次坐标连乘
        gl_Position=proj*vec4(apos, 1);
        //插值处理
        outUV=inUV;
    }
</script>
1
2
3
4
5
6
7
8
9
10
11
12
13
14

# 2、JavaScript代码

除了下面两次不一样,其他的代码基本上是一样的。

  • WebGL上下文的获取及全局变量的定义
 let mvp = matrix.identity();
let Vector3 = window.lib3d.Vector3;
let Quaternion = window.lib3d.Quaternion;
function init() {
    let lastMouseX = 0, lastMouseY = 0;
    let offsetX = 0, offsetY = 0;
    let mousedown = false;
    //通过getElementById()方法获取canvas画布
    const canvas = document.getElementById('webgl');
    // resizeCanvas(canvas);
    //通过方法getContext()获取WebGL上下文
    const gl = canvas.getContext('webgl');
    const aspect = canvas.width / canvas.height;
    const projectionMatrix = matrix.ortho(-aspect * 1, aspect * 1, -1, 1, 500, -500);
    let lastMatrix = matrix.identity();
    let tempMatrix = matrix.identity();
    //顶点着色器源码
    const vertexShaderSource = document.getElementById('vertexShader').innerText;

    //片元着色器源码
    const fragShaderSource = document.getElementById('fragmentShader').innerText;
    //初始化着色器
    const program = initShader(gl, vertexShaderSource, fragShaderSource);
    initBuffer(gl, program);
    rotate(gl,canvas);
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
  • 鼠标控制旋转的函数 通过监听鼠标的mousedown,mousemove,mouseup来不断计算运动后的矩阵。在mousemove事件中不断渲染GPU,使的立方体不断的旋转。这里用到了矩阵的四元数运算。
function rotate(gl, canvas, program) {
    let lastQ = new Quaternion();
    let currentQ = new Quaternion();
    canvas.addEventListener('mousedown', (event) => {
        mousedown = true;
        const { clientX, clientY } = event;
        lastMouseX = clientX;
        lastMouseY = clientY;
        canvas.addEventListener('mousemove', (event) => {
            if (!mousedown) return;
            const { clientX, clientY } = event;
            offsetX = (clientX - lastMouseX);
            offsetY = (clientY - lastMouseY);
            let l = Math.sqrt(offsetX * offsetX + offsetY * offsetY);
            if (l == 0) {
                return;
            }
            let tempQ = Quaternion.fromRotation(
                { x: offsetY / l, y: offsetX / l, z: 0 },
                l / 2
            );
            currentQ = Quaternion.multiplyQuaternions(tempQ, lastQ);
            mvp = Quaternion.makeRotationFromQuaternion(currentQ);
            render(gl, program);
        })
        canvas.addEventListener('mouseup', () => {
            mousedown = false;
            // matrix.cloneMatrix(mvp, lastMatrix);
            Object.assign(lastQ, currentQ);
        })
    })
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
  • WebGL渲染函数 这里多了个矩阵赋值的操作。
 function render(gl, program, count = 36) {
    const proj = gl.getUniformLocation(program, 'proj');
    gl.uniformMatrix4fv(proj, false, mvp);
    //设置清屏颜色为黑色。
    gl.clearColor(0, 0, 0, 1);
    gl.clear(gl.COLOR_BUFFER_BIT);
    gl.drawElements(gl.TRIANGLES, count, gl.UNSIGNED_SHORT, 0);
}
1
2
3
4
5
6
7
8

参考
WebGL零基础入门教程(郭隆邦) (opens new window)
WebGL 入门与实践 (opens new window)
WebGL官方文档 (opens new window)

Last Updated: 6/24/2024, 6:04:56 PM