Java - 包含/排除的简单平面

时间:2012-04-03 14:00:27

标签: java math graphics 3d space

之前可能已经回答过,如果有的话,请指出答案。否则,就在这里。

在空间中有x个对象,它们具有边界坐标p0和p1。 p0和p1各自是3维坐标,p0总是具有较低的值 - 无论是负数还是正数,p1总是具有更高的值。

现在,你有一个平面,它与摄像机C的方向完全正交,它有一个位置(pC)和一个航向(hC)。然后可以将该平面定义为距离摄像机偏航90度(π/ 2弧度)(有时称为“#39;航向”)并且俯仰并延伸到该空间中最远的定义边界。 / p>

因为我不允许超过180度FOV,所以必须排除完全位于相机后面(在排除平面后面)的任何东西。

有一种简单的方法吗?对于这个问题,我不讨论必须检查空间中的每个对象的问题;为了我们的问题,假设总是存在有限数量的对象 - 通过以某种方式划分空间来管理 - 以便我们检查的对象总是有问题的。

另外请记住,因为这些不是点而是代表3d边界立方体的点对,所以仅仅位于平面的这一侧或那一侧是不够的。

我觉得有一种简单的方法可以做到这一点,但没有采用计算机图形学我从未被引入数学。

3 个答案:

答案 0 :(得分:1)

我想你想要找到两个点都位于相机平面后面的一对点(我认为你描述的是一个包含点pC和正常hC的普通2d平面),但我可能有误解。

如果这是你想要的,那就试试这个:

  • hC是你的飞机正常
  • 将vp0设置为从pC到p0的向量(p0的位置 - pC的位置)
  • 将vp1设置为从pC到p1的向量(p1的位置 - pC的位置)
如果vp0,

p0可见。 hC> = 0(如果您希望它必须严格位于相机前面,则为> 0。)

如果vp1,

p1是可见的。 hC> = 0(如果您希望它必须严格位于相机前面,则为> 0。)

。这是一个标准的矢量点积。

因此,如果p0和p1都在相机后面,则可以排除形状。

答案 1 :(得分:1)

如果“立方体”(通常称为轴对齐边界框或AABB)的6个角中的任何一个位于平面的视图侧,则可能会在其中看到某些内容。您可以先检查两个初始点,但如果它们都不可见,您还需要检查其他六个角,如下所示:

initial corners: p0=(p0.x, p0.y, p0.z)
                 p1=(p1.x, p1.y, p1.z)

other corners:      (p1.x, p0.y, p0.z)
                    (p0.x, p1.y, p0.z)
                    (p0.x, p0.y, p1.z)

                    (p1.x, p1.y, p0.z)
                    (p0.x, p1.y, p1.z)
                    (p1.x, p0.y, p1.z)

请注意,传统的光栅化管道不应该在相机后面绘制对象,因为它会剪切落在viewing frustum之外的三角形。这表明你可能也想对其他平截头体飞机进行测试,或者对整个观察视锥体进行测试,这有点复杂,但可能是一个好主意。这可能看起来很乏味,但是平截头体测试仍然比试图绘制隐形物体更便宜。

答案 2 :(得分:1)

所以这是如何做到的。

首先,您需要以可预测的方式在每个边界框中存储八个点,例如,整数中的每个位表示其关于框中心的位置。您可以做的是使用0x4表示EAST(+ x)​​(该位为0表示WEST)0x2表示NORTH(该位表示零表示SOUTH),0x1表示TOP(该位表示零表示BOTTOM)。现在,您可以通过指定位置编号来普遍访问边界框相同位置的所有点。 (所有零位数都只为零.Java警告说这些赋值没有意义,但它们有助于提高可读性。)

设置边界框:(为每个边界框执行此操作)

    pointList = new Point3d[8];

    pointList[WEST|SOUTH|BOTTOM] = new Point3d(x0,y0,z0);
    pointList[WEST|SOUTH|TOP]    = new Point3d(x0,y0,z1);
    pointList[WEST|NORTH|BOTTOM] = new Point3d(x0,y1,z0);
    pointList[WEST|NORTH|TOP]    = new Point3d(x0,y1,z1);
    pointList[EAST|SOUTH|BOTTOM] = new Point3d(x1,y0,z0);
    pointList[EAST|SOUTH|TOP]    = new Point3d(x1,y0,z1);
    pointList[EAST|NORTH|BOTTOM] = new Point3d(x1,y1,z0);
    pointList[EAST|NORTH|TOP]    = new Point3d(x1,y1,z1);

接下来,从您的视角计算法线。 (偏航是左/右旋转,俯仰是上/下旋转)

    float nx = -(float)Math.cos(yaw);
    float ny = (float)Math.sin(yaw);
    float nz = (float)Math.sin(pitch);

我认为否定是正确的,但如果一方都看不见,只需反转它:)

计算特征点,它就是你要在每个边界框中检查的索引,因为它表示每个框中最接近隐形边平面的点:

    int characteristicPoint = (nx<0?WEST:EAST)|
                              (ny<0?SOUTH:NORTH)|
                              (nz<0?BOTTOM:TOP);

确保每个边界框都设置为x,y,z小于x,y,z prime(x0 = x aught,x1 = x prime)

然后收集您的特征('检查')点,您的法线组('frustrum')和您的相机位置(x,y,z),并对每个边界框执行此操作:

    float checkA = ((bounds.pointList[check].x-position.x)*frustrum.x) +
            ((bounds.pointList[check].y-position.y)*frustrum.y);

    float checkB = ((bounds.pointList[check].x-position.x)*frustrum.x) +
            ((bounds.pointList[check].z-position.z)*frustrum.z);
    if(checkB>=0&&checkA>=0) {
        visible = true;
        return;
    } else if(checkB<0&&checkA<0) {
        visible = false;
        return;
    } else {
       float checkC = ((bounds.pointList[check].y-position.y)*frustrum.y) +
            ((bounds.pointList[check].z-position.z)*frustrum.z);
       if(checkC>=0) {
          visible = true;
          return;
       } else {
          visible = false;
          return;
       }

    }

这是简单的线性代数(IMO),逻辑如下:如果该点位于表示平面的两条或更多条线的正侧,则可见。如果它位于两个或多个代表平面的线的负侧,则它是不可见的。你计算前两个,如果它们不同(一个是负数,一个是正数),你检查第三个并取这个值。

将线条视为方程时,请务必注意以下属性:

-x-y = p != x+y = p

这条线是相同的,但它隐含的“面对”是反向的。

我希望这可以帮助其他人解决这个问题。弄清楚这很难,但很有乐趣。

通过存储CheckA的前半部分可以提高效率,我想:)