返回

WebGL 初探:坐标系统和 Canvas 画布创建指南

前端

引子:踏入 WebGL 的世界

对于渴望探索 3D 图形的 web 开发人员而言,WebGL 是一个不容错过的利器。与传统的 canvas2D 相比,WebGL 赋予我们操控复杂三维物体的强大能力。在踏上 WebGL 之旅之前,让我们从了解其坐标系统和创建 canvas 画布的基本步骤开始吧。

WebGL 坐标系统:解构 3D 空间

WebGL 使用左手坐标系,其原点位于画布的中心。X 轴向右延伸,Y 轴向上延伸,Z 轴向外延伸,形成一个三维空间。理解这个坐标系对于在 WebGL 中定位和变换对象至关重要。

创建 WebGL Canvas 画布

创建 WebGL 画布很简单,只需遵循以下步骤:

  1. 创建一个 <canvas> 元素并将其添加到 HTML 文档中:
<canvas id="webgl-canvas"></canvas>
  1. 获取画布的 WebGL 上下文:
const canvas = document.getElementById("webgl-canvas");
const gl = canvas.getContext("webgl");

实例演示:构建一个旋转立方体

现在,让我们用 WebGL 创建一个旋转立方体,以实践我们所学的内容:

// 创建一个立方体的顶点数据
const vertices = [
  // 前面
  -0.5, -0.5,  0.5,
  0.5, -0.5,  0.5,
  0.5,  0.5,  0.5,
  -0.5,  0.5,  0.5,

  // 后面
  -0.5, -0.5, -0.5,
  -0.5,  0.5, -0.5,
  0.5,  0.5, -0.5,
  0.5, -0.5, -0.5,

  // 顶部
  -0.5,  0.5,  0.5,
  -0.5,  0.5, -0.5,
  0.5,  0.5, -0.5,
  0.5,  0.5,  0.5,

  // 底部
  -0.5, -0.5,  0.5,
  0.5, -0.5,  0.5,
  0.5, -0.5, -0.5,
  -0.5, -0.5, -0.5,

  // 左侧
  -0.5, -0.5,  0.5,
  -0.5,  0.5,  0.5,
  -0.5,  0.5, -0.5,
  -0.5, -0.5, -0.5,

  // 右侧
  0.5, -0.5,  0.5,
  0.5,  0.5,  0.5,
  0.5,  0.5, -0.5,
  0.5, -0.5, -0.5
];

// 创建一个 WebGL 缓冲区对象 (VBO)
const vertexBuffer = gl.createBuffer();

// 绑定 VBO 并填充顶点数据
gl.bindBuffer(gl.ARRAY_BUFFER, vertexBuffer);
gl.bufferData(gl.ARRAY_BUFFER, new Float32Array(vertices), gl.STATIC_DRAW);

// 创建一个 WebGL 着色器程序
const vertexShaderSource = `
  attribute vec3 position;
  uniform mat4 modelViewMatrix;
  uniform mat4 projectionMatrix;
  void main() {
    gl_Position = projectionMatrix * modelViewMatrix * vec4(position, 1.0);
  }
`;
const fragmentShaderSource = `
  void main() {
    gl_FragColor = vec4(1.0, 0.0, 0.0, 1.0);
  }
`;
const vertexShader = gl.createShader(gl.VERTEX_SHADER);
const fragmentShader = gl.createShader(gl.FRAGMENT_SHADER);
gl.shaderSource(vertexShader, vertexShaderSource);
gl.shaderSource(fragmentShader, fragmentShaderSource);
gl.compileShader(vertexShader);
gl.compileShader(fragmentShader);
const program = gl.createProgram();
gl.attachShader(program, vertexShader);
gl.attachShader(program, fragmentShader);
gl.linkProgram(program);

// 获取顶点着色器中的位置属性
const positionAttribLocation = gl.getAttribLocation(program, "position");

// 创建一个 WebGL Uniform 对象
const modelViewMatrixLocation = gl.getUniformLocation(program, "modelViewMatrix");
const projectionMatrixLocation = gl.getUniformLocation(program, "projectionMatrix");

// 设置模型视图矩阵和投影矩阵
const modelViewMatrix = mat4.create();
const projectionMatrix = mat4.create();
mat4.translate(modelViewMatrix, modelViewMatrix, [0.0, 0.0, -2.0]);
mat4.perspective(projectionMatrix, 45 * (Math.PI / 180), canvas.width / canvas.height, 0.1, 10.0);

// 渲染循环
function render() {
  gl.clearColor(0.0, 0.0, 0.0, 1.0);
  gl.clear(gl.COLOR_BUFFER_BIT | gl.DEPTH_BUFFER_BIT);

  gl.useProgram(program);

  // 将顶点着色器中的位置属性与 VBO 绑定
  gl.bindBuffer(gl.ARRAY_BUFFER, vertexBuffer);
  gl.enableVertexAttribArray(positionAttribLocation);
  gl.vertexAttribPointer(positionAttribLocation, 3, gl.FLOAT, false, 0, 0);

  // 将模型视图矩阵和投影矩阵上传到着色器
  gl.uniformMatrix4fv(modelViewMatrixLocation, false, modelViewMatrix);
  gl.uniformMatrix4fv(projectionMatrixLocation, false, projectionMatrix);

  // 绘制立方体
  gl.drawArrays(gl.TRIANGLES, 0, vertices.length / 3);

  requestAnimationFrame(render);
}
render();

结论:解锁 WebGL 的无限可能

掌握了 WebGL 的坐标系统和 canvas 画布创建后,您已经踏上了探索 3D 图形的奇妙之旅。通过本文介绍的基础知识,您可以自由地构建和交互式地渲染各种 3D 对象。WebGL 的可能性是无限的,期待您解锁它的全部潜力!