Math 提取视锥平面(Gribb&Hartmann方法)

Math 提取视锥平面(Gribb&Hartmann方法),math,3d,frustum,culling,occlusion-culling,Math,3d,Frustum,Culling,Occlusion Culling,我已经与之斗争了一段时间,但收效甚微。我想构建一个摄影机视图截锥体来剔除我的场景 我正在使用右手坐标系中的列主矩阵。(OpenGL风格——我使用的是C#和Playstation Mobile,但数学应该是一样的) 我想在世界空间中得到我的平面,所以我从视图投影矩阵(即projectionMatrix*viewMatrix)构建了我的截锥体。视图矩阵是摄影机世界变换的逆矩阵 问题是,;不管我如何调整,我似乎都找不到正确的平截头体。我想我可能遗漏了一些明显的东西 如果我在仍然向下看z轴的同时向左或向

我已经与之斗争了一段时间,但收效甚微。我想构建一个摄影机视图截锥体来剔除我的场景

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

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

问题是,;不管我如何调整,我似乎都找不到正确的平截头体。我想我可能遗漏了一些明显的东西


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

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

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

见:

注意:如果矩阵组件未规格化,并且需要Hessian法线形式平面,则需要规格化生成的平面。

缺少的部分:

comboMatrix = projection_matrix * Matrix4_Transpose(modelview_matrix)
然后,OpenGL的世界空间截头体平面提取与Gribb/Hartmann方法中提到的完全相同:

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

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
}
for(int i=0;i<6;i++)
{
var dist=dot3(世界空间点xyz,p_平面[i].xyz)+p_平面[i].d+球体半径;
if(dist<0)返回false;//已剔除球体
}

我昨天遇到了同样的问题。我有一种感觉,那篇论文中的OpenGL代码可能是错误的,或者至少我使用了DirectX代码,它工作得很好,即使我使用的是OpenGL。我用点云可视化了这些平面,它们现在看起来很像。你试过了吗?我也有同样的问题。在使用行主矩阵查询时,我实现了DirectX样式段落中描述的算法。我无法使正确的筛选工作正常进行。但我注意到,如果要剔除的对象正好位于世界中心(0,0,0),则剔除效果非常好@DAVco你能解决这个问题吗?在进行任意变换的情况下,你仍然需要对平面进行规格化。这不是只有在平面需要通过使用它们的任何代码进行规格化的情况下才会发生吗许多飞机操作不需要这样做,尽管如此,谢谢你的提醒——答案中提到了。你说得对,你不需要所有操作都使用标准化的飞机。尽管如此,如果删除一些自由度,代码可能会更健壮。当然,您可能希望这样做,但在某些情况下,不这样做也可以,因为规范化可能会很昂贵。在回答中指出,如果需要,可以进行正常化。
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
}