是否可以在 WebGL2 中将 MSAA 渲染为 RGBA32F 纹理?
Is it possible to render MSAA to RGBA32F texture in WebGL2?
首先,我的 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;
现在,我想将 sceneFramebuffer 渲染为 RGBA32F 以用于 HDR 目的,当我尝试此配置时:
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?
谢谢!
似乎对我有用
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>
首先,我的 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;
现在,我想将 sceneFramebuffer 渲染为 RGBA32F 以用于 HDR 目的,当我尝试此配置时:
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?
谢谢!
似乎对我有用
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>