3D 指向屏幕位置。丢弃 OpenGL 中相机后面的点
3D point to screen position. Discarding the points behind the camera in OpenGL
我正在尝试将 3D 点转换为其屏幕位置。
这是我使用的代码。
glm::vec2 screenPosition(const glm::vec3 & _coord) const {
glm::vec4 coord = glm::vec4(_coord, 1);
coord = getProjection() * getView() * coord;
coord.x /= coord.w;
coord.y /= coord.w;
coord.z /= coord.w;
coord.x = (coord.x + 1) * width * 0.5;
coord.y = (coord.y + 1) * height * 0.5;
return glm::vec2(coord.x, coord.y);
我不是 100% 确定代码,但我不知道如何丢弃相机后面的点。
有人可以帮助我吗?
谢谢
如果 coord.z
(除以 coord.w
后)不在区间 [-1,1] 中,则应丢弃该点。超出该区间的值表示该点不在相机视锥体中,这也包括点在相机后面的情况。对于 DirectX 和 Vulkan,间隔是 [0,1].
进行基元剔除/裁剪的正确方法是在 clip space 中,在透视划分之前进行。
默认的OpenGL剪辑约定是-w <= x,y,z, <= w
,所有不满足这个条件的点都可以被丢弃(剔除)。请注意,丢弃点仅适用于点图元,如果您处理更复杂的图元(线,三角形),则需要进行实际的裁剪。
在大多数情况下,您将使用 透视 投影,剪辑 space w
值会因顶点而异 - 而且它可以是 0 - 在这种情况下,尝试在 NDC 中进行丢弃将导致被零除。
如果你只想处理相机后面的裁剪点,你可以丢弃所有w <= 0
,但通常,另外 裁剪 近平面 更有意义(并且在非常靠近相机时也避免了一些数值问题):z < -w
.
我想在这里强调一些细节。剪辑条件 -w <= x,y,z, <= w
意味着必须拒绝真正位于相机后面的点 (w < 0
),但是 w = 0
的情况仍然有点奇怪,因为齐次点 (0,0,0,0)
仍然会满足上述剪辑条件(并且在进行透视划分时实际上不会产生有用的结果)。但是,OpenGL(和 GPU)不会针对相机所在的平面 (w=0
) 进行裁剪,而是针对视图体积进行裁剪,并且需要您设置一个位于相机前方的近平面。而在这样的场景下,即使可以出现w=0
,也保证不会同时出现both w=0
和z=0
,所以(0,0,0,0)
案例永远不会被击中。然而,这并不能阻止人们将 (0,0,0,0)
实际输入 gl_Position
,并且您可以假设现实世界的实现不仅会拒绝上述剪辑条件直接要求的 w < 0
情况, 但会拒绝 /clip 任何内容 w <= 0
。请注意,一个顶点具有 (0,0,0,0)
的剪辑 space 坐标的原始剪辑仍然会导致无意义,但您当时明确要求这样做。
对于正交投影,实际上没有办法剪掉相机后面的点,因为从概念上讲,相机是无限远的。您仍然可以通过您的视图矩阵设置一个想象的“相机位置”,并通过投影矩阵设置一个视图体积,您仍然可以 cull/clip 对 近平面 那里( z < -w
)。请注意,出于实际目的,正交投影将产生 w = 1
,因此在透视情况下所需的额外 w <= 0
检查是无关紧要的。
我正在尝试将 3D 点转换为其屏幕位置。
这是我使用的代码。
glm::vec2 screenPosition(const glm::vec3 & _coord) const {
glm::vec4 coord = glm::vec4(_coord, 1);
coord = getProjection() * getView() * coord;
coord.x /= coord.w;
coord.y /= coord.w;
coord.z /= coord.w;
coord.x = (coord.x + 1) * width * 0.5;
coord.y = (coord.y + 1) * height * 0.5;
return glm::vec2(coord.x, coord.y);
我不是 100% 确定代码,但我不知道如何丢弃相机后面的点。
有人可以帮助我吗? 谢谢
如果 coord.z
(除以 coord.w
后)不在区间 [-1,1] 中,则应丢弃该点。超出该区间的值表示该点不在相机视锥体中,这也包括点在相机后面的情况。对于 DirectX 和 Vulkan,间隔是 [0,1].
进行基元剔除/裁剪的正确方法是在 clip space 中,在透视划分之前进行。
默认的OpenGL剪辑约定是-w <= x,y,z, <= w
,所有不满足这个条件的点都可以被丢弃(剔除)。请注意,丢弃点仅适用于点图元,如果您处理更复杂的图元(线,三角形),则需要进行实际的裁剪。
在大多数情况下,您将使用 透视 投影,剪辑 space w
值会因顶点而异 - 而且它可以是 0 - 在这种情况下,尝试在 NDC 中进行丢弃将导致被零除。
如果你只想处理相机后面的裁剪点,你可以丢弃所有w <= 0
,但通常,另外 裁剪 近平面 更有意义(并且在非常靠近相机时也避免了一些数值问题):z < -w
.
我想在这里强调一些细节。剪辑条件 -w <= x,y,z, <= w
意味着必须拒绝真正位于相机后面的点 (w < 0
),但是 w = 0
的情况仍然有点奇怪,因为齐次点 (0,0,0,0)
仍然会满足上述剪辑条件(并且在进行透视划分时实际上不会产生有用的结果)。但是,OpenGL(和 GPU)不会针对相机所在的平面 (w=0
) 进行裁剪,而是针对视图体积进行裁剪,并且需要您设置一个位于相机前方的近平面。而在这样的场景下,即使可以出现w=0
,也保证不会同时出现both w=0
和z=0
,所以(0,0,0,0)
案例永远不会被击中。然而,这并不能阻止人们将 (0,0,0,0)
实际输入 gl_Position
,并且您可以假设现实世界的实现不仅会拒绝上述剪辑条件直接要求的 w < 0
情况, 但会拒绝 /clip 任何内容 w <= 0
。请注意,一个顶点具有 (0,0,0,0)
的剪辑 space 坐标的原始剪辑仍然会导致无意义,但您当时明确要求这样做。
对于正交投影,实际上没有办法剪掉相机后面的点,因为从概念上讲,相机是无限远的。您仍然可以通过您的视图矩阵设置一个想象的“相机位置”,并通过投影矩阵设置一个视图体积,您仍然可以 cull/clip 对 近平面 那里( z < -w
)。请注意,出于实际目的,正交投影将产生 w = 1
,因此在透视情况下所需的额外 w <= 0
检查是无关紧要的。