bindFramebuffer

📅 2026/8/25 14:19:43
bindFramebuffer
代码里两处bindFramebuffer分别干什么先把代码里两处关键位置摘出来第一处初始化阶段构建 FBOconst fbo gl.createFramebuffer(); const pickTex gl.createTexture(); gl.bindTexture(gl.TEXTURE_2D, pickTex); gl.texImage2D(gl.TEXTURE_2D, 0, gl.RGBA, canvas.width, canvas.height, 0, gl.RGBA, gl.UNSIGNED_BYTE, null); gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, gl.NEAREST); gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MAG_FILTER, gl.NEAREST); //① gl.bindFramebuffer(gl.FRAMEBUFFER, fbo); gl.framebufferTexture2D(gl.FRAMEBUFFER, gl.COLOR_ATTACHMENT0, gl.TEXTURE_2D, pickTex, 0); //② gl.bindFramebuffer(gl.FRAMEBUFFER, null);gl.bindFramebuffer(gl.FRAMEBUFFER, fbo)① 把新建的 fbo 绑定到帧缓冲绑定点让后面的framebufferTexture2D作用到这个 fbo 对象上把 pickTex 纹理挂载为它的颜色附件。挂载关系会永久保存在 fbo 对象内部。gl.bindFramebuffer(gl.FRAMEBUFFER, null)② 初始化挂载完成切回浏览器默认屏幕帧缓冲。如果这里不切回 null后面页面初始render()执行 drawArrays渲染会跑到 pickTex 离屏纹理上屏幕画布就是黑的什么都看不见。⚠️注意解绑null不会销毁 fbo也不会取消纹理挂载关系只是把 “当前操作对象” 切回屏幕。后续点击拾取还可以再次 bind 这个 fbo。第二处点击鼠标pickLine()拾取函数内部function pickLine(mouseX, mouseY) { //③ gl.bindFramebuffer(gl.FRAMEBUFFER, fbo); gl.clearColor(0,0,0,0); gl.clear(gl.COLOR_BUFFER_BIT); gl.useProgram(pickProg); gl.bindBuffer(gl.ARRAY_BUFFER, vbo); gl.vertexAttribPointer(aPosPick, 2, gl.FLOAT, false, 0, 0); gl.enableVertexAttribArray(aPosPick); for(let id0; idLINE_COUNT; id){ const color idToColor(id); gl.uniform3fv(uIdColorPick, color); gl.drawArrays(gl.LINES, id*2, 2); } const pixels new Uint8Array(4); const glY canvas.height - mouseY; gl.readPixels(mouseX, glY, 1,1, gl.RGBA, gl.UNSIGNED_BYTE, pixels); //④ gl.bindFramebuffer(gl.FRAMEBUFFER, null); const [r,g,b,a] pixels; if(a 0) return -1; return colorToId(r,g,b); }gl.bindFramebuffer(gl.FRAMEBUFFER, fbo)③ 鼠标点击触发拾取再次激活 fbo。 此时所有drawArrays绘制不再画到屏幕而是绘制输出到pickTex纹理把每条线段的 ID 颜色渲染到离屏纹理。readPixels也必须在 fbo 绑定状态下才能读取离屏纹理的像素。gl.bindFramebuffer(gl.FRAMEBUFFER, null)④ 拾取逻辑全部完成再次切回屏幕帧缓冲。 退出 pickLine 之后回到render()正常绘制场景输出到页面 canvas。四处 bindFramebuffer 总结表格序号位置作用①初始化绑定 fbo执行framebufferTexture2D挂载纹理②初始化解绑切回屏幕防止初始化渲染跑到离屏纹理③pickLine 拾取函数开头激活 fbodraw 绘制 ID 颜色、readPixels 读取离屏纹理像素④pickLine 拾取函数末尾解绑切回屏幕后续正常渲染画到页面核心逻辑bindFramebuffer (fbo) “切换输出目标到离屏 FBO”bindFramebuffer (null) “切换输出目标回到浏览器屏幕画布”这个代码有一个严重性能 bug百万线段// pickLine里面 for(let id0; idLINE_COUNT; id){ const color idToColor(id); gl.uniform3fv(uIdColorPick, color); gl.drawArrays(gl.LINES, id*2, 2); }一百万次循环调用 drawArrays百万次 drawcall浏览器会巨卡甚至直接崩溃。正确做法顶点缓冲区里直接预存每一条线的 id 颜色属性一次 drawArrays 全部提交而不是循环一百万次逐个 draw。简单一句话 初始化阶段两次 bindFramebuffer 是为了给 FBO 挂上纹理做完立刻切回屏幕 拾取函数内部两次 bindFramebuffer 是点击的时候临时切到离屏做拾取读完像素马上切回屏幕渲染画面。