TransformFeedback在WebGL2中需显式配置:必须提前用transformFeedbackVaryings声明输出变量(link前)、绑定双缓冲VBO、禁用光栅化并严格匹配绘制模式,否则静默失败或报INVALID_OPERATION。

TransformFeedback 在 WebGL2 中不是“开启即用”的功能,它需要显式声明、绑定、启用和切换缓冲区。直接写 gl.beginTransformFeedback() 而不配置好着色器输出和缓冲区绑定,会静默失败或触发 INVALID_OPERATION 错误。
必须先在着色器中声明 transform feedback 输出变量
WebGL2 要求你用 transformFeedbackVaryings() 显式指定哪些 out 变量要被捕获——不能靠着色器里写了 out 就自动捕获。而且这个调用必须在 linkProgram() 之前完成。
-
gl.transformFeedbackVaryings(program, ['Pos', 'Velocity', 'Life'], gl.INTERLEAVED_ATTRIBS)是常见写法,注意变量名必须与着色器中out声明的标识符完全一致(区分大小写) - 如果用
SEPARATE_ATTRIBS,每个变量会独占一个 buffer binding point,适合后续分别绑定不同 VBO;INTERLEAVED_ATTRIBS更省内存,但所有变量必须打包进同一个 VBO 的连续 layout 中 - 链接失败时,
gl.getProgramParameter(program, gl.LINK_STATUS)为false,此时gl.getProgramInfoLog(program)通常会提示 “transform feedback varyings not specified” 或变量名不匹配
双缓冲 VBO + 交替绑定 feedback 对象是硬性要求
GPU 无法同时读写同一块内存。所以粒子更新阶段:上一帧的输出 VBO 必须是当前帧的输入 VBO,而当前帧的输出目标必须是另一块 VBO。这意味着你至少需要两个 WebGLBuffer 和两个 WebGLTransformFeedback 对象。
- 创建:
const vboA = gl.createBuffer(); const vboB = gl.createBuffer(); const tfA = gl.createTransformFeedback(); const tfB = gl.createTransformFeedback(); - 初始化时分别绑定 VBO 到
tfA和tfB的 binding point 0:gl.bindTransformFeedback(gl.TRANSFORM_FEEDBACK, tfA); gl.bindBufferBase(gl.TRANSFORM_FEEDBACK, 0, vboA);(同理绑tfB→vboB) - 每帧更新时交换:
gl.bindTransformFeedback(gl.TRANSFORM_FEEDBACK, i % 2 === 0 ? tfA : tfB);,然后gl.bindBufferBase(...)绑定对应 VBO 到 binding point 0 —— 注意:这里不是重新 bindBufferBase,而是确保当前 feedback 对象已绑定到正确的 buffer - 忘记调用
gl.bindBufferBase()或绑定错 binding point(比如用了 1 而不是 0),会导致beginTransformFeedback()后无数据写入,且无报错
update shader 必须禁用光栅化,且 draw mode 要严格匹配
transform feedback 的本质是截断渲染管线,在 vertex shader(+ optional geometry shader)之后停止,不进入片元阶段。因此你不能用 gl.drawArrays(gl.TRIANGLES, ...) 去驱动 feedback,否则可能被驱动硬件忽略或报错。
- 必须使用与着色器中
gl_Position计算逻辑兼容的 primitive type:gl.POINTS最安全,因为粒子系统天然按点处理;若用gl.LINES或gl.TRIANGLES,需确保顶点数能被整除,否则行为未定义 - 着色器中不能有
discard或任何依赖 fragment shader 的逻辑;片元着色器可以极简,例如只写out vec4 fragColor; void main() { fragColor = vec4(1.); },但它必须存在且成功链接(WebGL2 不允许无 fragment shader 的 program) - 调用顺序不能乱:
gl.bindTransformFeedback()→gl.bindVertexArray()→gl.beginTransformFeedback()→gl.drawArrays()→gl.endTransformFeedback();漏掉begin/end或顺序颠倒,feedback 不生效
render 阶段直接用上一帧的输出 VBO 作为 attribute source
不需要把数据拉回 CPU,也不需要 gl.bufferData() 重传。上一帧 update shader 写入的 VBO,这一帧直接 gl.bindBuffer(gl.ARRAY_BUFFER, vboA) 并 gl.vertexAttribPointer() 关联到 render shader 的 in 变量即可。
立即学习“前端免费学习笔记(深入)”;
- 确保 render shader 的
in变量 layout(类型、步长、偏移)与 update shader 的out结构完全一致,否则读出来是乱码 - 如果 update shader 输出的是
struct { vec3 Pos; vec3 Velocity; float Life; },那 VBO 数据 layout 必须是3*4 + 3*4 + 4 = 40字节/粒子,且vertexAttribPointer的stride和offset要精确对齐 - 容易忽略的一点:
gl.bindBuffer(gl.ARRAY_BUFFER, vboA)后,必须再调一次gl.enableVertexAttribArray()才能让 attribute 生效——即使上一帧刚用过,这一步也不能省
gl.enableVertexAttribArray()。WebGL2 的 transform feedback 没有运行时反射,出错了只能靠 log 和逐行检查 binding 点是否对得上。



















