WebGL 只为最远的边着色,而不是最近的边
WebGL only colors the furthest side, instead of nearest side
我正在使用 WebGL 绘制一个简单的平截头几何体。我试着给前面上色
(小)和背(大)面红色,侧面白色。
这是它的样子。请注意,较小的表面离眼睛较近,较大的表面离眼睛较远。不要被这个图像所迷惑。看起来着色器选择为离眼睛最远的侧面着色,而忽略前面朝上的面孔。
我应该如何使它正常工作?
以下是我的着色器设置:
深度缓冲区在初始化期间被清除并且从未使用过。
function init(){
// Retrieve <canvas> element
var canvas = document.getElementById('webgl');
// Get the rendering context for WebGL
gl = getWebGLContext(canvas);
if (!gl) {
console.log("lib1.js: init() failed to get WebGL rendering context 'gl'\n");
console.log("from the HTML-5 Canvas object named 'canvas'!\n\n");
return;
}
// Initialize shaders
if (!initShaders(gl, VSHADER_SOURCE, FSHADER_SOURCE)) {
console.log('lib1.js: init() failed to intialize shaders.');
return;
}
bufferSetup(gl);
// Set the background-clearing color and enable the depth test
gl.clearColor(0.0, 0.0, 0.0, 1.0); // black!
gl.enable(gl.DEPTH_TEST);
gl.enable(gl.CULL_FACE); // draw the back side of triangles
gl.clear(gl.COLOR_BUFFER_BIT | gl.DEPTH_BUFFER_BIT);
}
感谢 Denis 指出这一点!我还尝试打开和关闭 gl.CULL_FACE
,并尝试了 gl.BACK
和 gl.FRONT
。 None 个正常工作。
gl.disable(gl.CULL_FACE);
// gl.cullFace(gl.BACK)
我们知道CVV坐标系,非变换绘图轴
(CVV == 规范视图体积,我们在屏幕上描绘的 +/-1 立方体体积)
具有右手坐标,原点位于 CVV 立方体的中心,x 向右增加,y 向上增加,z 向外增加,
朝向你的眼睛。但是对于我们来说,CVV 中具有更大、更正 Z 深度的片段没有必要被绘制为 'nearer',并且在同一屏幕位置具有更小、更负 Z 的片段被重叠。为什么?
WebGL(以及 OpenGL-ES 和 OpenGL)在 3D 绘图的其他方面是明智的方法有一个历史怪癖:它将 'depth' 定义为 0.0 和 1.0 之间的计算值,它不仅仅是CVV 坐标中的 z
值。
默认情况下,WebGL 将深度定义为:
- 0.0 对于 'least' 深度,最近的屏幕或相机; (CVV 中的
z = +1
)
- 1.0 'most' 深度,离屏幕或相机最远; (CVV 中的
z = -1
)
虽然 GPU 会自动计算深度,但正确的结果需要由 3D 相机投影矩阵转换的顶点来模拟相机镜头。有时,如果我们没有定义或使用投影矩阵,GPU 深度计算会减少到:
depth = 0.5 + 0.5*(gl_position.z / gl.position.w);
换句话说,没有这个'camera-projection'矩阵,GPU计算
'depth' backwards -- 顶点 at z = -1
在深度应该为 1 时获得 0。有关 GPU 如何计算深度的更多详细信息,请参阅:
知道这一点,我们可以通过以下任一方式轻松解决此问题:
- 我们可以编写始终设置第一个 ModelMatrix 变换的代码
改变
z
的符号,像这样:myMatrix.setScale(1,1,-1)
;
然后我们计算的所有 z
值都将反转符号。
(当结合复杂的场景图时,这有点混乱......)。
- 我们可以保留
z
值不变,而是告诉 WebGL
对深度缓冲区的使用应用不同的规则;这是一个更明智的解决方案。尝试添加这些代码行
gl.enable(gl.DEPTH_TEST); // enabled by default, but let's be SURE.
gl.clearDepth(0.0); // each time we 'clear' our depth buffer, set all
// pixel depths to 0.0 (1.0 is DEFAULT)
gl.depthFunc(gl.GREATER); // gl.LESS is DEFAULT; reverse it!
// draw a pixel only if its depth value is GREATER
// than the depth buffer's stored value.
感谢我的计算机图形学教授 - John E. Tumblin
我正在使用 WebGL 绘制一个简单的平截头几何体。我试着给前面上色 (小)和背(大)面红色,侧面白色。
这是它的样子。请注意,较小的表面离眼睛较近,较大的表面离眼睛较远。不要被这个图像所迷惑。看起来着色器选择为离眼睛最远的侧面着色,而忽略前面朝上的面孔。
我应该如何使它正常工作?
以下是我的着色器设置: 深度缓冲区在初始化期间被清除并且从未使用过。
function init(){
// Retrieve <canvas> element
var canvas = document.getElementById('webgl');
// Get the rendering context for WebGL
gl = getWebGLContext(canvas);
if (!gl) {
console.log("lib1.js: init() failed to get WebGL rendering context 'gl'\n");
console.log("from the HTML-5 Canvas object named 'canvas'!\n\n");
return;
}
// Initialize shaders
if (!initShaders(gl, VSHADER_SOURCE, FSHADER_SOURCE)) {
console.log('lib1.js: init() failed to intialize shaders.');
return;
}
bufferSetup(gl);
// Set the background-clearing color and enable the depth test
gl.clearColor(0.0, 0.0, 0.0, 1.0); // black!
gl.enable(gl.DEPTH_TEST);
gl.enable(gl.CULL_FACE); // draw the back side of triangles
gl.clear(gl.COLOR_BUFFER_BIT | gl.DEPTH_BUFFER_BIT);
}
感谢 Denis 指出这一点!我还尝试打开和关闭 gl.CULL_FACE
,并尝试了 gl.BACK
和 gl.FRONT
。 None 个正常工作。
gl.disable(gl.CULL_FACE);
// gl.cullFace(gl.BACK)
我们知道CVV坐标系,非变换绘图轴 (CVV == 规范视图体积,我们在屏幕上描绘的 +/-1 立方体体积) 具有右手坐标,原点位于 CVV 立方体的中心,x 向右增加,y 向上增加,z 向外增加, 朝向你的眼睛。但是对于我们来说,CVV 中具有更大、更正 Z 深度的片段没有必要被绘制为 'nearer',并且在同一屏幕位置具有更小、更负 Z 的片段被重叠。为什么?
WebGL(以及 OpenGL-ES 和 OpenGL)在 3D 绘图的其他方面是明智的方法有一个历史怪癖:它将 'depth' 定义为 0.0 和 1.0 之间的计算值,它不仅仅是CVV 坐标中的 z
值。
默认情况下,WebGL 将深度定义为:
- 0.0 对于 'least' 深度,最近的屏幕或相机; (CVV 中的
z = +1
) - 1.0 'most' 深度,离屏幕或相机最远; (CVV 中的
z = -1
)
虽然 GPU 会自动计算深度,但正确的结果需要由 3D 相机投影矩阵转换的顶点来模拟相机镜头。有时,如果我们没有定义或使用投影矩阵,GPU 深度计算会减少到:
depth = 0.5 + 0.5*(gl_position.z / gl.position.w);
换句话说,没有这个'camera-projection'矩阵,GPU计算
'depth' backwards -- 顶点 at z = -1
在深度应该为 1 时获得 0。有关 GPU 如何计算深度的更多详细信息,请参阅:
知道这一点,我们可以通过以下任一方式轻松解决此问题:
- 我们可以编写始终设置第一个 ModelMatrix 变换的代码
改变
z
的符号,像这样:myMatrix.setScale(1,1,-1)
; 然后我们计算的所有z
值都将反转符号。 (当结合复杂的场景图时,这有点混乱......)。 - 我们可以保留
z
值不变,而是告诉 WebGL 对深度缓冲区的使用应用不同的规则;这是一个更明智的解决方案。尝试添加这些代码行
gl.enable(gl.DEPTH_TEST); // enabled by default, but let's be SURE.
gl.clearDepth(0.0); // each time we 'clear' our depth buffer, set all
// pixel depths to 0.0 (1.0 is DEFAULT)
gl.depthFunc(gl.GREATER); // gl.LESS is DEFAULT; reverse it!
// draw a pixel only if its depth value is GREATER
// than the depth buffer's stored value.
感谢我的计算机图形学教授 - John E. Tumblin