渲染到立方体贴图的非零 mip 级别
Render to a non-zero mip level of a cube map
我正在尝试将环境贴图渲染到单独的立方体贴图 mip 级别。
const levels = 8;
const width = 128;
const height = 128;
const internalFormat = gl.RGBA8;
const type = gl.UNSIGNED_BYTE;
const format = gl.RGBA;
const bindingPoint = gl.TEXTURE_CUBE_MAP;
const level = 1;
const target = gl.TEXTURE_CUBE_MAP_POSITIVE_X + 0;
const magFilter = gl.LINEAR;
const minFilter = gl.LINEAR_MIPMAP_LINEAR;
const wrapS = gl.CLAMP_TO_EDGE;
const wrapT = gl.CLAMP_TO_EDGE;
const texId = gl.createTexture();
gl.bindTexture(bindingPoint, texId);
gl.texParameteri(bindingPoint, gl.TEXTURE_WRAP_S, wrapS);
gl.texParameteri(bindingPoint, gl.TEXTURE_WRAP_T, wrapT);
gl.texParameteri(bindingPoint, gl.TEXTURE_MIN_FILTER, minFilter);
gl.texParameteri(bindingPoint, gl.TEXTURE_MAG_FILTER, magFilter);
gl.texStorage2D(bindingPoint, levels, internalFormat, width, height);
const framebuffer = gl.createFramebuffer();
gl.bindFramebuffer(gl.FRAMEBUFFER, framebuffer);
gl.framebufferTexture2D(gl.FRAMEBUFFER, gl.COLOR_ATTACHMENT0, target, texId, level);
const status = gl.checkFramebufferStatus(gl.FRAMEBUFFER);
console.assert(status === gl.FRAMEBUFFER_COMPLETE, 'incomplete!');
gl.viewport(0, 0, width/2, height/2);
// cube rendering
毕竟,我通过 textureLod()
传递级别作为第三个参数在片段着色器中读取它。但结果是黑色而不是适当的环境颜色。
根据 this 它必须起作用,但它不起作用。
在 Chromium 70.0.3538.110 版本和 Firefox 63.0.3 上测试。
我没有发现您发布的代码有任何问题。它对我有用。也许问题出在其他地方?还是您的驱动程序中的错误?
const gl = document.createElement('canvas').getContext('webgl2');
console.assert(gl !== null, 'no webgl2');
const levels = 8;
const width = 128;
const height = 128;
const internalFormat = gl.RGBA8;
const type = gl.UNSIGNED_BYTE;
const format = gl.RGBA;
const bindingPoint = gl.TEXTURE_CUBE_MAP;
const magFilter = gl.LINEAR;
const minFilter = gl.LINEAR_MIPMAP_LINEAR;
const wrapS = gl.CLAMP_TO_EDGE;
const wrapT = gl.CLAMP_TO_EDGE;
const texId = gl.createTexture();
gl.bindTexture(bindingPoint, texId);
gl.texParameteri(bindingPoint, gl.TEXTURE_WRAP_S, wrapS);
gl.texParameteri(bindingPoint, gl.TEXTURE_WRAP_T, wrapT);
gl.texParameteri(bindingPoint, gl.TEXTURE_MIN_FILTER, minFilter);
gl.texParameteri(bindingPoint, gl.TEXTURE_MAG_FILTER, magFilter);
gl.texStorage2D(bindingPoint, levels, internalFormat, width, height);
const levelFaceFBs = [];
for (let level = 0; level < levels; ++level) {
const faceFBs = [];
for (let face = 0; face < 6; ++face) {
const framebuffer = gl.createFramebuffer();
const target = gl.TEXTURE_CUBE_MAP_POSITIVE_X + face;
gl.bindFramebuffer(gl.FRAMEBUFFER, framebuffer);
gl.framebufferTexture2D(
gl.FRAMEBUFFER, gl.COLOR_ATTACHMENT0,
target, texId, level);
const status = gl.checkFramebufferStatus(gl.FRAMEBUFFER);
console.assert(status === gl.FRAMEBUFFER_COMPLETE, 'incomplete!');
const c = face + level;
gl.clearColor(
c & 1 ? 1 : 0,
c & 2 ? 1 : 0,
c & 4 ? 1 : 0,
(level + 1) / levels);
gl.clear(gl.COLOR_BUFFER_BIT);
faceFBs.push(framebuffer);
}
levelFaceFBs.push(faceFBs);
}
log('--> based on clear');
dumpAll();
renderToAll();
log('--> based on render');
dumpAll();
log(gl.getError(), '<- 0 = no errors')
function renderToAll() {
const vs = `
void main() {
gl_PointSize = 10.0;
gl_Position = vec4(-1, -1, 0, 1);
}
`;
const fs = `
precision mediump float;
uniform vec4 color;
void main() {
gl_FragColor = color;
}
`;
const programInfo = twgl.createProgramInfo(gl, [vs, fs]);
gl.useProgram(programInfo.program);
// render to every face at every level
levelFaceFBs.forEach((faceFBs, l) => {
faceFBs.forEach((faceFB, f) => {
gl.bindFramebuffer(gl.FRAMEBUFFER, faceFB);
gl.viewport(0, 0, width >> l, height >> l);
const c = f + l;
twgl.setUniforms(programInfo, {
color: [
c & 1 ? .2 : .7,
c & 2 ? .2 : .7,
c & 4 ? .2 : .7,
(levels - l) / levels,
],
});
gl.drawArrays(gl.POINTS, 0, 1);
});
});
}
function dumpAll() {
// get color of every face at every level
levelFaceFBs.forEach((faceFBs, l) => {
faceFBs.forEach((faceFB, f) => {
gl.bindFramebuffer(gl.FRAMEBUFFER, faceFB);
const pixel = new Uint8Array(4);
gl.readPixels(0, 0, 1, 1, gl.RGBA, gl.UNSIGNED_BYTE, pixel);
log('level:', l, 'face:', f, 'color:', pixel);
});
});
}
function log(...args) {
const elem = document.createElement('pre');
elem.textContent = [...args].join(' ');
document.body.appendChild(elem);
}
pre { margin: 0; }
<script src="https://twgljs.org/dist/4.x/twgl.min.js"></script>
我正在尝试将环境贴图渲染到单独的立方体贴图 mip 级别。
const levels = 8;
const width = 128;
const height = 128;
const internalFormat = gl.RGBA8;
const type = gl.UNSIGNED_BYTE;
const format = gl.RGBA;
const bindingPoint = gl.TEXTURE_CUBE_MAP;
const level = 1;
const target = gl.TEXTURE_CUBE_MAP_POSITIVE_X + 0;
const magFilter = gl.LINEAR;
const minFilter = gl.LINEAR_MIPMAP_LINEAR;
const wrapS = gl.CLAMP_TO_EDGE;
const wrapT = gl.CLAMP_TO_EDGE;
const texId = gl.createTexture();
gl.bindTexture(bindingPoint, texId);
gl.texParameteri(bindingPoint, gl.TEXTURE_WRAP_S, wrapS);
gl.texParameteri(bindingPoint, gl.TEXTURE_WRAP_T, wrapT);
gl.texParameteri(bindingPoint, gl.TEXTURE_MIN_FILTER, minFilter);
gl.texParameteri(bindingPoint, gl.TEXTURE_MAG_FILTER, magFilter);
gl.texStorage2D(bindingPoint, levels, internalFormat, width, height);
const framebuffer = gl.createFramebuffer();
gl.bindFramebuffer(gl.FRAMEBUFFER, framebuffer);
gl.framebufferTexture2D(gl.FRAMEBUFFER, gl.COLOR_ATTACHMENT0, target, texId, level);
const status = gl.checkFramebufferStatus(gl.FRAMEBUFFER);
console.assert(status === gl.FRAMEBUFFER_COMPLETE, 'incomplete!');
gl.viewport(0, 0, width/2, height/2);
// cube rendering
毕竟,我通过 textureLod()
传递级别作为第三个参数在片段着色器中读取它。但结果是黑色而不是适当的环境颜色。
根据 this 它必须起作用,但它不起作用。
在 Chromium 70.0.3538.110 版本和 Firefox 63.0.3 上测试。
我没有发现您发布的代码有任何问题。它对我有用。也许问题出在其他地方?还是您的驱动程序中的错误?
const gl = document.createElement('canvas').getContext('webgl2');
console.assert(gl !== null, 'no webgl2');
const levels = 8;
const width = 128;
const height = 128;
const internalFormat = gl.RGBA8;
const type = gl.UNSIGNED_BYTE;
const format = gl.RGBA;
const bindingPoint = gl.TEXTURE_CUBE_MAP;
const magFilter = gl.LINEAR;
const minFilter = gl.LINEAR_MIPMAP_LINEAR;
const wrapS = gl.CLAMP_TO_EDGE;
const wrapT = gl.CLAMP_TO_EDGE;
const texId = gl.createTexture();
gl.bindTexture(bindingPoint, texId);
gl.texParameteri(bindingPoint, gl.TEXTURE_WRAP_S, wrapS);
gl.texParameteri(bindingPoint, gl.TEXTURE_WRAP_T, wrapT);
gl.texParameteri(bindingPoint, gl.TEXTURE_MIN_FILTER, minFilter);
gl.texParameteri(bindingPoint, gl.TEXTURE_MAG_FILTER, magFilter);
gl.texStorage2D(bindingPoint, levels, internalFormat, width, height);
const levelFaceFBs = [];
for (let level = 0; level < levels; ++level) {
const faceFBs = [];
for (let face = 0; face < 6; ++face) {
const framebuffer = gl.createFramebuffer();
const target = gl.TEXTURE_CUBE_MAP_POSITIVE_X + face;
gl.bindFramebuffer(gl.FRAMEBUFFER, framebuffer);
gl.framebufferTexture2D(
gl.FRAMEBUFFER, gl.COLOR_ATTACHMENT0,
target, texId, level);
const status = gl.checkFramebufferStatus(gl.FRAMEBUFFER);
console.assert(status === gl.FRAMEBUFFER_COMPLETE, 'incomplete!');
const c = face + level;
gl.clearColor(
c & 1 ? 1 : 0,
c & 2 ? 1 : 0,
c & 4 ? 1 : 0,
(level + 1) / levels);
gl.clear(gl.COLOR_BUFFER_BIT);
faceFBs.push(framebuffer);
}
levelFaceFBs.push(faceFBs);
}
log('--> based on clear');
dumpAll();
renderToAll();
log('--> based on render');
dumpAll();
log(gl.getError(), '<- 0 = no errors')
function renderToAll() {
const vs = `
void main() {
gl_PointSize = 10.0;
gl_Position = vec4(-1, -1, 0, 1);
}
`;
const fs = `
precision mediump float;
uniform vec4 color;
void main() {
gl_FragColor = color;
}
`;
const programInfo = twgl.createProgramInfo(gl, [vs, fs]);
gl.useProgram(programInfo.program);
// render to every face at every level
levelFaceFBs.forEach((faceFBs, l) => {
faceFBs.forEach((faceFB, f) => {
gl.bindFramebuffer(gl.FRAMEBUFFER, faceFB);
gl.viewport(0, 0, width >> l, height >> l);
const c = f + l;
twgl.setUniforms(programInfo, {
color: [
c & 1 ? .2 : .7,
c & 2 ? .2 : .7,
c & 4 ? .2 : .7,
(levels - l) / levels,
],
});
gl.drawArrays(gl.POINTS, 0, 1);
});
});
}
function dumpAll() {
// get color of every face at every level
levelFaceFBs.forEach((faceFBs, l) => {
faceFBs.forEach((faceFB, f) => {
gl.bindFramebuffer(gl.FRAMEBUFFER, faceFB);
const pixel = new Uint8Array(4);
gl.readPixels(0, 0, 1, 1, gl.RGBA, gl.UNSIGNED_BYTE, pixel);
log('level:', l, 'face:', f, 'color:', pixel);
});
});
}
function log(...args) {
const elem = document.createElement('pre');
elem.textContent = [...args].join(' ');
document.body.appendChild(elem);
}
pre { margin: 0; }
<script src="https://twgljs.org/dist/4.x/twgl.min.js"></script>