返回

WebGL矩阵操纵指南:释放图形学的真实潜力

前端

WebGL矩阵简介

WebGL中的矩阵是一个用于表示空间变换的数学对象,它可以物体的位移、旋转和缩放。矩阵通常由一个由16个数字排列成的4x4方阵表示,其中前3列对应于x、y和z轴的基向量,而第4列对应于平移向量。

变换矩阵

变换矩阵用于将物体从一个位置移动到另一个位置。变换矩阵可以分为三种类型:平移、旋转和缩放。

  • 平移矩阵 :平移矩阵用于将物体沿x、y或z轴移动一定距离。
  • 旋转矩阵 :旋转矩阵用于将物体绕x、y或z轴旋转一定角度。
  • 缩放矩阵 :缩放矩阵用于将物体沿x、y或z轴缩放一定比例。

实例代码:使用变换矩阵创建3D立方体

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

// 创建一个 WebGL 程序
const vertexShaderSource = `
  attribute vec3 a_position;
  uniform mat4 u_modelViewMatrix;
  uniform mat4 u_projectionMatrix;
  void main() {
    gl_Position = u_projectionMatrix * u_modelViewMatrix * vec4(a_position, 1.0);
  }
`;

const fragmentShaderSource = `
  precision mediump float;
  void main() {
    gl_FragColor = vec4(1.0, 0.0, 0.0, 1.0);
  }
`;

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);

// 告诉 WebGL 使用这个程序
gl.useProgram(program);

// 创建一个缓冲区对象来存储顶点数据
const positionBuffer = gl.createBuffer();
gl.bindBuffer(gl.ARRAY_BUFFER, positionBuffer);

const positions = [
  -1.0, -1.0,  1.0,
   1.0, -1.0,  1.0,
   1.0,  1.0,  1.0,
  -1.0,  1.0,  1.0,

  -1.0, -1.0, -1.0,
  -1.0,  1.0, -1.0,
   1.0,  1.0, -1.0,
   1.0, -1.0, -1.0,

  -1.0,  1.0, -1.0,
  -1.0,  1.0,  1.0,
   1.0,  1.0,  1.0,
   1.0,  1.0, -1.0,

  -1.0, -1.0, -1.0,
   1.0, -1.0, -1.0,
   1.0, -1.0,  1.0,
  -1.0, -1.0,  1.0,

  -1.0, -1.0, -1.0,
  -1.0,  1.0, -1.0,
  -1.0,  1.0,  1.0,
  -1.0, -1.0,  1.0,

   1.0, -1.0, -1.0,
   1.0,  1.0, -1.0,
   1.0,  1.0,  1.0,
   1.0, -1.0,  1.0,
];

gl.bufferData(gl.ARRAY_BUFFER, new Float32Array(positions), gl.STATIC_DRAW);

// 获取 attribute 变量的存储位置
const positionLocation = gl.getAttribLocation(program, "a_position");
gl.enableVertexAttribArray(positionLocation);
gl.vertexAttribPointer(positionLocation, 3, gl.FLOAT, false, 0, 0);

// 创建一个uniform变量来存储模型视图矩阵
const modelViewMatrixLocation = gl.getUniformLocation(program, "u_modelViewMatrix");

// 创建一个模型视图矩阵
const modelViewMatrix = mat4.create();
mat4.translate(modelViewMatrix, modelViewMatrix, [0.0, 0.0, -3.0]);

// 将模型视图矩阵传递给uniform变量
gl.uniformMatrix4fv(modelViewMatrixLocation, false, modelViewMatrix);

// 创建一个 uniform 变量来存储投影矩阵
const projectionMatrixLocation = gl.getUniformLocation(program, "u_projectionMatrix");

// 创建一个投影矩阵
const projectionMatrix = mat4.create();
mat4.perspective(projectionMatrix, 45 * (Math.PI / 180), canvas.width / canvas.height, 0.1, 100.0);

// 将投影矩阵传递给 uniform 变量
gl.uniformMatrix4fv(projectionMatrixLocation, false, projectionMatrix);

// 清空画布
gl.clearColor(0.0, 0.0, 0.0, 1.0);
gl.clear(gl.COLOR_BUFFER_BIT | gl.DEPTH_BUFFER_BIT);

// 绘制立方体
gl.drawArrays(gl.TRIANGLES, 0, 36);

透视矩阵

透视矩阵用于将3D空间投影到2D屏幕上。透视矩阵可以分为两种类型:正交投影和透视投影。

  • 正交投影 :正交投影将3D空间中的对象投影到一个平面上,无论对象离相机有多远,它们的大小都不会改变。
  • 透视投影 :透视投影将3D空间中的对象投影到一个透视平面上,离相机越近的对象看起来越大,离相机越远的对象看起来越小。

实例代码:使用透视矩阵创建3D场景

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

// 创建一个 WebGL 程序
const vertexShaderSource = `
  attribute vec3 a_position;
  uniform mat4 u_modelViewMatrix;
  uniform mat4 u_projectionMatrix;
  void main() {
    gl_Position = u_projectionMatrix * u_modelViewMatrix * vec4(a_position, 1.0);
  }
`;

const fragmentShaderSource = `
  precision mediump float;
  void main() {
    gl_FragColor = vec4(1.0, 0.0, 0.0, 1.0);
  }
`;

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);

// 告诉 WebGL 使用这个程序
gl.useProgram(program);

// 创建一个缓冲区对象来存储顶点数据
const positionBuffer = gl.createBuffer();
gl.bindBuffer(gl.ARRAY_BUFFER, positionBuffer);

const positions = [
  -1.0, -1.0,  1.0,
   1.0, -1.0,  1.0,
   1.0,  1.0,  1.0,
  -1.0,  1.0,  1.0,

  -1.0, -1.0, -1.0,
  -1.0,  1.0, -1.0,