是否可以在WebGL2中将MSAA渲染为RGBA32F纹理?

时间:2019-03-06 10:22:11

标签: webgl webgl2 hdr msaa

首先,我的msaa运行良好,就像这样(抽象):

    sceneFramebuffer = new MultisampleRenderbuffer({
        msaa: 8,
        internalFormat: "RGBA8"
    });

    blitFramebuffer = new Framebuffer({
        internalFormat: "RGBA8",
        format: "RGBA",
        type: "UNSIGNED_INT"
    });

   Draw scene with sceneFramebuffer;

   sceneFramebuffer.blit(blitFramebuffer);

   Draw blitFramebuffer on the screen quad;

现在,我想为HDR目的将sceneFramebuffer渲染为RGBA32F,并且在尝试这种配置时:

sceneFramebuffer = new MultisampleRenderbuffer({
    msaa: 8
    internalFormat: "RGBA32F"
});

blitFramebuffer = new Framebuffer({
    internalFormat: "RGBA32F",
    format: "RGBA",
    type: "FLOAT"
});

我明白了: GL错误:GL_INVALID_OPERATION:glBlitFramebufferCHROMIUM:颜色的src和dst格式不同

但是,当我为sceneFramebuffer设置 msaa:0 时,它显示了我的场景,但没有msaa的课程平滑处理。

是否有可能将我用于hdr的多重采样和浮点输出相结合?

谢谢!

1 个答案:

答案 0 :(得分:0)

似乎为我工作

function main() {
  const gl = document.querySelector('canvas').getContext('webgl2');
  if (!gl) {
    return alert('need webgl2');
  }
  // without this we can't render to RGBA32F
  if (!gl.getExtension('EXT_color_buffer_float')) {
    return alert('need EXT_color_buffer_float');
  }
  // just guessing without this we can't downsample
  if (!gl.getExtension('OES_texture_float_linear')) {
    return alert('need OES_texture_float_linear');
  }
  
  const msFB = gl.createFramebuffer();
  gl.bindFramebuffer(gl.FRAMEBUFFER, msFB);
  const msRB = gl.createRenderbuffer();
  gl.bindRenderbuffer(gl.RENDERBUFFER, msRB);
  const samples = 4;
  const internalFormat = gl.RGBA32F;
  const width = 16;
  const height = 16;
  gl.renderbufferStorageMultisample(
     gl.RENDERBUFFER, samples, internalFormat, width, height);
  gl.framebufferRenderbuffer(
     gl.FRAMEBUFFER, gl.COLOR_ATTACHMENT0, gl.RENDERBUFFER, msRB);
  checkFramebuffer(gl);
  
  gl.clearColor(1,0,0,1);
  gl.clear(gl.COLOR_BUFFER_BIT);
  
  const texFB = gl.createFramebuffer();
  gl.bindFramebuffer(gl.FRAMEBUFFER, texFB);
  const tex = gl.createTexture();
  gl.bindTexture(gl.TEXTURE_2D, tex);
  const levels = 1;
  gl.texStorage2D(gl.TEXTURE_2D, levels, internalFormat, width, height);
  gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, gl.LINEAR);
  gl.framebufferTexture2D(
      gl.FRAMEBUFFER, gl.COLOR_ATTACHMENT0, gl.TEXTURE_2D, tex, 0);
  
  checkFramebuffer(gl);
  
  // check before
  checkPixel(gl, 'before blit')
  
  gl.bindFramebuffer(gl.READ_FRAMEBUFFER, msFB);
  gl.bindFramebuffer(gl.DRAW_FRAMEBUFFER, texFB);
  gl.blitFramebuffer(
     0, 0, width, height,
     0, 0, width, height,
     gl.COLOR_BUFFER_BIT, gl.LINEAR);
     
  console.log('ERROR?:', glEnumToString(gl, gl.getError()));
  
  gl.bindFramebuffer(gl.FRAMEBUFFER, texFB);
  checkPixel(gl, 'after blit:');
}

function checkFramebuffer(gl) {
  const status = gl.checkFramebufferStatus(gl.FRAMEBUFFER);
  if (status !== gl.FRAMEBUFFER_COMPLETE) {
    console.error(glEnumToString(gl, status));
  }
}

function checkPixel(gl, msg) {
  const pixel = new Float32Array(4);
  gl.readPixels(0, 0, 1, 1, gl.RGBA, gl.FLOAT, pixel);
  console.log(msg, Array.from(pixel).join(', '));
}
  
function glEnumToString(gl, v) {
  const hits = [];
  for (const key in gl) {
    if (gl[key] === v) {
      hits.push(key);
    }
  }
  return hits.length ? hits.join(' | ') : `0x${v.toString(16)}`;
}

main();
<canvas></canvas>

为了明确起见,它与texStorage2D无关

function main() {
  const gl = document.querySelector('canvas').getContext('webgl2');
  if (!gl) {
    return alert('need webgl2');
  }
  // without this we can't render to RGBA32F
  if (!gl.getExtension('EXT_color_buffer_float')) {
    return alert('need EXT_color_buffer_float');
  }
  // just guessing without this we can't downsample
  if (!gl.getExtension('OES_texture_float_linear')) {
    return alert('need OES_texture_float_linear');
  }
  
  const msFB = gl.createFramebuffer();
  gl.bindFramebuffer(gl.FRAMEBUFFER, msFB);
  const msRB = gl.createRenderbuffer();
  gl.bindRenderbuffer(gl.RENDERBUFFER, msRB);
  const samples = 4;
  const internalFormat = gl.RGBA32F;
  const width = 16;
  const height = 16;
  gl.renderbufferStorageMultisample(
     gl.RENDERBUFFER, samples, internalFormat, width, height);
  gl.framebufferRenderbuffer(
     gl.FRAMEBUFFER, gl.COLOR_ATTACHMENT0, gl.RENDERBUFFER, msRB);
  checkFramebuffer(gl);
  
  gl.clearColor(1,0,0,1);
  gl.clear(gl.COLOR_BUFFER_BIT);
  
  const texFB = gl.createFramebuffer();
  gl.bindFramebuffer(gl.FRAMEBUFFER, texFB);
  const tex = gl.createTexture();
  gl.bindTexture(gl.TEXTURE_2D, tex);
  const level = 0;
  gl.texImage2D(gl.TEXTURE_2D, level, internalFormat, width, height, 0,
                gl.RGBA, gl.FLOAT, null);
  gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, gl.LINEAR);
  gl.framebufferTexture2D(
      gl.FRAMEBUFFER, gl.COLOR_ATTACHMENT0, gl.TEXTURE_2D, tex, 0);
  
  checkFramebuffer(gl);
  
  // check before
  checkPixel(gl, 'before blit')
  
  gl.bindFramebuffer(gl.READ_FRAMEBUFFER, msFB);
  gl.bindFramebuffer(gl.DRAW_FRAMEBUFFER, texFB);
  gl.blitFramebuffer(
     0, 0, width, height,
     0, 0, width, height,
     gl.COLOR_BUFFER_BIT, gl.LINEAR);
     
  console.log('ERROR?:', glEnumToString(gl, gl.getError()));
  
  gl.bindFramebuffer(gl.FRAMEBUFFER, texFB);
  checkPixel(gl, 'after blit:');
}

function checkFramebuffer(gl) {
  const status = gl.checkFramebufferStatus(gl.FRAMEBUFFER);
  if (status !== gl.FRAMEBUFFER_COMPLETE) {
    console.error(glEnumToString(gl, status));
  }
}

function checkPixel(gl, msg) {
  const pixel = new Float32Array(4);
  gl.readPixels(0, 0, 1, 1, gl.RGBA, gl.FLOAT, pixel);
  console.log(msg, Array.from(pixel).join(', '));
}
  
function glEnumToString(gl, v) {
  const hits = [];
  for (const key in gl) {
    if (gl[key] === v) {
      hits.push(key);
    }
  }
  return hits.length ? hits.join(' | ') : `0x${v.toString(16)}`;
}

main();
<canvas></canvas>