1

我希望在 WebGL 的 xy 平面 (z=0) 上绘制 2D 形状。

我正在从这里阅读。

这是我的drawScene函数:

function drawScene() {
    gl.viewport(0, 0, gl.viewportWidth, gl.viewportHeight);
    gl.clear(gl.COLOR_BUFFER_BIT | gl.DEPTH_BUFFER_BIT);

    mat4.perspective(45, gl.viewportWidth / gl.viewportHeight, 0.1, 100.0, pMatrix);

    mat4.identity(mvMatrix);
    mat4.translate(mvMatrix, [2.0, 5.0, -1.0]);

    mvPushMatrix();
    gl.bindBuffer(gl.ARRAY_BUFFER, squareVertexPositionBuffer);
    gl.vertexAttribPointer(shaderProgram.vertexPositionAttribute, squareVertexPositionBuffer.itemSize, gl.FLOAT, false, 0, 0);

    gl.bindBuffer(gl.ARRAY_BUFFER, squareVertexColorBuffer);
    gl.vertexAttribPointer(shaderProgram.vertexColorAttribute,squareVertexColorBuffer.itemSize, gl.FLOAT, false, 0, 0);

    setMatrixUniforms();
    gl.drawArrays(gl.TRIANGLE_FAN, 0, squareVertexPositionBuffer.numItems);

        mvPopMatrix();
}

squareVertexPositionBuffer 和 squareVertexColorBuffer 是我的对象的形状和颜色缓冲区。

问题在这里: mat4.perspective(45, gl.viewportWidth / gl.viewportHeight, 0.1, 100.0, pMatrix);mat4.translate(mvMatrix, [2.0, 5.0, -1.0]);

我希望在 z=0 平面上绘制对象。所以当我把它改成 mat4.perspective(45, gl.viewportWidth / gl.viewportHeight, 0.0, 100.0, pMatrix);mat4.translate(mvMatrix, [2.0, 5.0, 0.0]);

屏幕上什么也没有显示。为什么会这样?

此外,我们在 WebGL 中指定的数字是否以屏幕像素单位转换和存储缓冲区中的形状坐标?

4

4 回答 4

2

这是因为您的近剪裁平面( 中的第三个参数mat4.perspective)设置为 0.1,这意味着前面的任何东西都将被剔除。

于 2012-10-16T11:53:18.077 回答
1

如果你想做 2D 渲染,你不应该使用 3D 数学。摆脱 mat4 库并进行 2D 数学运算,所有关于 2D 的问题都会消失。

在 WebGL 中为 2D 使用 3D 数学可以说是 OpenGL 1.0 遗留下来的旧思想,并且不再应该被劝阻。

这是一系列关于如何进行 2D 的文章,包括 2D 数学库

http://games.greggman.com/game/webgl-fundamentals/

于 2012-10-17T07:13:55.860 回答
1

在我进入答案的主要部分之前,并努力回答您问题的最后一部分,了解 WebGL 接收到的数字实际上如何变成屏幕上的颜色可能会有所帮助。如果您不介意点击“ WebGL 的工作原理? ”,我已经写了一个详细的答案。

您不能将近平面深度 0 用于透视矩阵,因为这样做会产生除以 0,从而导致矩阵中的 NaN 值:

                     // fovy, aspect, znear, zfar
m = mat4.perspective(     45,      1,     0, 100);
//=> [NaN, 0, 0, 0, 0, NaN, 0, 0, NaN, NaN, -1, -1, 0, 0, 0, 0]

将近平面视为相机镜头的目镜。它非常靠近您的眼睛,但实际上并不您的眼睛中,这就是近平面 0 的含义。

然而,使用一个非零的近似值只是答案的一半。您应该熟悉正交投影,这有点与透视相反。

透视意味着随着物体变得更远,它们似乎变得更小。这就是给你深度感的原因。使用正交投影矩阵,无论对象离相机多近或多远,它们都被绘制成相同的大小,这使得它们非常适合各种 2D 操作,甚至在 3D 引擎中(例如绘制范围镜头或 HUD)。

值得注意的是,即使使用正交投影,仍然必须有一个近平面和远平面,并且物体必须仍然位于它们之间才能可见。

大多数矩阵库都具有生成正交投影的功能,实际上使用创建后的正交矩阵与使用透视矩阵相同。这是使用 实例化正交矩阵的示例gl-matrix

m = mat4.ortho(left, right, bottom, top, near, far);

大多数人都对价值观应该是什么感到困惑。事实是,你可以使用任何你想要的值。如果您希望将事物保持在单位空间中,则可以使用范围-1..1,如果您想将对象缩放到窗口大小,这很有用,或者您可以使用画布的像素坐标,这有时对布局很有用用户界面等。(是的,您可以使用接近 0 的值。)

使用负的近平面值是可行的,但可能有点笨拙,因为它在技术上意味着允许绘制摄像机后面的对象。在 2D 环境中,这可能不太重要。这样做有其用途,但并不常见。

我不完全确定物体是否会开始近平面上被剔除或越过它,所以你应该谨慎使用直接在近平面上的值。为了安全起见,我尝试始终将近平面设置为至少比最近的物体更近 0.01。

关于近值和远值的另一件事:它们直接且极大地影响深度缓冲区的准确性。让它们尽可能靠近。显然,这在 3D 中更为重要,但如果您正在制作伪 2D 场景,例如在图层中相互偏移精灵,则可以发挥作用。

最后,关于在 WebGL 中制作 2D 图形的最后一点说明。您需要调用一些函数:

// Disable depth testing. This way, the last object drawn is always in "front".
// WebGL will not attempt to determine whether one object lies behind another.
gl.disable(gl.DEPTH_TEST);

// Alternatively, keep depth testing, but allow objects that share a plane with
// one another to overwrite each other. Your mileage may vary but the idea here
// is to be able to draw the scene in distinct layers, where objects in a given
// layer share the same plane but objects from one layer to the next can still
// take advantage of depth testing.
gl.depthFunc(gl.LEQUAL);
于 2012-10-19T22:01:39.900 回答
0

此外,如果您正在执行 2D 渲染器,您可能应该禁用深度缓冲区测试。因为您可能希望依靠绘制顺序来确定可见性。

于 2012-10-16T17:49:10.387 回答