返回

WebGL 初探:坐标系与立方体

前端

踏入 WebGL 的神奇世界,坐标系和立方体将成为我们探索之旅的指路明灯。今天,我们将深入了解这些基础概念,揭开它们在 WebGL 中发挥的重要作用。

坐标系:指引迷宫的指南针

WebGL 中有三个主要坐标系:

  • 世界坐标系: 万物之源,所有对象和变换的参考点。
  • 观察坐标系: 摄像机的视角,通过它我们观察场景。
  • 局部坐标系: 每个对象的私有空间,用于定义其自身位置和变换。

坐标转换:空间的舞蹈

理解坐标系的关键在于理解坐标是如何在它们之间转换的:

  1. 模型变换: 将局部坐标系移动、旋转或缩放以创建对象。
  2. 观察变换: 将观察坐标系移动、旋转或缩放以改变摄像机视角。
  3. 投影变换: 将 3D 场景投影到 2D 屏幕上。

立方体:三维空间的基石

立方体是 WebGL 中的一个基本三维几何体,由 6 个面、12 个边和 8 个顶点组成。它可以为我们提供一个直观的平台来探索坐标变换。

通过操纵立方体的顶点坐标,我们可以将其移动、旋转或缩放,从而更好地理解这些变换在三维空间中的影响。

实例:绘制旋转立方体

以下代码示例展示了如何在 WebGL 中绘制一个旋转立方体:

// 获取 WebGL 上下文
const gl = canvas.getContext("webgl");

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

  // 后面
  -1, -1, -1,
  -1,  1, -1,
   1,  1, -1,
   1, -1, -1,

  // 顶部
  -1,  1, -1,
  -1,  1,  1,
   1,  1,  1,
   1,  1, -1,

  // 底部
  -1, -1, -1,
   1, -1, -1,
   1, -1,  1,
  -1, -1,  1,

  // 左面
  -1, -1, -1,
  -1, -1,  1,
  -1,  1,  1,
  -1,  1, -1,

  // 右面
   1, -1, -1,
   1,  1, -1,
   1,  1,  1,
   1, -1,  1,
];

// 创建一个顶点缓冲区对象 (VBO)
const vertexBuffer = gl.createBuffer();
gl.bindBuffer(gl.ARRAY_BUFFER, vertexBuffer);
gl.bufferData(gl.ARRAY_BUFFER, new Float32Array(vertices), gl.STATIC_DRAW);

// 链接顶点着色器和片元着色器
const vertexShaderSource = `
  attribute vec3 position;
  uniform mat4 modelMatrix;
  uniform mat4 viewMatrix;
  uniform mat4 projectionMatrix;
  void main() {
    gl_Position = projectionMatrix * viewMatrix * modelMatrix * vec4(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);
gl.useProgram(program);

// 获取 uniform 变量的位置
const modelMatrixLocation = gl.getUniformLocation(program, "modelMatrix");
const viewMatrixLocation = gl.getUniformLocation(program, "viewMatrix");
const projectionMatrixLocation = gl.getUniformLocation(program, "projectionMatrix");

// 创建模型、观察和投影矩阵
const modelMatrix = new Float32Array(16);
const viewMatrix = new Float32Array(16);
const projectionMatrix = new Float32Array(16);
mat4.identity(modelMatrix);
mat4.lookAt(viewMatrix, [0, 0, 5], [0, 0, 0], [0, 1, 0]);
mat4.perspective(projectionMatrix, Math.PI / 4, canvas.width / canvas.height, 0.1, 100.0);

// 启用顶点属性数组
const positionLocation = gl.getAttribLocation(program, "position");
gl.enableVertexAttribArray(positionLocation);
gl.vertexAttribPointer(positionLocation, 3, gl.FLOAT, false, 0, 0);

// 绘制立方体
gl.clearColor(0.0, 0.0, 0.0, 1.0);
gl.clear(gl.COLOR_BUFFER_BIT | gl.DEPTH_BUFFER_BIT);
gl.enable(gl.DEPTH_TEST);

// 设置 uniform 变量
gl.uniformMatrix4fv(modelMatrixLocation, false, modelMatrix);
gl.uniformMatrix4fv(viewMatrixLocation, false, viewMatrix);
gl.uniformMatrix4fv(projectionMatrixLocation, false, projectionMatrix);

// 绘制调用
gl.drawArrays(gl.TRIANGLES, 0, vertices.length / 3);

结论

WebGL 的坐标系和立方体是我们理解三维场景的基础。通过掌握这些概念,我们可以绘制出复杂、交互式的图形,从而构建出引人入胜的体验。继续探索 WebGL 的世界,发现它无穷的可能性!