之前可能已经回答过,如果有的话,请指出答案。否则,就在这里。
在空间中有x个对象,它们具有边界坐标p0和p1。 p0和p1各自是3维坐标,p0总是具有较低的值 - 无论是负数还是正数,p1总是具有更高的值。
现在,你有一个平面,它与摄像机C的方向完全正交,它有一个位置(pC)和一个航向(hC)。然后可以将该平面定义为距离摄像机偏航90度(π/ 2弧度)(有时称为“#39;航向”)并且俯仰并延伸到该空间中最远的定义边界。 / p>
因为我不允许超过180度FOV,所以必须排除完全位于相机后面(在排除平面后面)的任何东西。
有一种简单的方法吗?对于这个问题,我不讨论必须检查空间中的每个对象的问题;为了我们的问题,假设总是存在有限数量的对象 - 通过以某种方式划分空间来管理 - 以便我们检查的对象总是有问题的。
另外请记住,因为这些不是点而是代表3d边界立方体的点对,所以仅仅位于平面的这一侧或那一侧是不够的。
我觉得有一种简单的方法可以做到这一点,但没有采用计算机图形学我从未被引入数学。
答案 0 :(得分:1)
我想你想要找到两个点都位于相机平面后面的一对点(我认为你描述的是一个包含点pC和正常hC的普通2d平面),但我可能有误解。
如果这是你想要的,那就试试这个:
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的前半部分可以提高效率,我想:)