在尝试创建可在移动平台上运行的VSM阴影时,我正在探索24位深度纹理存储瞬间的可能性(某些移动平台不支持浮点纹理)。
问题是我需要带阴影的全景灯,这意味着我需要立方体贴图(理想情况下)。至少firefox似乎不支持这一点,将Error: WebGL warning: texImage2D: With format DEPTH_COMPONENT24, this function may only be called with target=TEXTURE_2D, data=null, and level=0.
打印到控制台。
我用DEPTH_COMPONENT作为格式和内部格式调用gl.texImage2D。对于类型I,尝试过gl.UNSIGNED_SHORT,gl.UNSIGNED_INT和ext.UNSIGNED_INT_24_8_WEBGL,都无济于事。
我可以将立方体的边缘映射到2d纹理,并为每边添加边距以避免插值伪影,但这似乎过于复杂且难以维护。
是否有其他解决方法可以使用DEPTH_COMPONENT格式的采样器多维数据集?
这适用于WebGL 1
编辑:我在gman的答案中对代码做了一些修改,以更好地反映我的问题。 Here是一个小人物。它似乎适用于chrome(红色背景上的深红色立方体),但不适用于Firefox(一切都是黑色)。答案 0 :(得分:2)
如果要使用深度纹理,则需要尝试启用WEBGL_depth_texture
extension。请注意many mobile devices don't support depth textures。 (单击左上角的过滤器)
然后,according to the spec,您不能将DEPTH_COMPONENT24
传递给texImage2D
。在传递DEPTH_COMPONENT
和类型gl.UNSIGNED_SHORT
或gl.UNSIGNED_INT
中,实现选择位深度。您可以通过致电gl.getParameter(gl.DEPTH_BITS)
;
function main() {
const m4 = twgl.m4;
const v3 = twgl.v3;
const gl = document.querySelector("canvas").getContext("webgl");
const ext = gl.getExtension("WEBGL_depth_texture");
if (!ext) {
alert("Need WEBGL_depth_texture");
return;
}
const width = 128;
const height = 128;
const depthTex = gl.createTexture();
gl.bindTexture(gl.TEXTURE_2D, depthTex);
gl.texImage2D(gl.TEXTURE_2D, 0, gl.DEPTH_COMPONENT, width, height, 0,
gl.DEPTH_COMPONENT, gl.UNSIGNED_INT, null);
// calls gl.bindTexture, gl.texParameteri
twgl.setTextureParameters(gl, depthTex, {
minMag: gl.NEAREST,
wrap: gl.CLAMP_TO_EDGE,
});
// calls gl.createTexture, gl.bindTexture, gl.texImage2D, gl.texParameteri
const cubeTex = twgl.createTexture(gl, {
target: gl.TEXTURE_CUBE_MAP,
minMag: gl.NEAREST,
wrap: gl.CLAMP_TO_EDGE,
width: width,
height: height,
});
const faces = [
gl.TEXTURE_CUBE_MAP_POSITIVE_X,
gl.TEXTURE_CUBE_MAP_NEGATIVE_X,
gl.TEXTURE_CUBE_MAP_POSITIVE_Y,
gl.TEXTURE_CUBE_MAP_NEGATIVE_Y,
gl.TEXTURE_CUBE_MAP_POSITIVE_Z,
gl.TEXTURE_CUBE_MAP_NEGATIVE_Z,
];
const fbs = faces.map(face => {
const fb = gl.createFramebuffer();
gl.bindFramebuffer(gl.FRAMEBUFFER, fb);
gl.framebufferTexture2D(gl.FRAMEBUFFER, gl.COLOR_ATTACHMENT0, face, cubeTex, 0);
gl.framebufferTexture2D(gl.FRAMEBUFFER, gl.DEPTH_ATTACHMENT, gl.TEXTURE_2D, depthTex, 0);
const status = gl.checkFramebufferStatus(gl.FRAMEBUFFER);
if (status !== gl.FRAMEBUFFER_COMPLETE) {
console.log("can't use this framebuffer attachment combo");
}
return fb;
});
const vs = `
attribute vec4 position;
attribute vec3 normal;
uniform mat4 u_worldViewProjection;
uniform mat4 u_worldInverseTranspose;
varying vec3 v_normal;
void main() {
gl_Position = u_worldViewProjection * position;
v_normal = (u_worldInverseTranspose * vec4(normal, 0)).xyz;
}
`;
const fs = `
precision mediump float;
uniform vec3 u_color;
uniform vec3 u_lightDir;
varying vec3 v_normal;
void main() {
float light = dot(u_lightDir, normalize(v_normal)) * .5 + .5;
gl_FragColor = vec4(u_color * light, 1);
}
`;
const vs2 = `
attribute vec4 position;
uniform mat4 u_matrix;
varying vec3 v_texcoord;
void main() {
gl_Position = u_matrix * position;
v_texcoord = position.xyz;
}
`;
const fs2 = `
precision mediump float;
uniform samplerCube u_cube;
varying vec3 v_texcoord;
void main() {
gl_FragColor = textureCube(u_cube, normalize(v_texcoord));
}
`;
// compile shaders, links program, looks up locations
const colorProgramInfo = twgl.createProgramInfo(gl, [vs, fs]);
// compile shaders, links program, looks up locations
const cubeProgramInfo = twgl.createProgramInfo(gl, [vs2, fs2]);
// calls gl.createBuffer, gl.bindBuffer, gl.bufferData
const cubeBufferInfo = twgl.primitives.createCubeBufferInfo(gl);
function render(time) {
time *= 0.001; // seconds
gl.enable(gl.DEPTH_TEST);
gl.useProgram(colorProgramInfo.program);
// calls gl.bindBuffer, gl.enableVertexAttribArray, gl.vertexAttribPointer
twgl.setBuffersAndAttributes(gl, colorProgramInfo, cubeBufferInfo);
// draw a different color on each face
faces.forEach((face, ndx) => {
const c = ndx + 1;
const color = [
(c & 0x1) ? 1 : 0,
(c & 0x2) ? 1 : 0,
(c & 0x4) ? 1 : 0,
];
gl.bindFramebuffer(gl.FRAMEBUFFER, fbs[ndx]);
gl.viewport(0, 0, width, height);
gl.clearColor(1 - color[0], 1 - color[1], 1 - color[2], 1);
gl.clear(gl.COLOR_BUFFER_BIT | gl.DEPTH_BUFFER_BIT);
const fov = Math.PI * 0.25;
const aspect = width / height;
const zNear = 0.001;
const zFar = 100;
const projection = m4.perspective(fov, aspect, zNear, zFar);
const world = m4.translation([0, 0, -3]);
m4.rotateY(world, Math.PI * .1 * c * time, world);
m4.rotateX(world, Math.PI * .15 * c * time, world);
// calls gl.uniformXXX
twgl.setUniforms(colorProgramInfo, {
u_color: color,
u_lightDir: v3.normalize([1, 5, 10]),
u_worldViewProjection: m4.multiply(projection, world),
u_worldInverseTranspose: m4.transpose(m4.inverse(world)),
});
// calls gl.drawArrays or gl.drawElements
twgl.drawBufferInfo(gl, cubeBufferInfo);
});
gl.bindFramebuffer(gl.FRAMEBUFFER, null);
gl.viewport(0, 0, gl.canvas.width, gl.canvas.height);
gl.clearColor(0, 0, 0, 0);
gl.clear(gl.COLOR_BUFFER_BIT | gl.DEPTH_BUFFER_BIT);
gl.useProgram(cubeProgramInfo.program);
// calls gl.bindBuffer, gl.enableVertexAttribArray, gl.vertexAttribPointer
twgl.setBuffersAndAttributes(gl, cubeProgramInfo, cubeBufferInfo);
const fov = Math.PI * 0.25;
const aspect = gl.canvas.clientWidth / gl.canvas.clientHeight;
const zNear = 0.001;
const zFar = 10;
const mat = m4.perspective(fov, aspect, zNear, zFar);
m4.translate(mat, [0, 0, -2], mat);
m4.rotateY(mat, Math.PI * .25 * time, mat);
m4.rotateX(mat, Math.PI * .25 * time, mat);
twgl.setUniforms(cubeProgramInfo, {
u_cube: cubeTex,
u_matrix: mat,
});
// calls gl.drawArrays or gl.drawElements
twgl.drawBufferInfo(gl, cubeBufferInfo);
requestAnimationFrame(render);
}
requestAnimationFrame(render);
}
main();

canvas { border: 1px solid black; }

<script src="https://twgljs.org/dist/3.x/twgl-full.min.js"></script>
<canvas></canvas>
&#13;
否则您可以使用深度渲染缓冲区。 Where's an example code is here和code that creates the framebuffers for the cubemap is here。
。the spec对于立方体贴图深度纹理here,具体说只支持TEXTURE_2D
。
在以下情况下会生成错误INVALID_OPERATION:
使用DEPTH_COMPONENT的格式和内部格式调用
- texImage2D 或DEPTH_STENCIL和目标不是TEXTURE_2D,
您可能必须切换到WebGL2。它适用于firefox和chrome
function main() {
const m4 = twgl.m4;
const v3 = twgl.v3;
const gl = document.querySelector("canvas").getContext("webgl2");
const width = 128;
const height = 128;
const colorTex = twgl.createTexture(gl, {
target: gl.TEXTURE_CUBE_MAP,
minMag: gl.NEAREST,
wrap: gl.CLAMP_TO_EDGE,
width: width,
height: height,
});
// calls gl.createTexture, gl.bindTexture, gl.texImage2D, gl.texParameteri
const depthTex = twgl.createTexture(gl, {
target: gl.TEXTURE_CUBE_MAP,
internalFormat: gl.DEPTH_COMPONENT24,
format: gl.DEPTH_COMPONENT,
type: gl.UNSIGNED_INT,
width: width,
height: height,
wrap: gl.CLAMP_TO_EDGE,
minMax: gl.NEAREST,
});
const faces = [
gl.TEXTURE_CUBE_MAP_POSITIVE_X,
gl.TEXTURE_CUBE_MAP_NEGATIVE_X,
gl.TEXTURE_CUBE_MAP_POSITIVE_Y,
gl.TEXTURE_CUBE_MAP_NEGATIVE_Y,
gl.TEXTURE_CUBE_MAP_POSITIVE_Z,
gl.TEXTURE_CUBE_MAP_NEGATIVE_Z,
];
const fbs = faces.map(face => {
const fb = gl.createFramebuffer();
gl.bindFramebuffer(gl.FRAMEBUFFER, fb);
gl.framebufferTexture2D(gl.FRAMEBUFFER, gl.COLOR_ATTACHMENT0, face, colorTex, 0);
gl.framebufferTexture2D(gl.FRAMEBUFFER, gl.DEPTH_ATTACHMENT, face, depthTex, 0);
const status = gl.checkFramebufferStatus(gl.FRAMEBUFFER);
if (status !== gl.FRAMEBUFFER_COMPLETE) {
console.log("can't use this framebuffer attachment combo");
}
return fb;
});
const vs = `
attribute vec4 position;
attribute vec3 normal;
uniform mat4 u_worldViewProjection;
uniform mat4 u_worldInverseTranspose;
varying vec3 v_normal;
void main() {
gl_Position = u_worldViewProjection * position;
gl_Position.z = 0.5;
v_normal = (u_worldInverseTranspose * vec4(normal, 0)).xyz;
}
`;
const fs = `
precision mediump float;
uniform vec3 u_color;
uniform vec3 u_lightDir;
varying vec3 v_normal;
void main() {
float light = dot(u_lightDir, normalize(v_normal)) * .5 + .5;
gl_FragColor = vec4(u_color * light, 1);
}
`;
const vs2 = `
attribute vec4 position;
uniform mat4 u_matrix;
varying vec3 v_texcoord;
void main() {
gl_Position = u_matrix * position;
v_texcoord = position.xyz;
}
`;
const fs2 = `
precision mediump float;
uniform samplerCube u_cube;
varying vec3 v_texcoord;
void main() {
gl_FragColor = textureCube(u_cube, normalize(v_texcoord)) / vec4(2.0, 1.0, 1.0, 1.0);
}
`;
// compile shaders, links program, looks up locations
const colorProgramInfo = twgl.createProgramInfo(gl, [vs, fs]);
// compile shaders, links program, looks up locations
const cubeProgramInfo = twgl.createProgramInfo(gl, [vs2, fs2]);
// calls gl.createBuffer, gl.bindBuffer, gl.bufferData
const cubeBufferInfo = twgl.primitives.createCubeBufferInfo(gl);
function render(time) {
time *= 0.001; // seconds
gl.enable(gl.DEPTH_TEST);
gl.enable(gl.CULL_FACE);
gl.useProgram(colorProgramInfo.program);
// calls gl.bindBuffer, gl.enableVertexAttribArray, gl.vertexAttribPointer
twgl.setBuffersAndAttributes(gl, colorProgramInfo, cubeBufferInfo);
// draw a different color on each face
faces.forEach((face, ndx) => {
const c = ndx + 1;
const color = [
(c & 0x1) ? 1 : 0,
(c & 0x2) ? 1 : 0,
(c & 0x4) ? 1 : 0,
];
gl.bindFramebuffer(gl.FRAMEBUFFER, fbs[ndx]);
gl.viewport(0, 0, width, height);
gl.clearColor(1 - color[0], 1 - color[1], 1 - color[2], 1);
gl.clear(gl.COLOR_BUFFER_BIT | gl.DEPTH_BUFFER_BIT);
const fov = Math.PI * 0.25;
const aspect = width / height;
const zNear = 0.001;
const zFar = 100;
const projection = m4.perspective(fov, aspect, zNear, zFar);
const world = m4.translation([0, 0, -3]);
m4.rotateY(world, Math.PI * .1 * c * time, world);
m4.rotateX(world, Math.PI * .15 * c * time, world);
// calls gl.uniformXXX
twgl.setUniforms(colorProgramInfo, {
u_color: color,
u_lightDir: v3.normalize([1, 5, 10]),
u_worldViewProjection: m4.multiply(projection, world),
u_worldInverseTranspose: m4.transpose(m4.inverse(world)),
});
// calls gl.drawArrays or gl.drawElements
twgl.drawBufferInfo(gl, cubeBufferInfo);
});
gl.bindFramebuffer(gl.FRAMEBUFFER, null);
gl.viewport(0, 0, gl.canvas.width, gl.canvas.height);
gl.clearColor(0, 0, 0, 0);
gl.clear(gl.COLOR_BUFFER_BIT | gl.DEPTH_BUFFER_BIT);
gl.useProgram(cubeProgramInfo.program);
// calls gl.bindBuffer, gl.enableVertexAttribArray, gl.vertexAttribPointer
twgl.setBuffersAndAttributes(gl, cubeProgramInfo, cubeBufferInfo);
const fov = Math.PI * 0.25;
const aspect = gl.canvas.clientWidth / gl.canvas.clientHeight;
const zNear = 0.001;
const zFar = 10;
const mat = m4.perspective(fov, aspect, zNear, zFar);
m4.translate(mat, [0, 0, -2], mat);
m4.rotateY(mat, Math.PI * .25 * time, mat);
m4.rotateX(mat, Math.PI * .25 * time, mat);
twgl.setUniforms(cubeProgramInfo, {
u_cube: colorTex,
u_matrix: mat,
});
// calls gl.drawArrays or gl.drawElements
twgl.drawBufferInfo(gl, cubeBufferInfo);
requestAnimationFrame(render);
}
requestAnimationFrame(render);
}
main();
&#13;
canvas { border: 1px solid black; }
&#13;
<script src="https://twgljs.org/dist/3.x/twgl-full.min.js"></script>
<canvas></canvas>
&#13;