WebGL 版本概述
WebGL 1.0 于 2011 年发布,基于 OpenGL ES 2.0。WebGL 2.0 于 2017 年发布,基于 OpenGL ES 3.0,带来了大量新功能和性能改进。
主要区别对比
| 特性 | WebGL 1.0 | WebGL 2.0 |
|---|
| 基础规范 | OpenGL ES 2.0 | OpenGL ES 3.0 |
| 发布年份 | 2011 | 2017 |
| 着色器版本 | GLSL ES 1.0 | GLSL ES 3.0 |
| 3D 纹理 | 需要扩展 | 原生支持 |
| 多重渲染目标(MRT) | 需要扩展 | 原生支持 |
| 实例化渲染 | 需要扩展 | 原生支持 |
| 变换反馈 | 不支持 | 支持 |
| 采样器对象 | 不支持 | 支持 |
| 顶点数组对象(VAO) | 需要扩展 | 原生支持 |
| 非2的幂次纹理 | 有限制 | 完全支持 |
着色器语言差异
WebGL 1.0 (GLSL ES 1.0)
// 顶点着色器
attribute vec3 a_position;
attribute vec2 a_texCoord;
uniform mat4 u_mvpMatrix;
uniform sampler2D u_texture;
varying vec2 v_texCoord;
void main() {
gl_Position = u_mvpMatrix * vec4(a_position, 1.0);
v_texCoord = a_texCoord;
}
// 片段着色器
precision mediump float;
varying vec2 v_texCoord;
uniform sampler2D u_texture;
void main() {
gl_FragColor = texture2D(u_texture, v_texCoord);
}
WebGL 2.0 (GLSL ES 3.0)
#version 300 es
// 顶点着色器
in vec3 a_position; // attribute → in
in vec2 a_texCoord;
uniform mat4 u_mvpMatrix;
out vec2 v_texCoord; // varying → out
void main() {
gl_Position = u_mvpMatrix * vec4(a_position, 1.0);
v_texCoord = a_texCoord;
}
// 片段着色器
#version 300 es
precision mediump float;
in vec2 v_texCoord; // varying → in
uniform sampler2D u_texture;
out vec4 fragColor; // gl_FragColor → out 变量
void main() {
fragColor = texture(u_texture, v_texCoord); // texture2D → texture
}
着色器语法变化
| WebGL 1.0 | WebGL 2.0 | 说明 |
|---|
attribute | in | 顶点输入 |
varying | in/out | 顶点/片段间传递数据 |
gl_FragColor | out 变量 | 片段着色器输出 |
texture2D() | texture() | 2D 纹理采样 |
textureCube() | texture() | 立方体纹理采样 |
| - | #version 300 es | 版本声明(必需) |
WebGL 2.0 新增功能详解
1. 3D 纹理
// WebGL 2.0 原生支持 3D 纹理
const texture3D = gl.createTexture();
gl.bindTexture(gl.TEXTURE_3D, texture3D);
gl.texImage3D(
gl.TEXTURE_3D, // 目标
0, // 级别
gl.RGBA, // 内部格式
width,
height,
depth, // 深度
0, // 边框
gl.RGBA,
gl.UNSIGNED_BYTE,
data
);
#version 300 es
uniform sampler3D u_volumeTexture;
void main() {
vec4 color = texture(u_volumeTexture, vec3(x, y, z));
}
2. 多重渲染目标(MRT)
// 创建帧缓冲区,绑定多个颜色附件
const framebuffer = gl.createFramebuffer();
gl.bindFramebuffer(gl.FRAMEBUFFER, framebuffer);
// 附加多个纹理
const textures = [];
for (let i = 0; i < 4; i++) {
const texture = gl.createTexture();
// ... 配置纹理
gl.framebufferTexture2D(
gl.FRAMEBUFFER,
gl.COLOR_ATTACHMENT0 + i, // COLOR_ATTACHMENT0, COLOR_ATTACHMENT1, ...
gl.TEXTURE_2D,
texture,
0
);
textures.push(texture);
}
// 指定绘制到哪些附件
gl.drawBuffers([
gl.COLOR_ATTACHMENT0,
gl.COLOR_ATTACHMENT1,
gl.COLOR_ATTACHMENT2,
gl.COLOR_ATTACHMENT3
]);
#version 300 es
layout(location = 0) out vec4 color0;
layout(location = 1) out vec4 color1;
layout(location = 2) out vec4 color2;
layout(location = 3) out vec4 color3;
void main() {
color0 = vec4(1.0, 0.0, 0.0, 1.0);
color1 = vec4(0.0, 1.0, 0.0, 1.0);
color2 = vec4(0.0, 0.0, 1.0, 1.0);
color3 = vec4(1.0, 1.0, 1.0, 1.0);
}
3. 实例化渲染(Instanced Rendering)
// WebGL 2.0 原生支持
// 绘制 1000 个实例,每个实例使用不同的变换
const instanceCount = 1000;
gl.drawArraysInstanced(gl.TRIANGLES, 0, vertexCount, instanceCount);
// 或使用索引绘制
gl.drawElementsInstanced(gl.TRIANGLES, indexCount, gl.UNSIGNED_SHORT, 0, instanceCount);
#version 300 es
in vec3 a_position;
in mat4 a_instanceMatrix; // 实例化矩阵
void main() {
gl_Position = u_projectionMatrix * u_viewMatrix * a_instanceMatrix * vec4(a_position, 1.0);
}
// 创建变换反馈对象
const transformFeedback = gl.createTransformFeedback();
// 设置顶点着色器输出
const vertexShaderSource = `#version 300 es
in vec3 a_position;
out vec3 v_newPosition; // 变换后的位置
void main() {
v_newPosition = a_position * 2.0; // 某种变换
}
`;
// 配置变换反馈
const program = gl.createProgram();
// ... 编译链接着色器
gl.transformFeedbackVaryings(
program,
['v_newPosition'], // 要捕获的输出变量
gl.SEPARATE_ATTRIBS // 或 INTERLEAVED_ATTRIBS
);
// 执行变换反馈
gl.bindTransformFeedback(gl.TRANSFORM_FEEDBACK, transformFeedback);
gl.beginTransformFeedback(gl.POINTS);
gl.drawArrays(gl.POINTS, 0, count);
gl.endTransformFeedback();
5. 采样器对象(Sampler Objects)
// 将纹理参数从纹理对象分离
const sampler = gl.createSampler();
// 配置采样器参数
gl.samplerParameteri(sampler, gl.TEXTURE_MIN_FILTER, gl.LINEAR_MIPMAP_LINEAR);
gl.samplerParameteri(sampler, gl.TEXTURE_MAG_FILTER, gl.LINEAR);
gl.samplerParameteri(sampler, gl.TEXTURE_WRAP_S, gl.CLAMP_TO_EDGE);
gl.samplerParameteri(sampler, gl.TEXTURE_WRAP_T, gl.CLAMP_TO_EDGE);
// 绑定采样器到纹理单元
gl.bindSampler(0, sampler); // 绑定到纹理单元 0
6. 顶点数组对象(VAO)原生支持
// WebGL 2.0 原生支持,无需扩展
const vao = gl.createVertexArray();
gl.bindVertexArray(vao);
// 配置顶点属性(存储在 VAO 中)
gl.bindBuffer(gl.ARRAY_BUFFER, positionBuffer);
gl.vertexAttribPointer(0, 3, gl.FLOAT, false, 0, 0);
gl.enableVertexAttribArray(0);
gl.bindVertexArray(null);
// 绘制时只需绑定 VAO
gl.bindVertexArray(vao);
gl.drawArrays(gl.TRIANGLES, 0, count);
新纹理功能
非2的幂次纹理完整支持
// WebGL 2.0 中,非2的幂次纹理支持所有功能
gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_S, gl.REPEAT);
gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_T, gl.REPEAT);
gl.generateMipmap(gl.TEXTURE_2D); // 也支持 mipmap
纹理数组
const textureArray = gl.createTexture();
gl.bindTexture(gl.TEXTURE_2D_ARRAY, textureArray);
gl.texImage3D(
gl.TEXTURE_2D_ARRAY,
0,
gl.RGBA,
width,
height,
layerCount, // 层数
0,
gl.RGBA,
gl.UNSIGNED_BYTE,
data
);
如何检测 WebGL 2.0 支持
function getWebGLContext(canvas) {
// 优先尝试 WebGL 2.0
let gl = canvas.getContext('webgl2');
if (gl) {
console.log('Using WebGL 2.0');
return gl;
}
// 回退到 WebGL 1.0
gl = canvas.getContext('webgl') || canvas.getContext('experimental-webgl');
if (gl) {
console.log('Using WebGL 1.0');
return gl;
}
console.error('WebGL not supported');
return null;
}
浏览器支持情况
| 浏览器 | WebGL 1.0 | WebGL 2.0 |
|---|
| Chrome | ✓ | ✓ (56+) |
| Firefox | ✓ | ✓ (51+) |
| Safari | ✓ | ✓ (15+) |
| Edge | ✓ | ✓ (79+) |
| IE 11 | ✓ | ✗ |
迁移建议
- 渐进增强:先检测 WebGL 2.0 支持,不支持时回退到 1.0
- 着色器版本:为两个版本准备不同的着色器代码
- 功能检测:使用特定功能前检查是否可用
- 性能考虑:WebGL 2.0 功能更强大,但 1.0 兼容性更好