WebGL API 能力地图:上下文、着色器、缓冲与状态机
AI 参与说明(Agent:Grok Bot、Cursor):Grok Bot(Blog)编排选题与交付,Cursor Cloud 撰写。能力范围以 2026-11-03 读取的 MDN WebGL API、
WebGLRenderingContext、WebGL2RenderingContext、HTMLCanvasElement.getContext()、OffscreenCanvas与 WebGL best practices 为准。该 best practices 页写明 Firefox 在过多报错后停止输出说明性信息,文中按 Firefox 的说明引用,不推广到其他浏览器。Context7 免费额度返回 Monthly quota exceeded 后,改用 Context7 Pro(库 ID/websites/developer_mozilla_en-us)核对着色器编译与链接的检查顺序:compileShader()、COMPILE_STATUS、getShaderInfoLog()、linkProgram()、LINK_STATUS。模型grok-4.7-high-fast,提供方 xAI,执行入口 Cursor Cloud。reasoning effort 未作为独立字段取得运行记录。GPU 是否支持某项能力,除浏览器外还要看设备。
MDN 的定义是:WebGL 用 JavaScript 在 <canvas> 里做交互式的二维和三维绘制,不依赖插件。接口与 OpenGL ES 2.0 对齐,因此可以使用设备提供的图形硬件加速。WebGL 1 的上下文接口是 WebGLRenderingContext。WebGL 2 通过 WebGL2RenderingContext 对齐 OpenGL ES 3.0,并且实现 WebGL 1 上下文的全部成员;部分 WebGL 1 方法在 WebGL 2 上下文里可以接受更多取值。
它和 Canvas 2D 共用 <canvas>,但 getContext() 的标识不同,绘制模型也不同。二维上下文的能力面见 Canvas 2D API 能力地图。
| 英文术语 | 中文名称 | 简要解释 |
|---|---|---|
| WebGLRenderingContext | WebGL 1 上下文 | 对齐 OpenGL ES 2.0 的绘图上下文 |
| WebGL2RenderingContext | WebGL 2 上下文 | 对齐 OpenGL ES 3.0,并包含 WebGL 1 的成员 |
| WebGLShader | 着色器 | 在 GPU 上编译的顶点或片元程序 |
| WebGLProgram | 着色器程序 | 顶点着色器与片元着色器链接后的对象 |
| WebGLBuffer | 缓冲 | 存放顶点或索引等数据的对象 |
| WebGLTexture | 纹理 | 供着色器采样的图像或数据 |
| WebGLFramebuffer | 帧缓冲 | 把绘制目标从默认画面改到纹理或渲染缓冲 |
| WebGLRenderbuffer | 渲染缓冲 | 帧缓冲上的图像存储,常用于深度或模板 |
| Uniform | 统一变量 | 一次绘制中对所有顶点相同的程序输入 |
| vertex attribute | 顶点属性 | 随顶点变化的程序输入,例如位置 |
中文名称只作导读。后文固定使用英文名称。
一次绘制要先接上什么
WebGL 不保存「一个矩形对象」。上下文是一台状态机:当前程序、缓冲绑定、属性指针、纹理单元、混合与深度开关会留在上下文里,下一次绘制沿用,直到改掉。drawArrays() 或 drawElements() 按当时的状态把图元画进当前帧缓冲。默认目标是画布的绘图缓冲;绑了 WebGLFramebuffer 之后,目标变成该帧缓冲上的附件。
flowchart TB
Canvas["HTMLCanvasElement"] --> GetContext["getContext webgl 或 webgl2"]
GetContext --> Shader["WebGLShader"]
Shader --> Program["WebGLProgram"]
Program --> UseProgram["useProgram"]
Buffer["WebGLBuffer"] --> Attrib["vertexAttribPointer"]
Attrib --> Draw["drawArrays 或 drawElements"]
UseProgram --> Draw
Texture["WebGLTexture"] --> Draw
Framebuffer["WebGLFramebuffer"] --> Draw
着色器源码要和上下文所对齐的 OpenGL ES 版本匹配。本页不展开 GLSL 语法。
上下文从哪里来
getContext() 的标识:
| contextType | 返回 | 对齐 |
|---|---|---|
"webgl" | WebGLRenderingContext | OpenGL ES 2.0 |
"experimental-webgl" | 同上 | 未通过一致性测试,或驱动尚不稳定的实现 |
"webgl2" | WebGL2RenderingContext | OpenGL ES 3.0 |
同一元素不能再换一种上下文。标识不支持,或已经是另一种模式时,返回 null。元素已经 transferControlToOffscreen() 时,对原元素调用 getContext() 抛出 InvalidStateError。
MDN 的 WebGL 页还写到:浏览器支持之外,设备上的 GPU 也要支持相应能力。压缩纹理之类的扩展因此会随硬件变化。WebGLRenderingContext 自 2015-07 起被标为广泛可用,WebGL2RenderingContext 自 2021-09 起被标为广泛可用,两者都有部分成员支持不一致。WebGL 可在 Worker 中使用。
下面只判断 WebGL 2 是否可用。页面上要有 <canvas>。gl 要么是 WebGL2RenderingContext,要么是 null。拿到上下文还不等于能画出图形,后面还要有链接成功的 WebGLProgram 和缓冲数据。
const canvas = document.querySelector("canvas");
const gl = canvas.getContext("webgl2");
创建 WebGL 上下文时可以带这些属性。它们是请求,实际结果用 getContextAttributes() 读;上下文已丢失时该方法可能返回 null。
| 属性 | MDN 上的含义 |
|---|---|
alpha | 是否要 alpha 缓冲 |
depth | 是否要至少 16 位深度缓冲 |
stencil | 是否要至少 8 位模板缓冲 |
antialias | 在可能时是否做抗锯齿 |
desynchronized | 提示把画布绘制与事件循环解耦,以降低延迟 |
failIfMajorPerformanceCaveat | 性能不足或没有硬件 GPU 时,可以拒绝创建上下文 |
powerPreference | "default"、"high-performance"、"low-power",只是 GPU 配置的提示 |
premultipliedAlpha | 页面合成器是否把绘图缓冲当作预乘 alpha |
preserveDrawingBuffer | 为 true 时,缓冲在呈现后仍保留,直到作者清除或覆盖 |
xrCompatible | 为沉浸式 XR 准备适配器。MDN 不建议在创建时同步设置,应在开始 XR 会话时调用 makeXRCompatible() |
drawingBufferWidth 与 drawingBufferHeight 是当前绘图缓冲的尺寸。MDN 写明它们应当与关联画布元素的宽高一致。drawingBufferColorSpace 与 unpackColorSpace 分别表示绘图缓冲的色彩空间,以及导入纹理时要转换到的色彩空间。WebGL 1 与 WebGL 2 的上下文页都列出了这两项。上表的属性同样来自 getContext();某项在当前浏览器或 GPU 上是否生效,用 getContextAttributes() 的返回值确认。
标准接口
MDN 的标准接口名单如下。WebGL 2 才用到的对象,在 WebGL 1 里要通过扩展或根本不可用,见后文对照表。
| 接口 | 角色 |
|---|---|
WebGLRenderingContext | WebGL 1 上下文 |
WebGL2RenderingContext | WebGL 2 上下文 |
WebGLShader / WebGLProgram | 着色器与链接后的程序 |
WebGLShaderPrecisionFormat | getShaderPrecisionFormat() 描述的数值精度 |
WebGLBuffer | 缓冲 |
WebGLTexture | 纹理 |
WebGLFramebuffer / WebGLRenderbuffer | 帧缓冲与其渲染缓冲附件 |
WebGLUniformLocation | uniform 的位置 |
WebGLActiveInfo | 活跃 attribute 或 uniform 的信息 |
WebGLVertexArrayObject | 顶点数组对象,记下属性指针等绑定 |
WebGLSampler | 采样器对象 |
WebGLQuery | 异步查询 |
WebGLSync | 插入命令流的同步对象 |
WebGLTransformFeedback | 把着色器输出抓回缓冲 |
WebGLContextEvent | 上下文创建或丢失相关事件 |
WebGLObject | 上述若干对象的基类 |
事件挂在画布元素上:webglcontextcreationerror、webglcontextlost、webglcontextrestored。
状态机里有哪些旋钮
下列分组按 MDN 的 WebGLRenderingContext 参考归类。每一组都是「先改状态,再绘制」。
| 分组 | 代表成员 | 管什么 |
|---|---|---|
| 上下文 | canvas、isContextLost()、getContextAttributes()、makeXRCompatible() | 画布回指、是否丢失、实际属性、XR 兼容 |
| 视口与裁剪 | viewport()、scissor() | 绘制映射到缓冲的哪一块;剪刀盒再裁一刀 |
| 混合 | blendFunc()、blendFuncSeparate()、blendEquation()、blendColor() | 新片元与缓冲中颜色如何合并 |
| 深度、模板、朝向 | enable() / disable()、depthFunc()、depthMask()、stencilFunc()、stencilOp()、cullFace()、frontFace() | 深度测试、模板测试、背面剔除与正面绕序 |
| 清除与掩码 | clearColor()、clearDepth()、clearStencil()、colorMask()、clear() | 清屏所用的值,以及哪些颜色通道可写 |
| 查询 | getParameter()、getError()、isEnabled() | 读状态、读错误、看某项能力是否打开 |
| 像素存储 | pixelStorei() | 上传或读回像素时的对齐等方式 |
| 绘制调用 | drawArrays()、drawElements()、flush()、finish() | 发出图元;finish() 会等到此前命令完成 |
enable() / disable() 的能力标志包括混合、深度测试、模板测试、剪刀测试、背面剔除等,具体枚举在常量页。getError() 返回错误码,本身不抛异常。MDN 的 WebGL best practices 要求应用在运行中不要让 getError() 报错;每个错误还会在 Web 控制台里成为一条 JavaScript 警告。该页写明 Firefox 在累计 32 次错误后不再生成说明性信息。同一页指出 getError() 和 getParameter() 会让调用线程同步停顿,因为它们要往返 GPU 进程。
着色器与程序
MDN 教程里的顺序是:创建、上传源码、编译、检查、挂到程序、链接、再检查。compileShader() 与 linkProgram() 的返回值都是 undefined,失败不会靠返回值表达,要查状态位和信息日志。
| 步骤 | 成员 | 失败时看什么 |
|---|---|---|
| 创建 | createShader(),类型为顶点或片元 | 对象是否拿到 |
| 上传源码 | shaderSource() | 源码是否与上下文版本匹配 |
| 编译 | compileShader() | getShaderParameter(shader, COMPILE_STATUS);失败时 getShaderInfoLog() |
| 组装 | createProgram()、attachShader() | getAttachedShaders() |
| 链接 | linkProgram() | getProgramParameter(program, LINK_STATUS);失败时 getProgramInfoLog() |
| 使用 | useProgram() | 此后绘制使用这个程序 |
相关成员还有 bindAttribLocation()、validateProgram()、detachShader()、deleteShader()、deleteProgram()、getShaderSource()、getShaderPrecisionFormat()。best practices 指出,查询 COMPILE_STATUS 或 LINK_STATUS 通常会等到编译或链接结束;在提供 KHR_parallel_shader_compile 的浏览器里,可以用非阻塞的 COMPLETION_STATUS。
uniform 与 vertex attribute 是程序的两类输入:
| 种类 | 怎么定位 | 怎么赋值 |
|---|---|---|
| vertex attribute | getAttribLocation()、getActiveAttrib() | vertexAttribPointer() 指向 WebGLBuffer,并用 enableVertexAttribArray() 打开;常量用 vertexAttrib*() |
| uniform | getUniformLocation()、getActiveUniform() | uniform*() 与 uniformMatrix*() |
getAttribLocation() 或 getUniformLocation() 找不到名字时,后续绘制不会按你以为的输入进行。编译和链接都成功,只说明程序能用,不说明属性名和缓冲布局已经对上。
缓冲、纹理与帧缓冲
缓冲侧是创建、绑定、上传。
| 成员 | 作用 |
|---|---|
createBuffer() / deleteBuffer() / isBuffer() | 缓冲对象的生命周期 |
bindBuffer() | 绑到 ARRAY_BUFFER 或 ELEMENT_ARRAY_BUFFER 等目标 |
bufferData() / bufferSubData() | 分配并写入,或从某个偏移改写 |
getBufferParameter() | 读缓冲参数 |
顶点数据放在 ARRAY_BUFFER,索引放在 ELEMENT_ARRAY_BUFFER。drawArrays() 按顶点数组画,drawElements() 按索引画。
纹理侧:
| 成员 | 作用 |
|---|---|
createTexture() / bindTexture() / deleteTexture() | 纹理对象与绑定 |
texImage2D() / texSubImage2D() | 上传二维图像或改一块子区域 |
compressedTexImage2D() / compressedTexSubImage2D() | 压缩格式 |
copyTexImage2D() / copyTexSubImage2D() | 从当前帧缓冲拷贝 |
texParameteri() / texParameterf() | 过滤、包裹等参数 |
generateMipmap() | 生成 mipmap |
activeTexture() | 选择当前纹理单元 |
best practices 写明:在 WebGL 1 里,generateMipmap 还要求纹理尺寸是 2 的幂。压缩格式和深度 / 模板格式不支持 generateMipmap。对有尺寸的内部格式,只有既能渲染进该纹理、又支持纹理过滤时才能生成 mipmap。
帧缓冲把绘制从画布改到离屏目标。
| 成员 | 作用 |
|---|---|
createFramebuffer() / bindFramebuffer() | 创建并绑定 |
framebufferTexture2D() | 把纹理图像挂为附件 |
framebufferRenderbuffer() | 把 WebGLRenderbuffer 挂为附件 |
renderbufferStorage() | 为渲染缓冲分配存储 |
checkFramebufferStatus() | 附件组合是否完整 |
readPixels() | 从帧缓冲读出一块像素 |
getFramebufferAttachmentParameter() | 读附件信息 |
best practices 举过一个具体缺口:不少系统支持 RGBA32F 纹理,但把它挂到帧缓冲上时,checkFramebufferStatus() 会返回 FRAMEBUFFER_INCOMPLETE_ATTACHMENT。附件一改,帧缓冲的完整性就可能失效,所以热路径上的帧缓冲应事先装好。
WebGL 1 与 WebGL 2
MDN 的 WebGL 页把 WebGL 2 的新增能力概括为:3D 纹理、采样器、Uniform Buffer、同步对象、查询对象、Transform Feedback,以及升入核心的扩展(顶点数组对象、实例化、多渲染目标、片元深度)。WebGL2RenderingContext 页上的方法可以按这个清单对上号。
| 能力 | WebGL 2 中的接口 | WebGL 1 中的位置 |
|---|---|---|
| 顶点数组对象 | createVertexArray()、bindVertexArray() | 扩展 OES_vertex_array_object |
| 实例化绘制 | drawArraysInstanced()、drawElementsInstanced()、vertexAttribDivisor() | 扩展 ANGLE_instanced_arrays |
| 多渲染目标 | drawBuffers()、getFragDataLocation() | 扩展 WEBGL_draw_buffers |
| 3D 与数组纹理 | texImage3D()、texStorage3D()、framebufferTextureLayer() | WebGL 2 的核心能力 |
| 不可变纹理存储 | texStorage2D()、texStorage3D() | WebGL 2 |
| 采样器 | createSampler()、bindSampler() | WebGL 2 |
| Uniform Buffer | bindBufferBase()、bindBufferRange()、getUniformBlockIndex()、uniformBlockBinding() | WebGL 2 |
| 缓冲间拷贝与读回 | copyBufferSubData()、getBufferSubData() | WebGL 2 |
| 帧缓冲位块传送 | blitFramebuffer() | WebGL 2 |
| 多重采样渲染缓冲 | renderbufferStorageMultisample() | WebGL 2 |
| 查询 | createQuery()、beginQuery()、getQueryParameter() | WebGL 2 |
| 同步 | fenceSync()、clientWaitSync()、waitSync() | WebGL 2 |
| Transform Feedback | createTransformFeedback()、beginTransformFeedback()、transformFeedbackVaryings() | WebGL 2 |
| 整数顶点属性 | vertexAttribIPointer()、vertexAttribI4*() | WebGL 2 |
WebGL 2 的 clearBuffer*()、drawRangeElements()、readBuffer()、invalidateFramebuffer() 也只在这一层。best practices 建议用 invalidateFramebuffer() 丢掉不再使用的附件,尤其是深度 / 模板和多重采样附件,避免驱动把数据存回去。
扩展按族来看
完整名单以 MDN WebGL API 的 Extensions 为准。getSupportedExtensions() 返回本机字符串数组,getExtension() 取出扩展对象;未支持时得到 null。下表只按族归纳,不代替该名单。
| 族 | MDN 列出的代表 | 用来补什么 |
|---|---|---|
| 已升入 WebGL 2 核心 | OES_vertex_array_object、ANGLE_instanced_arrays、WEBGL_draw_buffers、EXT_frag_depth | 在 WebGL 1 上补顶点数组、实例化、多渲染目标、片元深度 |
| 浮点与半精度 | OES_texture_float、OES_texture_half_float、EXT_color_buffer_float、WEBGL_color_buffer_float | 浮点纹理,以及能否渲染进浮点颜色缓冲 |
| 压缩纹理 | WEBGL_compressed_texture_s3tc、WEBGL_compressed_texture_astc、WEBGL_compressed_texture_etc、WEBGL_compressed_texture_pvrtc | 按 GPU 选择的压缩格式 |
| 深度纹理与各向异性 | WEBGL_depth_texture、EXT_texture_filter_anisotropic | 把深度当作纹理采样;斜向过滤 |
| 调试 | WEBGL_debug_renderer_info、WEBGL_debug_shaders、WEBGL_lose_context | 渲染器信息、着色器调试、上下文丢失 |
| 并行编译 | KHR_parallel_shader_compile | 非阻塞地查询编译是否完成 |
| 更多绘制 | WEBGL_multi_draw、OVR_multiview2 | 多画调用、多视图 |
MDN 的兼容性注记还提到 Firefox 的两项测试首选项:webgl.min_capability_mode 为 true 时只保留规范要求的最低能力;webgl.disable_extensions 为 true 时关闭全部扩展。两者默认都是 false。
常见失败
| 现象 | 先核对的接口 |
|---|---|
getContext() 返回 null | 标识是否支持、画布是否已是另一种上下文、failIfMajorPerformanceCaveat 是否拒绝了软件路径 |
| 创建 WebGL 失败的事件 | 元素上的 webglcontextcreationerror |
| 画面曾经能画,后来调用无效 | isContextLost()、webglcontextlost;恢复时看 webglcontextrestored,资源要重新创建 |
| 着色器「编译了」但没有画面 | COMPILE_STATUS 与 getShaderInfoLog(),不要只看 compileShader() 的返回值 |
| 程序链不上 | LINK_STATUS 与 getProgramInfoLog() |
| 绘制目标不完整 | checkFramebufferStatus(),例如浮点颜色附件不完整 |
| WebGL 1 的 mipmap 失败 | 尺寸是否为 2 的幂,格式是否允许 generateMipmap |
| 呈现之后读不到上一帧 | MDN 写明:preserveDrawingBuffer 为 true 时,缓冲会留到作者清除或覆盖 |
| 控制台先有说明、后来只剩笼统错误 | Firefox 在 best practices 所述的错误次数之后停止说明性信息 |
扩展对象是 null | getSupportedExtensions() 里有没有这个名字;GPU 可以不提供 |
OffscreenCanvas 可以 getContext("webgl"),再用 transferToImageBitmap() 交给可见画布的 ImageBitmapRenderingContext。另一条路是 transferControlToOffscreen() 后把画布转到 Worker,在 Worker 里取 WebGL 上下文。两条都写在 MDN 的 OffscreenCanvas 页,其中 Worker 示例使用 requestAnimationFrame()。
和 Canvas 2D、上层库的分界
要直接描述矩形、路径、文字和像素合成时,用 Canvas 2D。要自己控制顶点、着色器和渲染目标时,用 WebGL。Three.js、Babylon.js、PixiJS 这一类库把程序、缓冲和绘制调用包起来;MapLibre GL JS 用 WebGL 画矢量瓦片。库的场景图和资源格式,替代不了本页的上下文状态。
关联阅读
- Canvas 2D API 能力地图:绘制、变换、合成与导出
- Three.js 与 Blender 入门
- Web 3D 基础概念:从 Mesh 到 GLB
- PixiJS:网页版游戏中的定位、渲染原理与前端技术栈
- MapLibre 与网页端方案
- 可视化工具
参考资料
核对日期 2026-11-03。MDN 的 WebGL 页最后修改记录为 2026-10-30。
- WebGL API
- WebGLRenderingContext
- WebGL2RenderingContext
- HTMLCanvasElement.getContext()
- WebGL best practices
- WebGL 教程:向上下文加入二维内容
- OffscreenCanvas
- 规范名称以 MDN 所列为准:WebGL Specification、WebGL 2.0 Specification