webGL问题:移动相机时部分屏幕消失

webGL problem: part of the screen dissapears when moving the camera

我想知道是否有人可以帮助我解决这个我找不到原因的渲染错误。我有一个 webGL 网页,它呈现一些非常简单的东西(一个 3D 迷宫,但这并不重要),当我移动相机(观察者)的位置时,部分屏幕消失了。当你向外移动相机时,它看起来像一团空无一物的东西。

我画了一个简单的立方体来说明问题。它主要发生在你走到立方体的“后面”(坐标 z 负),并开始旋转你的相机,或者移动你自己。

我很确定问题出在进行相机移动时计算 mvp 矩阵的公式。我使用 Gauss-Schmidt 来计算正交基(我不太记得为什么但我记得我必须这样做才能找到平移视图的方向)。

我附加了一些 gif 和 YouTube 链接:

https://imgur.com/xXW9nLf https://youtu.be/7POI3sty0aE

https://imgur.com/1K4Ot37 https://youtu.be/7POI3sty0aE

function GetModelViewMatrix(translationX, translationY, translationZ,
                            rotationX, rotationY, rotationZ, cameraRotationXY) {

    const cosRotationX = Math.cos(rotationX);
    const sinRotationX = Math.sin(rotationX);

    const cosRotationY = Math.cos(rotationY);
    const sinRotationY = Math.sin(rotationY);

    const cosRotationZ = Math.cos(rotationZ);
    const sinRotationZ = Math.sin(rotationZ);

    let rotationMatrixX = [
        1, 0, 0, 0,
        0, cosRotationX, sinRotationX, 0,
        0, -sinRotationX, cosRotationX, 0,
        0, 0, 0, 1
    ]

    let rotationMatrixY = [
        cosRotationY, 0, -sinRotationY, 0,
        0, 1, 0, 0,
        sinRotationY, 0, cosRotationY, 0,
        0, 0, 0, 1
    ]

    let rotationMatrixZ = [
        cosRotationZ, sinRotationZ, 0, 0,
        -sinRotationZ, cosRotationZ, 0, 0,
        0, 0, 1, 0,
        0, 0, 0, 1
    ]

    let rotations = MatrixMult(rotationMatrixZ, MatrixMult(rotationMatrixX, rotationMatrixY));

    let trans = [
        1, 0, 0, 0,
        0, 1, 0, 0,
        0, 0, 1, 0,
        translationX, translationY, translationZ, 1
    ];

    let mv = MatrixMult(trans, rotations);

    let alpha = 0;
    let theta = cameraRotationXY;

    let w = new Vertex([
                           Math.cos(alpha) * Math.sin(theta),
                           Math.sin(alpha) * Math.sin(theta),
                           Math.cos(theta)]);

    let v2 = new Vertex([-w.z, 0, w.y]);
    let p = proj(w, v2);
    let u2 = new Vertex([v2.x - p.x, v2.y - p.y, v2.z - p.z]);

    let u = Normalize(u2);

    let u3 = crossProduct(w, u);
    let v = Normalize(u3);

    let direction = [
        -u.x, -u.y, -u.z, 0,
        -v.x, -v.y, -v.z, 0,
        w.x, w.y, w.z, 0,
        0, 0, 0, 1
    ];

    return MatrixMult(direction, mv);
}

投影矩阵为:

function UpdateProjectionMatrix() {
    perspectiveMatrix = ProjectionMatrix(canvas, transZ);
}

// Calculates the perspective matrix (column-major)
function ProjectionMatrix(c, z, fov_angle = 60) {
    const magia_z = 1.74;

    let r = c.width / c.height;
    let n = (z - magia_z);
    const min_n = 0.001;
    if (n < min_n) n = min_n;
    let f = (z + magia_z);
    let fov = Math.PI * fov_angle / 180;
    let s = 1 / Math.tan(fov / 2);

    return [
        s / r, 0, 0, 0,
        0, s, 0, 0,
        0, 0, (n + f) / (f - n), 1,
        0, 0, -2 * n * f / (f - n), 0
    ];
}

然后mvp矩阵计算为:

    let mv = GetModelViewMatrix(transX, transY, transZ, rotX, autorot + rotY, rotZ, cameraRotationXY);
    let mvp = MatrixMult(perspectiveMatrix, mv);

您需要定义适用于场景的静态近距和远距裁剪平面,例如.01 到 100.0。传统的矩阵堆栈像相机一样构建:投影矩阵是镜头(定义视野、缩放和聚焦),视图矩阵是实际相机(平移和方向),模型矩阵是你的主题(位置、方向) , 规模)。 Scratchpixel 似乎有一个关于投影的完整部分。 – LJᛃ