【问题标题】:WebGL only colors the furthest side, instead of nearest sideWebGL 只为最远的一侧着色,而不是最近的一侧
【发布时间】:2019-01-26 08:20:01
【问题描述】:

我正在使用 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);
}

感谢丹尼斯指出这一点!我还尝试打开和关闭gl.CULL_FACE,并尝试了gl.BACKgl.FRONT。它们都不能正常工作。

  gl.disable(gl.CULL_FACE);
  // gl.cullFace(gl.BACK)

【问题讨论】:

  • 答案取决于您的着色器代码和您指定顶点的方式,请将这些详细信息添加到您的问题中。
  • @idoby谢谢!我已将这些添加到问题中
  • 试试 gl.cullFace(gl.BACK); / gl.cullFace(gl.FRONT) 或玩剔除以查看这是否有助于解决您的问题。很可能您得到了“错误的方式”的顶点,这意味着渲染器将正面视为您认为是正面的三角形的另一面。
  • @Denis 谢谢!我正在尝试这个,抱歉我没有在描述中添加这个。我尝试打开和关闭 gl.CULL_FACE,还尝试了 gl.BACK 和 gl.FRONT。它们都不起作用。
  • “请注意,较小的表面离眼睛较近,较大的表面离眼睛较远。” - 你使用透视投影吗?越远的表面是否越大,但由于透视投影的原因似乎更小?

标签: graphics webgl


【解决方案1】:

我们知道CVV坐标系,未变换的绘图轴 (CVV == 标准视图体积,我们在屏幕上描绘的 +/-1 立方体体积) 具有右手坐标,原点位于 CVV 立方体的中心,x 向右增加,y 向上增加,z 向外增加, 朝向你的眼睛。但是没有必要将 CVV 中具有更大、更正 Z 深度的片段绘制为离我们“更近”,并且在同一屏幕位置具有更小、更负 Z 的片段被重叠。为什么?

WebGL(以及 OpenGL-ES 和 OpenGL)在用于 3D 绘图的其他合理方法中具有历史性的怪癖:它将“深度”定义为介于 0.0 和 1.0 之间的计算值,而不仅仅是 z CVV 坐标中的值。

默认情况下,WebGL 将深度定义为:

  • 0.0 表示“最小”深度,最接近屏幕或摄像头; (CVV 中的z = +1
  • 1.0 表示“最”深度,离屏幕或相机最远; (z = -1 在 CVV 中)

虽然 GPU 会自动计算深度,但正确的结果需要通过 3D 相机投影矩阵转换的顶点来模拟相机镜头。有时,如果我们不定义或不使用投影矩阵,GPU 深度计算会减少为:

depth = 0.5 + 0.5*(gl_position.z / gl.position.w);

换句话说,如果没有这个“相机投影”矩阵,GPU 会计算 'depth' 向后 - 顶点at z = -1 在应该为 1 时得到深度 0。有关 GPU 如何计算深度的更多详细信息,请参阅: How does WebGL set values in the depth buffer?

知道这一点,我们可以很容易地解决这个问题:

  1. 我们可以编写始终设置第一个 ModelMatrix 变换的代码 更改z 的符号,如下所示:myMatrix.setScale(1,1,-1); 然后我们计算的所有z 值都将具有相反的符号。 (与复杂的场景图结合起来有点混乱......)。
  2. 我们可以保持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

【讨论】:

    猜你喜欢
    • 2018-04-28
    • 2012-06-17
    • 1970-01-01
    • 2011-03-19
    • 2015-02-24
    • 2019-04-06
    • 2013-01-04
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多