在相机后面的位置进行广告牌时的伪影
Posted
技术标签:
【中文标题】在相机后面的位置进行广告牌时的伪影【英文标题】:Artefacts when billboarding at positions just behind camera 【发布时间】:2021-08-21 10:07:14 【问题描述】:我在 opengl/rust 中绘制了一堆广告牌/三角形。我得到这些人工制品,其中一半的屏幕颜色模糊。经过调试,我发现经过变换后,一些顶点变得非常大。我将在下面用 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,我会跳过渲染那个广告牌。
有没有更好的方法来确定哪些位置会导致广告牌变得巨大?
【问题讨论】:
检查您的坐标,您的vtx_pos
似乎在摄像机后面。当您从-696.2638
向0.72691596
方向看(x 轴)时,-714.08
不在相机前面。您还可以很容易地看到,因为剪辑空间中的可见点必须在 [-w, w] 范围内具有 x,y,z。
@BDL 是的,但是那个顶点是两个三角形的一部分,它们都形成了一个巨大的三角形,当我稍微旋转我的相机时,那个三角形的一部分进入了我的视锥体。这有点导致问题。我应该怎么做才能避免这种情况?
为什么要“避免”这种情况?如果您的世界中有一个巨大的三角形,并且它与您的视锥相交,则输出是正确的。您在这里真正要解决的问题是什么?
@derhass 我没有大三角形。我在某个位置制作了一个广告牌,就像在相机后面一样。这会导致某种不连续性,其中左顶点停留在最左边,而右顶点由于变化的符号在 ndc 中变得非常大,如果我不手动剪辑它们就会产生问题。在多次不和谐询问后我意识到了这一点,但我仍然不知道如何处理不连续的问题。现在我只是在计算左右顶点之间的距离,如果它在 ndc 中大于 2.0,我会跳过渲染那个广告牌。
这个问题根本不清楚。 OpenGL 会自动进行所有裁剪,所以这个问题完全是误导性的。如果您编写自己的渲染器,那么剪裁将是必不可少的,否则如果几何部分位于相机后面,您会得到荒谬的伪影。
【参考方案1】:
花了几个小时询问和戳其他有经验的图形编程不和谐的人,但我对正在发生的事情有了更好的了解。 现在我改变了我的问题,过去我可以在堆栈溢出中看到类似的问题。我只是检查了其中一些并找到了一个很好的答案 https://***.com/a/65168709/7484780.
剪裁的整个问题是因为我将三角形/广告牌顶点作为 vec3 发送,而在顶点着色器中我做gl_Position = vec4(pos, 1.0)
,所以 opengl 不做任何剪裁。同时,在进行透视分割之前,我也不做任何剪辑。所以,未剪辑的广告牌是我得到的人工制品,尤其是在相机后面。
【讨论】:
如果您手动进行透视分割,并且只是将 NDC 坐标输入到gl_Position
(出于某种原因,它位于 剪辑空间 中),那么您不仅可以绕过剪辑, 也是插值的透视校正。以上是关于在相机后面的位置进行广告牌时的伪影的主要内容,如果未能解决你的问题,请参考以下文章