返回

WebGL图形变换轻松学,掌握矩阵,纵横3D世界

前端

序言

大家好,我是广州小井,上一节我们初步认识了矩阵的数学基础,但我们还不知道学来干嘛?那这一节我们马不停蹄的来应用矩阵进行实战!

矩阵在WebGL中的作用

在WebGL中,矩阵主要用于对物体进行变换,包括平移、旋转和缩放。通过矩阵变换,我们可以轻松实现物体在3D世界中的移动、旋转和缩放效果。

平移矩阵

平移矩阵用于将物体在X、Y和Z轴上进行平移。平移矩阵的数学形式为:

[1 0 0 x]
[0 1 0 y]
[0 0 1 z]
[0 0 0 1]

其中,x、y和z是物体在X、Y和Z轴上的平移距离。

旋转矩阵

旋转矩阵用于将物体绕X、Y和Z轴进行旋转。旋转矩阵的数学形式为:

[cosθ 0 sinθ 0]
[0 1 0 0]
[-sinθ 0 cosθ 0]
[0 0 0 1]

其中,θ是物体绕X轴旋转的角度,φ是物体绕Y轴旋转的角度,ω是物体绕Z轴旋转的角度。

缩放矩阵

缩放矩阵用于将物体在X、Y和Z轴上进行缩放。缩放矩阵的数学形式为:

[sx 0 0 0]
[0 sy 0 0]
[0 0 sz 0]
[0 0 0 1]

其中,sx、sy和sz是物体在X、Y和Z轴上的缩放比例。

应用实例

现在,我们已经了解了平移矩阵、旋转矩阵和缩放矩阵的基本知识,接下来,我们来看看如何将它们应用到WebGL中。

首先,我们需要创建一个WebGL上下文,然后加载顶点着色器和片段着色器。接着,我们需要创建一个缓冲区对象来存储顶点数据,并创建一个纹理对象来存储纹理数据。最后,我们需要编写JavaScript代码来控制矩阵变换,并将其应用到物体上。

// 创建WebGL上下文
const canvas = document.getElementById('canvas');
const gl = canvas.getContext('webgl');

// 加载顶点着色器和片段着色器
const vertexShaderSource = `
    attribute vec3 position;
    attribute vec2 texcoord;
    varying vec2 vTexcoord;

    uniform mat4 modelMatrix;
    uniform mat4 viewMatrix;
    uniform mat4 projectionMatrix;

    void main() {
        gl_Position = projectionMatrix * viewMatrix * modelMatrix * vec4(position, 1.0);
        vTexcoord = texcoord;
    }
`;

const fragmentShaderSource = `
    precision mediump float;
    varying vec2 vTexcoord;

    uniform sampler2D texture;

    void main() {
        gl_FragColor = texture2D(texture, vTexcoord);
    }
`;

const vertexShader = gl.createShader(gl.VERTEX_SHADER);
gl.shaderSource(vertexShader, vertexShaderSource);
gl.compileShader(vertexShader);

const fragmentShader = gl.createShader(gl.FRAGMENT_SHADER);
gl.shaderSource(fragmentShader, fragmentShaderSource);
gl.compileShader(fragmentShader);

// 创建程序对象
const program = gl.createProgram();
gl.attachShader(program, vertexShader);
gl.attachShader(program, fragmentShader);
gl.linkProgram(program);

// 获取属性位置
const positionAttributeLocation = gl.getAttribLocation(program, 'position');
const texcoordAttributeLocation = gl.getAttribLocation(program, 'texcoord');

// 获取uniform位置
const modelMatrixUniformLocation = gl.getUniformLocation(program, 'modelMatrix');
const viewMatrixUniformLocation = gl.getUniformLocation(program, 'viewMatrix');
const projectionMatrixUniformLocation = gl.getUniformLocation(program, 'projectionMatrix');

// 创建缓冲区对象
const positionBuffer = gl.createBuffer();
gl.bindBuffer(gl.ARRAY_BUFFER, positionBuffer);
gl.bufferData(gl.ARRAY_BUFFER, new Float32Array([
    -0.5, -0.5, 0.0,
    0.5, -0.5, 0.0,
    0.0, 0.5, 0.0
]), gl.STATIC_DRAW);

const texcoordBuffer = gl.createBuffer();
gl.bindBuffer(gl.ARRAY_BUFFER, texcoordBuffer);
gl.bufferData(gl.ARRAY_BUFFER, new Float32Array([
    0.0, 0.0,
    1.0, 0.0,
    0.5, 1.0
]), gl.STATIC_DRAW);

// 创建纹理对象
const texture = gl.createTexture();
gl.bindTexture(gl.TEXTURE_2D, texture);
gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_S, gl.CLAMP_TO_EDGE);
gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_T, gl.CLAMP_TO_EDGE);
gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, gl.LINEAR);
gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MAG_FILTER, gl.LINEAR);
gl.texImage2D(gl.TEXTURE_2D, 0, gl.RGBA, 1, 1, 0, gl.RGBA, gl.UNSIGNED_BYTE, new Uint8Array([
    255, 0, 0, 255
]));

// 设置视口
gl.viewport(0, 0, canvas.width, canvas.height);

// 清除颜色缓冲区
gl.clearColor(0.0, 0.0, 0.0, 1.0);
gl.clear(gl.COLOR_BUFFER_BIT);

// 启用顶点属性
gl.enableVertexAttribArray(positionAttributeLocation);
gl.bindBuffer(gl.ARRAY_BUFFER, positionBuffer);
gl.vertexAttribPointer(positionAttributeLocation, 3, gl.FLOAT, false, 0, 0);

gl.enableVertexAttribArray(texcoordAttributeLocation);
gl.bindBuffer(gl.ARRAY_BUFFER, texcoordBuffer);
gl.vertexAttribPointer(texcoordAttributeLocation, 2, gl.FLOAT, false, 0, 0);

// 激活程序对象
gl.useProgram(program);

// 设置uniform值
const modelMatrix = new Float32Array([
    1.0, 0.0, 0.0, 0.0,
    0.0, 1.0, 0.0, 0.0,
    0.0, 0.0, 1.0, 0.0,
    0.0, 0.0, 0.0, 1.0
]);
gl.uniformMatrix4fv(modelMatrixUniformLocation, false, modelMatrix);

const viewMatrix = new Float32Array([
    1.0, 0.0, 0.0, 0.0,
    0.0, 1.0, 0.0, 0.0,
    0.0, 0.0, 1.0, 0.0,
    0.0, 0.0, 0.0, 1.0
]);
gl.uniformMatrix4fv(viewMatrixUniformLocation, false, viewMatrix);

const projectionMatrix = new Float32Array([
    1.0, 0.0, 0.0, 0.0,
    0.0, 1.0, 0.0, 0.0,
    0.0, 0.0, 1.0, 0.0,
    0.0, 0.0, 0.0, 1.0
]);
gl.uniformMatrix4fv(projectionMatrixUniformLocation, false, projectionMatrix);

// 绑定纹理
gl.bindTexture(gl.TEXTURE_2D, texture);

// 绘制三角形
gl.drawArrays(gl.TRIANGLES, 0, 3);

这段代码首先创建了一个WebGL上下文,然后加载顶点着色器和片段着色器。接着,它创建了一个缓冲区对象来存储顶点数据,并创建一个纹理对象来存储纹理数据。最后,它编写了JavaScript代码来控制矩阵变换,并将其应用到物体上。

结语

通过矩阵变换,我们可以轻松实现物体在3D世界中的移动、旋转和缩放