在相机后面的位置做广告牌时的人工制品

Artefacts when billboarding at positions just behind camera

我在 opengl/rust 中画了一堆 billboards/triangles。我得到这些人工制品,其中一半的屏幕颜色模糊。调试后发现,经过变换后,有些顶点变得非常大。我将在下面用矩阵的 glam 库在 Rust 中放置一个最小可重现的示例。

    let camera_position = [-696.2638, 31.615665, 346.61575];
    let camera_front = [0.72691596, -0.2045585, 0.65555245];
    let vtx_pos = [-714.08, 21.8639, 363.706];
    let fov: f32 = 1.012;
    let width = 1920_f32;
    let height = 1080_f32;
    let up = vec3(0.0, 1.0, 0.0).normalize();

    
    let camera_position = vec3(camera_position[0], camera_position[1], camera_position[2]);
    let camera_front = vec3(camera_front[0], camera_front[1], camera_front[2]);
    let camera_dvec =  camera_position + camera_front;
    dbg!(camera_dvec);
    // make matrix
    let view = Mat4::look_at_lh(camera_position, camera_dvec, up);
    dbg!(view);
    let projection = Mat4::perspective_lh(fov, width / height, 1.0, 5000.0);
    dbg!(projection);
    let vp = projection * view;
    dbg!(vp);

    // left bottom vertex
    let world_vtx = vec4(vtx_pos[0], vtx_pos[1], vtx_pos[2], 1.0);
    dbg!(world_vtx);
    let clip_vtx = vp * world_vtx;
    dbg!(clip_vtx);
    let ndc_vtx = clip_vtx.xyz() / clip_vtx.w;
    dbg!(ndc_vtx);

从上面的代码,我们得到


[src/main.rs:29] world_vtx = Vec4(
    -714.08,
    21.8639,
    363.706,
    1.0,
)
[src/main.rs:31] clip_vtx = Vec4(
    -24.995728,
    -17.885654,
    -0.7529907,
    0.24725342,
)
[src/main.rs:33] ndc_vtx = Vec3(
    -101.09356,
    -72.33734,
    -3.045421,
)

我认为 clip_vtx 的 W 部分应该在 -Z 的值附近。但其较小的值导致透视分割后的归一化设备坐标变得巨大。这使三角形大得令人讨厌,每当该三角形的一部分进入我的视锥体时,我就会得到奇怪的颜色人工制品。

谁能帮我找出我做错了什么?或者这是矩阵变换的正常部分,教程没有教我。

根据我在 gamedev discords 中询问的知识: 我在一个位置做了一个广告牌,就像在相机后面一样。这会导致某种不连续性,其中左顶点停留在最左端,而右顶点由于不断变化的符号而变得最右端在 ndc 中变得巨大,如果我不手动剪辑它们就会产生问题。我仍然不知道如何处理中断问题。现在我只是在计算左右顶点之间的距离,如果它在 ndc 中大于 2.0,我将跳过渲染那个广告牌。

有没有更好的方法来确定哪些位置会出现广告牌变大的问题?

我花了几个小时向图形编程方面的其他有经验的人询问和戳戳不和谐,但我对发生的事情有了更好的了解。 现在我改变了我的问题,我可以看到过去关于堆栈溢出的类似问题。我只是检查了其中的一些并找到了一个很好的答案 .

整个裁剪问题是因为我将 triangle/billboard 顶点作为 vec3 发送,而在顶点着色器中我发送 gl_Position = vec4(pos, 1.0),所以 opengl 不进行任何裁剪。同时,在进行透视分割之前,我也不做任何裁剪。所以,未剪裁的广告牌是我得到的人工制品,尤其是在相机后面。