第二章:WebGL 核心概念 第二章:WebGL 核心概念 引言 WebGL (Web Graphics Library) 是一项革命性的技术,它允许我们在网页浏览器中直接渲染高性能的交互式 2D 和 3D 图形,而无需安装任何插件。 作为基于 OpenGL ES 2.0 的 JavaScript API,WebGL 将图形处理单元 (GPU) 的强大能力带入 Web 开发领域,为创建复杂的视觉效果、游戏、数据可视化以及各种图形密集型应用开辟了无限可能。 理解 WebGL 的核心概念是掌握这项技术的基石。 本章将深入剖析 WebGL 的关键组成部分,包括 WebGL 上下文、着色器、缓冲区对象、顶点属性、Uniform 变量、绘制图元以及坐标系统与变换等核心概念。
第二章:WebGL 核心概念
引言
WebGL (Web Graphics Library) 是一项革命性的技术,它允许我们在网页浏览器中直接渲染高性能的交互式 2D 和 3D 图形,而无需安装任何插件。 作为基于 OpenGL ES 2.0 的 JavaScript API,WebGL 将图形处理单元 (GPU) 的强大能力带入 Web 开发领域,为创建复杂的视觉效果、游戏、数据可视化以及各种图形密集型应用开辟了无限可能。
理解 WebGL 的核心概念是掌握这项技术的基石。 本章将深入剖析 WebGL 的关键组成部分,包括 WebGL 上下文、着色器、缓冲区对象、顶点属性、Uniform 变量、绘制图元以及坐标系统与变换等核心概念。 通过理论讲解与实践代码相结合的方式,我们将逐步揭开 WebGL 的神秘面纱,为后续深入学习和应用 WebGL 打下坚实的基础。
1. WebGL 上下文 (WebGL Context)
WebGL 的一切操作都始于 WebGL 上下文 (WebGL Context)。 可以将 WebGL 上下文视为 WebGL 程序的“画布”或“舞台”,所有的图形渲染操作都将在这个上下文中进行。 要使用 WebGL,首先需要获取 WebGL 上下文。
获取 WebGL 上下文通常通过 HTML5 的 <canvas> 元素来实现。 <canvas> 元素本身只是一个用于绘图的容器,我们需要通过 JavaScript 代码获取其 WebGL 上下文,才能使用 WebGL API 进行图形渲染。
以下代码演示了如何获取 WebGL 上下文:
<!DOCTYPE html> <html> <head> <title>WebGL Context Example</title> <style> body { margin: 0; } canvas { display: block; } </style> </head> <body> <canvas id="glCanvas" width="640" height="480"></canvas> <script> const canvas = document.getElementById("glCanvas"); const gl = canvas.getContext("webgl"); // 获取 WebGL 上下文 if (!gl) { alert("Unable to initialize WebGL. Your browser may not support it."); } else { console.log("WebGL context initialized successfully!"); // 在这里可以开始进行 WebGL 渲染操作 } </script> </body> </html>
代码详解:
<canvas id="glCanvas" width="640" height="480"></canvas>: 在 HTML 中创建一个 <canvas> 元素,并设置了 id、width 和 height 属性。id 用于在 JavaScript 中获取该元素,width 和 height 定义了画布的尺寸。
document.getElementById("glCanvas"): 使用 JavaScript 获取 id 为 "glCanvas" 的 <canvas> 元素。
canvas.getContext("webgl"): 调用 canvas 元素的 getContext("webgl") 方法来尝试获取 WebGL 上下文。 如果浏览器支持 WebGL,并且初始化成功,该方法将返回一个 WebGL 上下文对象 (gl);否则,返回 null。
if (!gl) { ... } else { ... }: 检查 gl 是否为 null,以判断 WebGL 上下文是否成功获取。 如果获取失败,则弹出警告信息;如果成功,则在控制台输出成功信息,并可以在 else 代码块中开始进行 WebGL 渲染操作。
重要提示:
getContext("webgl2") 可以尝试获取 WebGL 2.0 上下文。 WebGL 2.0 是 WebGL 的升级版本,提供了更多更强大的功能,但兼容性可能不如 WebGL 1.0 (即 getContext("webgl"))。
如果 getContext("webgl") 返回 null,可能是由于浏览器不支持 WebGL,或者用户的显卡驱动程序存在问题。
2. 着色器与 GLSL (Shaders & GLSL)
WebGL 渲染管线的核心是 着色器 (Shaders)。 着色器是用 GLSL (OpenGL Shading Language) 编写的小程序,运行在 GPU 上,负责处理图形渲染的各个阶段。 WebGL 主要使用两种类型的着色器:
顶点着色器 (Vertex Shader): 处理顶点数据,例如顶点的位置、颜色、法线等。 顶点着色器负责将顶点坐标从模型空间转换到裁剪空间,并可以进行各种顶点属性的计算和处理。 每个顶点都会执行一次顶点着色器。
片元着色器 (Fragment Shader): 也称为像素着色器 (Pixel Shader),处理光栅化后的每个片元 (Fragment,可以理解为像素)。 片元着色器负责计算每个像素的最终颜色,包括纹理采样、光照计算、颜色混合等。 每个像素都会执行一次片元着色器。
GLSL (OpenGL Shading Language) 是一种类似于 C 语法的编程语言,专门用于编写着色器程序。 GLSL 提供了丰富的内置函数和数据类型,用于图形计算和操作。
着色器程序结构:
一个基本的着色器程序通常包含以下几个部分:
版本声明 (Version Directive): 指定 GLSL 版本,例如 #version 100 (WebGL 1.0) 或 #version 300 es (WebGL 2.0)。
精度限定符 (Precision Qualifiers): 指定变量的精度,例如 highp float (高精度浮点数), mediump float (中精度浮点数), lowp float (低精度浮点数)。 精度会影响计算速度和精度。
输入变量 (Input Variables): 从 WebGL 程序传入到着色器的变量,例如顶点属性 (attributes) 和 Uniform 变量 (uniforms)。 在顶点着色器中,输入变量通常是顶点属性;在片元着色器中,输入变量可以是顶点着色器传递过来的 varying 变量或 Uniform 变量。
输出变量 (Output Variables): 从着色器输出到 WebGL 程序或下一个渲染阶段的变量。 顶点着色器的输出变量通常是 gl_Position (裁剪空间顶点坐标) 和 varying 变量;片元着色器的输出变量通常是 gl_FragColor (片元颜色)。
Uniform 变量 (Uniform Variables): 全局只读变量,在整个渲染过程中保持不变。 Uniform 变量通常用于传递变换矩阵、颜色、光照参数等全局数据。
Varying 变量 (Varying Variables): 顶点着色器传递到片元着色器的变量。 Varying 变量在光栅化过程中会被插值,因此片元着色器接收到的 varying 变量值是插值后的结果。
主函数 (main Function): 着色器程序的入口函数,类似于 C 语言的 main 函数。 着色器程序的所有逻辑都写在主函数中。
顶点着色器示例 (vertex shader):
#version 100 // GLSL ES 1.0 attribute vec4 aVertexPosition; // 顶点位置属性 uniform mat4 uModelViewMatrix; // 模型视图矩阵 uniform mat4 uProjectionMatrix; // 投影矩阵 void main() { gl_Position = uProjectionMatrix * uModelViewMatrix * aVertexPosition; // 计算裁剪空间顶点坐标 }
片元着色器示例 (fragment shader):
#version 100 // GLSL ES 1.0 precision mediump float; // 设置浮点数精度为 mediump void main() { gl_FragColor = vec4(1.0, 0.0, 0.0, 1.0); // 设置片元颜色为红色 (RGBA: 1, 0, 0, 1) }
代码详解:
顶点着色器:
#version 100: 指定 GLSL ES 1.0 版本。
attribute vec4 aVertexPosition: 声明一个 vec4 类型的顶点属性 aVertexPosition,用于接收顶点位置数据。attribute 关键字表示这是一个顶点属性。
uniform mat4 uModelViewMatrix, uniform mat4 uProjectionMatrix: 声明两个 mat4 类型的 Uniform 变量 uModelViewMatrix 和 uProjectionMatrix,分别用于接收模型视图矩阵和投影矩阵。uniform 关键字表示这是一个 Uniform 变量。
gl_Position = uProjectionMatrix * uModelViewMatrix * aVertexPosition: 在 main 函数中,计算裁剪空间顶点坐标,并将结果赋值给内置变量 gl_Position。 矩阵乘法顺序为:投影矩阵 * 模型视图矩阵 * 顶点位置。
片元着色器:
#version 100: 指定 GLSL ES 1.0 版本。
precision mediump float: 设置浮点数精度为 mediump。
gl_FragColor = vec4(1.0, 0.0, 0.0, 1.0): 在 main 函数中,设置片元颜色为红色,并将结果赋值给内置变量 gl_FragColor。 vec4(1.0, 0.0, 0.0, 1.0) 表示红色 (R=1, G=0, B=0, A=1)。
着色器编译与链接:
在 WebGL 中使用着色器,需要经过以下步骤:
创建着色器对象 (Create Shader Object): 使用 gl.createShader() 创建顶点着色器对象和片元着色器对象。
提供着色器源代码 (Shader Source Code): 使用 gl.shaderSource() 将 GLSL 源代码字符串加载到着色器对象中。
编译着色器 (Compile Shader): 使用 gl.compileShader() 编译着色器代码。 编译过程中会检查语法错误。
创建程序对象 (Create Program Object): 使用 gl.createProgram() 创建程序对象。 程序对象是管理着色器的容器。
附加着色器 (Attach Shader): 使用 gl.attachShader() 将编译好的顶点着色器和片元着色器附加到程序对象。
链接程序 (Link Program): 使用 gl.linkProgram() 链接程序对象。 链接过程会将顶点着色器和片元着色器组合成一个可执行的程序。
使用程序 (Use Program): 使用 gl.useProgram() 激活程序对象,使其成为当前 WebGL 上下文使用的着色器程序。
代码示例 (着色器编译与链接):
function initShaderProgram(gl, vsSource, fsSource) { const vertexShader = loadShader(gl, gl.VERTEX_SHADER, vsSource); const fragmentShader = loadShader(gl, gl.FRAGMENT_SHADER, fsSource); const shaderProgram = gl.createProgram(); gl.attachShader(shaderProgram, vertexShader); gl.attachShader(shaderProgram, fragmentShader); gl.linkProgram(shaderProgram); if (!gl.getProgramParameter(shaderProgram, gl.LINK_STATUS)) { alert('Unable to initialize the shader program: ' + gl.getProgramInfoLog(shaderProgram)); return null; } return shaderProgram; } function loadShader(gl, type, source) { const shader = gl.createShader(type); gl.shaderSource(shader, source); gl.compileShader(shader); if (!gl.getShaderParameter(shader, gl.COMPILE_STATUS)) { alert('An error occurred compiling the shaders: ' + gl.getShaderInfoLog(shader)); gl.deleteShader(shader); return null; } return shader; } // ... (顶点着色器源代码 vsSource 和片元着色器源代码 fsSource 定义) ... const shaderProgram = initShaderProgram(gl, vsSource, fsSource); if (shaderProgram) { gl.useProgram(shaderProgram); // 激活程序 // ... (后续渲染操作) ... }
代码详解:
initShaderProgram(gl, vsSource, fsSource) 函数负责初始化着色器程序,接收 WebGL 上下文 gl、顶点着色器源代码 vsSource 和片元着色器源代码 fsSource 作为参数。
loadShader(gl, type, source) 函数负责加载和编译单个着色器,接收 WebGL 上下文 gl、着色器类型 type (gl.VERTEX_SHADER 或 gl.FRAGMENT_SHADER) 和着色器源代码 source 作为参数。
gl.createProgram(), gl.attachShader(), gl.linkProgram(), gl.getProgramParameter(), gl.getProgramInfoLog(), gl.getShaderParameter(), gl.getShaderInfoLog(), gl.deleteShader(), gl.useProgram(): 这些都是 WebGL API 函数,用于着色器对象的创建、源代码加载、编译、程序对象的创建、着色器附加、程序链接、状态查询和错误信息获取。
3. 缓冲区对象 (Buffer Objects)
缓冲区对象 (Buffer Objects) 是 WebGL 中用于存储顶点数据、索引数据等数据的容器。 缓冲区对象存储在 GPU 的显存中,可以高效地将数据传递给着色器,加速图形渲染。
WebGL 中常用的缓冲区对象类型包括:
顶点缓冲区对象 (Vertex Buffer Object, VBO): 存储顶点属性数据,例如顶点位置、颜色、法线、纹理坐标等。 每个顶点属性通常对应一个 VBO。
索引缓冲区对象 (Index Buffer Object, IBO): 存储顶点索引数据,用于指定绘制图元时顶点的顺序。 使用索引缓冲区可以减少顶点数据的重复,提高渲染效率。
创建和使用缓冲区对象:
创建缓冲区对象 (Create Buffer Object): 使用 gl.createBuffer() 创建缓冲区对象。
绑定缓冲区对象 (Bind Buffer Object): 使用 gl.bindBuffer() 将缓冲区对象绑定到指定的缓冲区目标 (例如 gl.ARRAY_BUFFER 用于顶点缓冲区,gl.ELEMENT_ARRAY_BUFFER 用于索引缓冲区)。 绑定缓冲区后,后续的缓冲区操作都将作用于当前绑定的缓冲区对象。
向缓冲区对象写入数据 (Buffer Data): 使用 gl.bufferData() 将数据写入缓冲区对象。 gl.bufferData() 方法接收以下参数:
target: 缓冲区目标,例如 gl.ARRAY_BUFFER 或 gl.ELEMENT_ARRAY_BUFFER。
data: 要写入缓冲区的数据,通常是 Float32Array (浮点数数组), Uint16Array (16位无符号整数数组), Uint8Array (8位无符号整数数组) 等类型的数组。
usage: 数据的使用方式,例如 gl.STATIC_DRAW (数据只写入一次,多次绘制), gl.DYNAMIC_DRAW (数据可能频繁更新), gl.STREAM_DRAW (数据每次绘制都更新)。 gl.STATIC_DRAW 通常用于静态几何体,gl.DYNAMIC_DRAW 或 gl.STREAM_DRAW 用于动态几何体。
启用顶点属性数组 (Enable Vertex Attribute Array): 对于顶点缓冲区,需要使用 gl.enableVertexAttribArray() 启用对应的顶点属性数组。
指定顶点属性的解析方式 (Vertex Attribute Pointer): 使用 gl.vertexAttribPointer() 指定顶点属性数据的解析方式,包括:
index: 顶点属性的索引 (与顶点着色器中的 attribute 变量对应)。
size: 每个顶点属性的分量数 (例如 3 表示 vec3, 4 表示 vec4)。
type: 数据类型,例如 gl.FLOAT (浮点数), gl.UNSIGNED_SHORT (16位无符号整数), gl.UNSIGNED_BYTE (8位无符号整数)。
normalized: 是否将非浮点数数据归一化到 [0, 1] 或 [-1, 1] 范围。
stride: 顶点属性之间的字节偏移量 (用于 interleaved vertex data)。
offset: 顶点属性在缓冲区中的起始字节偏移量。
代码示例 (顶点缓冲区和索引缓冲区):
// 顶点数据 (三角形三个顶点的坐标) const positions = [ -1.0, -1.0, // 顶点 1 1.0, -1.0, // 顶点 2 0.0, 1.0 // 顶点 3 ]; // 索引数据 (三角形三个顶点的索引) const indices = [ 0, 1, 2 ]; // 创建顶点缓冲区对象 const positionBuffer = gl.createBuffer(); gl.bindBuffer(gl.ARRAY_BUFFER, positionBuffer); gl.bufferData(gl.ARRAY_BUFFER, new Float32Array(positions), gl.STATIC_DRAW); // 创建索引缓冲区对象 const indexBuffer = gl.createBuffer(); gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, indexBuffer); gl.bufferData(gl.ELEMENT_ARRAY_BUFFER, new Uint16Array(indices), gl.STATIC_DRAW); // ... (获取顶点属性位置 aVertexPosition 的 location) ... const positionAttributeLocation = gl.getAttribLocation(shaderProgram, 'aVertexPosition'); gl.enableVertexAttribArray(positionAttributeLocation); // 启用顶点属性数组 gl.bindBuffer(gl.ARRAY_BUFFER, positionBuffer); // 绑定顶点缓冲区 gl.vertexAttribPointer(positionAttributeLocation, 2, gl.FLOAT, false, 0, 0); // 指定顶点属性解析方式 // ... (后续绘制操作,使用 gl.drawElements() 绘制索引图元) ...
代码详解:
positions 数组存储三角形三个顶点的 x, y 坐标。
indices 数组存储三角形三个顶点的索引,指向 positions 数组中的顶点。
gl.createBuffer(), gl.bindBuffer(), gl.bufferData(): 创建、绑定和写入顶点缓冲区和索引缓冲区。
gl.getAttribLocation(shaderProgram, 'aVertexPosition'): 获取顶点着色器中 attribute vec4 aVertexPosition 变量的 location (索引)。
gl.enableVertexAttribArray(positionAttributeLocation): 启用索引为 positionAttributeLocation 的顶点属性数组。
gl.vertexAttribPointer(positionAttributeLocation, 2, gl.FLOAT, false, 0, 0): 指定顶点属性 aVertexPosition 的解析方式:
positionAttributeLocation: 顶点属性索引。
2: 每个顶点属性有两个分量 (x, y)。
gl.FLOAT: 数据类型为浮点数。
false: 不进行归一化。
0: stride 为 0,表示顶点属性紧密排列。
0: offset 为 0,表示顶点属性从缓冲区起始位置开始读取。
4. 顶点属性 (Vertex Attributes)
顶点属性 (Vertex Attributes) 是传递给顶点着色器的输入数据。 每个顶点可以拥有多个属性,例如位置、颜色、法线、纹理坐标等。 顶点属性数据存储在顶点缓冲区对象 (VBO) 中,并通过 attribute 变量在顶点着色器中声明和使用。
在 WebGL 程序中,我们需要完成以下步骤来使用顶点属性:
在顶点着色器中声明 attribute 变量: 例如 attribute vec4 aVertexPosition; 声明一个 vec4 类型的顶点位置属性。
创建顶点缓冲区对象 (VBO) 并写入顶点属性数据: 如前面缓冲区对象部分所述。
获取 attribute 变量的 location: 使用 gl.getAttribLocation(shaderProgram, 'aVertexPosition') 获取 attribute 变量在着色器程序中的 location (索引)。
启用顶点属性数组: 使用 gl.enableVertexAttribArray(location) 启用对应 location 的顶点属性数组。
指定顶点属性的解析方式: 使用 gl.vertexAttribPointer(location, size, type, normalized, stride, offset) 指定顶点属性数据的解析方式。
5. Uniform 变量 (Uniform Variables)
Uniform 变量 (Uniform Variables) 是全局只读变量,在整个渲染过程中保持不变。 Uniform 变量通常用于传递变换矩阵、颜色、光照参数等全局数据给着色器。 Uniform 变量在顶点着色器和片元着色器中都可以声明和使用。
在 WebGL 程序中使用 Uniform 变量的步骤:
在顶点着色器或片元着色器中声明 uniform 变量: 例如 uniform mat4 uModelViewMatrix; 声明一个 mat4 类型的模型视图矩阵 Uniform 变量。
获取 uniform 变量的 location: 使用 gl.getUniformLocation(shaderProgram, 'uModelViewMatrix') 获取 uniform 变量在着色器程序中的 location。
设置 uniform 变量的值: 使用 gl.uniformXXX() 函数设置 uniform 变量的值,其中 XXX 代表 Uniform 变量的数据类型,例如 gl.uniformMatrix4fv() (设置 4x4 矩阵), gl.uniform4fv() (设置 vec4), gl.uniform1f() (设置 float), gl.uniform1i() (设置 int) 等。 gl.uniformXXX() 函数接收以下参数:
location: uniform 变量的 location。
value: 要设置的 uniform 变量的值,通常是数组或单个数值。
代码示例 (Uniform 变量 - 矩阵变换):
// ... (着色器程序初始化) ... const modelViewMatrixLocation = gl.getUniformLocation(shaderProgram, 'uModelViewMatrix'); const projectionMatrixLocation = gl.getUniformLocation(shaderProgram, 'uProjectionMatrix'); // ... (计算模型视图矩阵和投影矩阵,例如使用 glMatrix 库) ... const modelViewMatrix = mat4.create(); const projectionMatrix = mat4.perspective(mat4.create(), 45 * Math.PI / 180, canvas.clientWidth / canvas.clientHeight, 0.1, 100.0); mat4.translate(modelViewMatrix, modelViewMatrix, [0.0, 0.0, -6.0]); // 将模型沿 Z 轴平移 -6 个单位 // 设置 Uniform 变量的值 gl.uniformMatrix4fv(modelViewMatrixLocation, false, modelViewMatrix); // 传递模型视图矩阵 gl.uniformMatrix4fv(projectionMatrixLocation, false, projectionMatrix); // 传递投影矩阵 // ... (绘制操作) ...
代码详解:
gl.getUniformLocation(shaderProgram, 'uModelViewMatrix'), gl.getUniformLocation(shaderProgram, 'uProjectionMatrix'): 获取着色器程序中 uniform mat4 uModelViewMatrix 和 uniform mat4 uProjectionMatrix 变量的 location。
mat4.create(), mat4.perspective(), mat4.translate(): 使用 glMatrix 库创建和计算模型视图矩阵和投影矩阵。 glMatrix 是一个常用的 JavaScript 矩阵和向量运算库。
gl.uniformMatrix4fv(modelViewMatrixLocation, false, modelViewMatrix), gl.uniformMatrix4fv(projectionMatrixLocation, false, projectionMatrix): 使用 gl.uniformMatrix4fv() 函数将模型视图矩阵和投影矩阵的值传递给 Uniform 变量。
modelViewMatrixLocation, projectionMatrixLocation: Uniform 变量的 location。
false: 表示矩阵不进行转置。
modelViewMatrix, projectionMatrix: 要传递的矩阵数据 (Float32Array 类型)。
6. 绘制图元 (Drawing Primitives)
绘制图元 (Drawing Primitives) 是 WebGL 中用于描述几何形状的基本单元。 WebGL 支持以下几种常用的绘制图元:
gl.POINTS: 绘制点。 每个顶点绘制为一个点。
gl.LINES: 绘制线段。 每两个顶点绘制一条线段。
gl.LINE_STRIP: 绘制连续线段。 从第一个顶点开始,每个顶点与前一个顶点连接成一条线段。
gl.LINE_LOOP: 绘制闭合线段。 类似于 gl.LINE_STRIP,但最后一个顶点与第一个顶点也连接成一条线段。
gl.TRIANGLES: 绘制三角形。 每三个顶点绘制一个三角形。
gl.TRIANGLE_STRIP: 绘制三角形带。 每三个顶点绘制一个三角形,后一个三角形与前一个三角形共享两个顶点。
gl.TRIANGLE_FAN: 绘制三角形扇。 第一个顶点作为扇形的中心,后续每个顶点与中心顶点和前一个顶点组成一个三角形。
绘制图元的方法:
WebGL 提供了两种主要的绘制图元的方法:
gl.drawArrays(mode, first, count): 使用顶点数组直接绘制图元。
mode: 绘制模式,即绘制图元类型,例如 gl.TRIANGLES, gl.LINES 等。
first: 起始顶点索引。
count: 顶点数量。
gl.drawElements(mode, count, type, offset): 使用索引缓冲区绘制索引图元。
mode: 绘制模式,即绘制图元类型。
count: 索引数量。
type: 索引数据类型,例如 gl.UNSIGNED_SHORT, gl.UNSIGNED_BYTE。
offset: 索引缓冲区起始字节偏移量。
代码示例 (绘制三角形):
// ... (顶点缓冲区、索引缓冲区、着色器程序初始化) ... // 使用索引缓冲区绘制三角形 gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, indexBuffer); // 绑定索引缓冲区 gl.drawElements(gl.TRIANGLES, indices.length, gl.UNSIGNED_SHORT, 0); // 绘制索引图元 (三角形)
代码详解:
gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, indexBuffer): 绑定索引缓冲区。
gl.drawElements(gl.TRIANGLES, indices.length, gl.UNSIGNED_SHORT, 0): 使用 gl.drawElements() 函数绘制索引图元:
gl.TRIANGLES: 绘制模式为三角形。
indices.length: 索引数量,即三角形的顶点索引数量。
gl.UNSIGNED_SHORT: 索引数据类型为 16位无符号整数。
0: 索引缓冲区起始字节偏移量为 0。
7. 坐标系统与变换 (Coordinate Systems & Transformations)
在 3D 图形渲染中,坐标系统和变换至关重要。 WebGL 使用一系列坐标系统和变换矩阵,将物体从模型空间最终转换到屏幕空间,并呈现到用户的视野中。 WebGL 中常用的坐标系统和变换包括:
模型空间 (Model Space): 也称为物体空间 (Object Space)。 模型空间是每个物体自身的局部坐标系。 在模型空间中,物体的顶点坐标通常是相对于物体自身中心或原点定义的。
世界空间 (World Space): 世界空间是场景的全局坐标系。 所有物体都放置在世界空间中。 模型变换 (Model Transformation) 将物体从模型空间转换到世界空间。
视图空间 (View Space): 也称为相机空间 (Camera Space) 或眼睛空间 (Eye Space)。 视图空间是以相机为原点的坐标系。 视图变换 (View Transformation) 将世界空间中的物体转换到视图空间。 视图变换模拟了相机的视角和位置。
裁剪空间 (Clip Space): 裁剪空间是投影变换后的坐标空间。 裁剪空间用于进行裁剪操作,将视锥体外部的图元裁剪掉。 投影变换 (Projection Transformation) 将视图空间中的物体转换到裁剪空间。
规范化设备坐标 (Normalized Device Coordinates, NDC): NDC 是裁剪空间经过透视除法 (Perspective Division) 后得到的坐标空间。 NDC 的 x, y, z 坐标范围都在 [-1, 1] 之间。
屏幕空间 (Screen Space): 屏幕空间是最终渲染到屏幕上的 2D 像素坐标空间。 视口变换 (Viewport Transformation) 将 NDC 坐标转换到屏幕空间。
变换矩阵:
模型矩阵 (Model Matrix): 将物体从模型空间转换到世界空间。 模型矩阵包括平移、旋转、缩放等变换。
视图矩阵 (View Matrix): 将世界空间中的物体转换到视图空间。 视图矩阵由相机的位置、目标点和向上方向决定。