WebGL是一套基于OpenGL ES标准的javascript API,它允许开发者借助浏览器底层的GPU加速能力,直接在HTML的canvas元素上渲染交互式2D和3D图形。和传统的前端绘图方式相比,WebGL能实现更复杂的视觉效果,适合开发网页游戏、数据可视化、3D产品展示等场景。

WebGL的核心基础概念
要理解WebGL的运行逻辑,需要先掌握几个核心概念:
- 着色器:分为顶点着色器和片元着色器,是运行在GPU上的小程序,负责处理顶点位置和像素颜色的计算。
- 缓冲区:用来存储顶点数据、颜色数据等信息,GPU会直接从缓冲区读取数据进行处理。
- 坐标系:WebGL使用的是归一化设备坐标系,坐标范围在-1到1之间,需要通过矩阵变换映射到屏幕坐标。
- WebGL上下文:通过canvas元素获取,是所有WebGL操作的入口,所有渲染指令都需要通过上下文对象调用。
用WebGL创建3D图形应用的完整步骤
第一步:初始化WebGL上下文
首先需要在页面中创建canvas元素,然后获取它的WebGL上下文,这是后续所有操作的基础。
<!DOCTYPE html>
<html lang="zh-CN">
<head>
<meta charset="UTF-8">
<title>WebGL 3D示例</title>
<style>
body { margin: 0; }
canvas { display: block; }
</style>
</head>
<body>
<canvas id="glCanvas" width="800" height="600"></canvas>
<script src="main.js"></script>
</body>
</html>
对应的javascript初始化代码如下:
// 获取canvas元素
const canvas = document.getElementById('glCanvas');
// 获取WebGL上下文,兼容不同浏览器
const gl = canvas.getContext('webgl') || canvas.getContext('experimental-webgl');
if (!gl) {
console.error('当前浏览器不支持WebGL');
return;
}
第二步:编写着色器程序
着色器使用GLSL语言编写,我们需要分别定义顶点着色器和片元着色器,然后编译、链接成可执行的着色器程序。
// 顶点着色器源码,处理顶点位置
const vertexShaderSource = `
attribute vec4 aPosition;
uniform mat4 uModelViewMatrix;
uniform mat4 uProjectionMatrix;
void main() {
// 将顶点位置经过矩阵变换后输出
gl_Position = uProjectionMatrix * uModelViewMatrix * aPosition;
}
`;
// 片元着色器源码,处理像素颜色
const fragmentShaderSource = `
precision mediump float;
uniform vec4 uColor;
void main() {
gl_FragColor = uColor;
}
`;
// 编译着色器的通用函数
function compileShader(gl, source, type) {
const shader = gl.createShader(type);
gl.shaderSource(shader, source);
gl.compileShader(shader);
if (!gl.getShaderParameter(shader, gl.COMPILE_STATUS)) {
console.error('着色器编译失败:', gl.getShaderInfoLog(shader));
gl.deleteShader(shader);
return null;
}
return shader;
}
// 创建着色器程序
const vertexShader = compileShader(gl, vertexShaderSource, gl.VERTEX_SHADER);
const fragmentShader = compileShader(gl, fragmentShaderSource, gl.FRAGMENT_SHADER);
const shaderProgram = gl.createProgram();
gl.attachShader(shaderProgram, vertexShader);
gl.attachShader(shaderProgram, fragmentShader);
gl.linkProgram(shaderProgram);
if (!gl.getProgramParameter(shaderProgram, gl.LINK_STATUS)) {
console.error('着色器程序链接失败:', gl.getProgramInfoLog(shaderProgram));
return;
}
// 使用着色器程序
gl.useProgram(shaderProgram);
第三步:准备顶点数据和缓冲区
这里以绘制一个3D立方体为例,需要准备立方体的8个顶点坐标,以及组成6个面的索引数据。
// 立方体的8个顶点坐标
const vertices = new Float32Array([
// 前面四个点
-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,
]);
// 立方体面的索引,每个面由两个三角形组成
const indices = new Uint16Array([
0, 1, 2, 0, 2, 3, // 前
4, 5, 6, 4, 6, 7, // 后
0, 1, 5, 0, 5, 4, // 下
2, 3, 7, 2, 7, 6, // 上
0, 3, 7, 0, 7, 4, // 左
1, 2, 6, 1, 6, 5, // 右
]);
// 创建顶点缓冲区并写入数据
const vertexBuffer = gl.createBuffer();
gl.bindBuffer(gl.ARRAY_BUFFER, vertexBuffer);
gl.bufferData(gl.ARRAY_BUFFER, vertices, gl.STATIC_DRAW);
// 创建索引缓冲区并写入数据
const indexBuffer = gl.createBuffer();
gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, indexBuffer);
gl.bufferData(gl.ELEMENT_ARRAY_BUFFER, indices, gl.STATIC_DRAW);
// 获取顶点属性位置并启用
const positionLocation = gl.getAttribLocation(shaderProgram, 'aPosition');
gl.vertexAttribPointer(positionLocation, 3, gl.FLOAT, false, 0, 0);
gl.enableVertexAttribArray(positionLocation);
第四步:设置矩阵和渲染循环
需要通过投影矩阵和模型视图矩阵将3D坐标映射到屏幕,同时添加旋转动画让立方体动起来。
// 获取矩阵uniform的位置
const modelViewMatrixLocation = gl.getUniformLocation(shaderProgram, 'uModelViewMatrix');
const projectionMatrixLocation = gl.getUniformLocation(shaderProgram, 'uProjectionMatrix');
const colorLocation = gl.getUniformLocation(shaderProgram, 'uColor');
// 创建投影矩阵(透视投影)
const projectionMatrix = mat4.create();
mat4.perspective(projectionMatrix, 45 * Math.PI / 180, canvas.width / canvas.height, 0.1, 100.0);
gl.uniformMatrix4fv(projectionMatrixLocation, false, projectionMatrix);
// 初始模型视图矩阵
const modelViewMatrix = mat4.create();
mat4.translate(modelViewMatrix, modelViewMatrix, [0.0, 0.0, -6.0]);
// 设置背景色和启用深度测试
gl.clearColor(0.0, 0.0, 0.0, 1.0);
gl.enable(gl.DEPTH_TEST);
gl.depthFunc(gl.LEQUAL);
// 渲染函数
let rotationAngle = 0;
function render() {
// 清空画布和深度缓冲区
gl.clear(gl.COLOR_BUFFER_BIT | gl.DEPTH_BUFFER_BIT);
// 更新旋转角度
rotationAngle += 0.01;
mat4.identity(modelViewMatrix);
mat4.translate(modelViewMatrix, modelViewMatrix, [0.0, 0.0, -6.0]);
mat4.rotate(modelViewMatrix, modelViewMatrix, rotationAngle, [1, 1, 0]);
gl.uniformMatrix4fv(modelViewMatrixLocation, false, modelViewMatrix);
// 设置颜色并绘制立方体
gl.uniform4fv(colorLocation, [0.8, 0.3, 0.3, 1.0]);
gl.drawElements(gl.TRIANGLES, indices.length, gl.UNSIGNED_SHORT, 0);
// 请求下一帧渲染
requestAnimationFrame(render);
}
// 启动渲染循环
render();
注意上面的矩阵操作使用了常用的mat4库,你可以引入gl-matrix库来简化矩阵计算,避免手动实现复杂的矩阵运算逻辑。
开发WebGL应用的常见问题
- 坐标范围错误:WebGL的顶点坐标需要在-1到1之间,超出范围的内容不会显示,需要通过矩阵变换调整。
- 深度测试未开启:绘制3D物体时如果没有开启深度测试,会出现后面的物体遮挡前面物体的错误显示。
- 着色器编译错误:GLSL语法和javascript不同,需要注意变量类型匹配、函数名正确,编译失败时要查看报错信息定位问题。
- 缓冲区数据错误:顶点数据的长度、索引的范围需要和着色器的属性配置匹配,否则会出现渲染异常。
WebGL的学习曲线相对较陡,建议先掌握基础的着色器编写和矩阵变换逻辑,再逐步尝试更复杂的纹理、光照等效果,多参考官方文档和示例能更快上手。
WebGLjavascript3D图形canvas修改时间:2026-06-27 12:34:08