WebGL着色器元数据读取:如何读取COLOR_ATTACHMENT1的带符号整数?
问题诊断与修复方案
你的核心问题是多渲染目标配置缺失、读取时未绑定目标FBO、UBO数据传递错误这几个关键问题导致的,以下是针对性修复步骤:
1. 绑定目标FBO后再读取像素
你当前的读取代码没有绑定离屏帧缓冲区(offscreenFramebuffer),readPixels默认读取的是WebGL的默认帧缓冲区(canvas),而非你写入数据的离屏FBO,所以必然得到全0结果。
修复代码:
// 先绑定离屏FBO GL.bindFramebuffer(GL.FRAMEBUFFER, offscreenFramebuffer); GL.readBuffer(GL.COLOR_ATTACHMENT1); const pixel = new Int32Array(4); // 转换鼠标坐标到FBO像素空间(匹配1200x800的FBO尺寸) const rect = GL.canvas.getBoundingClientRect(); const fboX = Math.round((mouse.x - rect.left) * (1200 / rect.width)); const fboY = Math.round((rect.bottom - mouse.y) * (800 / rect.height)); GL.readPixels(fboX, fboY, 1, 1, GL.RGBA_INTEGER, GL.INT, pixel); console.log(pixel); // 解绑FBO GL.bindFramebuffer(GL.FRAMEBUFFER, null);
2. 配置多渲染目标(MRT)的绘制缓冲区
WebGL2默认仅渲染到COLOR_ATTACHMENT0,当片段着色器有多个输出变量时,必须显式指定所有需要渲染的颜色附着点,否则COLOR_ATTACHMENT1不会被写入数据。
修复代码:
在帧缓冲区设置函数中,绑定完所有附着点后添加drawBuffers调用:
function setupFramebuffer(GL) { const w = 1200; const h = 800; // ... 原有纹理、深度缓冲区创建代码 ... const fb = GL.createFramebuffer(); GL.bindFramebuffer(GL.FRAMEBUFFER, fb); // 绑定COLOR_ATTACHMENT0和COLOR_ATTACHMENT1 GL.framebufferTexture2D(GL.FRAMEBUFFER, GL.COLOR_ATTACHMENT0, GL.TEXTURE_2D, offscreenColorTexture, 0); GL.framebufferTexture2D(GL.FRAMEBUFFER, GL.COLOR_ATTACHMENT1, GL.TEXTURE_2D, offscreenCoordTexture, 0); GL.framebufferRenderbuffer(GL.FRAMEBUFFER, GL.DEPTH_ATTACHMENT, GL.RENDERBUFFER, depthBuffer, 0); // 关键:指定要渲染的所有颜色附着点 GL.drawBuffers([GL.COLOR_ATTACHMENT0, GL.COLOR_ATTACHMENT1]); // 检查帧缓冲区完整性(避免静默失败) const status = GL.checkFramebufferStatus(GL.FRAMEBUFFER); if (status !== GL.FRAMEBUFFER_COMPLETE) { console.error(`帧缓冲区创建失败,状态码:${status}`); } GL.bindFramebuffer(GL.FRAMEBUFFER, null); offscreenFramebuffer = fb; }
3. 修正Uniform Buffer(UBO)的数据传递
你的drawVoxel函数中,UBO的bufferData调用参数顺序错误,WebGL要求直接传入TypedArray实例,而非构造函数。同时要遵循std140布局规则(ivec4占16字节,你的数据格式是正确的)。
修复代码:
function drawVoxel(GL, position) { const modelMatrix = Matrix.translate(position.x, position.y, position.z); uniformBuffers.matrices.bufferSubData( GL, GL.UNIFORM_BUFFER, modelMatrix.m, 32 * Float32Array.BYTES_PER_ELEMENT ); // 修正UBO数据传递:直接传入Int32Array实例 uniformBuffers.voxel.bufferData( GL.UNIFORM_BUFFER, new Int32Array([Math.round(position.x), Math.round(position.y), Math.round(position.z), 0]), GL.DYNAMIC_DRAW ); models.cube.render(GL); }
4. 额外验证项
- 确认你的WebGL上下文是WebGL2(
gl = canvas.getContext("webgl2")),WebGL1不支持整数纹理和多渲染目标。 - 渲染体素时必须先绑定
offscreenFramebuffer,否则数据不会写入离屏FBO。
内容的提问来源于stack exchange,提问作者salbeira
相关产品推荐
相关产品推荐

