You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.03 11:02:33