提取视锥体平面(Gribb 和 Hartmann 方法)

问题描述 投票:0回答:2

我一直在努力解决Gribb/Hartmann 提取平截头体平面的方法有一段时间了,但收效甚微。我想构建一个相机视锥体来剔除我的场景。

我正在右手坐标系中处理列主矩阵。 (OpenGL 风格 - 我使用 C# 和 Playstation Mobile,但数学应该是相同的)

我想在世界空间中获得我的飞机,所以我从视图投影矩阵(即projectionMatrix * viewMatrix)构建我的平截头体。视图矩阵是相机世界变换的逆矩阵。

问题是;无论我如何调整,我似乎都无法获得正确的截锥体。我认为我可能遗漏了一些明显的东西。

如果我向左或向右“扫射”相机,同时仍向下看 z 轴,我的平面的法线会发生变化,使它们始终指向场景的原点 - 这让我认为它们不在世界中 -空间...

math 3d frustum culling occlusion-culling
2个回答
14
投票

可以使用 Gribb/Hartmann 方法提取投影矩阵中的平面,如下所示(主要列):

void extract_planes_from_projmat(
        const float mat[4][4],
        float left[4], float right[4],
        float bottom[4], float top[4],
        float near[4], float far[4])
{
    for (int i = 4; i--; ) { left[i]   = mat[i][3] + mat[i][0]; }
    for (int i = 4; i--; ) { right[i]  = mat[i][3] - mat[i][0]; }
    for (int i = 4; i--; ) { bottom[i] = mat[i][3] + mat[i][1]; }
    for (int i = 4; i--; ) { top[i]    = mat[i][3] - mat[i][1]; }
    for (int i = 4; i--; ) { near[i]   = mat[i][3] + mat[i][2]; }
    for (int i = 4; i--; ) { far[i]    = mat[i][3] - mat[i][2]; }
}

其中

mat4
是投影矩阵和模型视图矩阵的乘积。

参见:

注意:如果矩阵分量未标准化并且您需要 Hessian Normal Form 平面,那么您将需要对结果平面进行标准化。


2
投票

缺失的部分:

comboMatrix = projection_matrix * Matrix4_Transpose(modelview_matrix)

那么OpenGL的世界空间平截头体平面提取就完全如Gribb/Hartmann方法中提到的那样:

p_planes[0].a = comboMatrix._41 + comboMatrix._11;
p_planes[0].b = comboMatrix._42 + comboMatrix._12;
p_planes[0].c = comboMatrix._43 + comboMatrix._13;
p_planes[0].d = comboMatrix._44 + comboMatrix._14;
// Right clipping plane
p_planes[1].a = comboMatrix._41 - comboMatrix._11;
p_planes[1].b = comboMatrix._42 - comboMatrix._12;
p_planes[1].c = comboMatrix._43 - comboMatrix._13;
p_planes[1].d = comboMatrix._44 - comboMatrix._14;
// Top clipping plane
p_planes[2].a = comboMatrix._41 - comboMatrix._21;
p_planes[2].b = comboMatrix._42 - comboMatrix._22;
p_planes[2].c = comboMatrix._43 - comboMatrix._23;
p_planes[2].d = comboMatrix._44 - comboMatrix._24;
// Bottom clipping plane
p_planes[3].a = comboMatrix._41 + comboMatrix._21;
p_planes[3].b = comboMatrix._42 + comboMatrix._22;
p_planes[3].c = comboMatrix._43 + comboMatrix._23;
p_planes[3].d = comboMatrix._44 + comboMatrix._24;
// Near clipping plane
p_planes[4].a = comboMatrix._41 + comboMatrix._31;
p_planes[4].b = comboMatrix._42 + comboMatrix._32;
p_planes[4].c = comboMatrix._43 + comboMatrix._33;
p_planes[4].d = comboMatrix._44 + comboMatrix._34;
// Far clipping plane
p_planes[5].a = comboMatrix._41 - comboMatrix._31;
p_planes[5].b = comboMatrix._42 - comboMatrix._32;
p_planes[5].c = comboMatrix._43 - comboMatrix._33;
p_planes[5].d = comboMatrix._44 - comboMatrix._34;

这些平面现在位于世界空间中,可用于剔除世界空间对象。

for(int i = 0; i < 6; i++)
{
    var dist = dot3(world_space_point.xyz, p_planes[i].xyz) + p_planes[i].d + sphere_radius;
    if(dist < 0) return false; // sphere culled
}
© www.soinside.com 2019 - 2024. All rights reserved.