13

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

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

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

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

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

4

2 回答 2

11

可以使用 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平面,那么您将需要对生成的平面进行归一化。

于 2016-01-23T07:38:38.173 回答
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
}
于 2018-07-14T03:32:05.910 回答