Java 将轴对齐的边界框和三角形的轴测试分离会产生不正确的结果(3D)
我正在做三角形到AABB交叉点的测试,我从Christer Ericson的实时碰撞检测中获取了这个示例代码。作者在给出示例之前在书中所说的与示例不同,因此我不确定如何测试其余轴。。a01-a22 测试:由两条边组合的叉积给出的九条轴Java 将轴对齐的边界框和三角形的轴测试分离会产生不正确的结果(3D),java,collision-detection,Java,Collision Detection,我正在做三角形到AABB交叉点的测试,我从Christer Ericson的实时碰撞检测中获取了这个示例代码。作者在给出示例之前在书中所说的与示例不同,因此我不确定如何测试其余轴。。a01-a22 测试:由两条边组合的叉积给出的九条轴 // Test axes a00..a22 ( category 3 ) // Test axis a00 originDistance0 = triangle.point0.z * triangle.point1.y - triangle.po
// Test axes a00..a22 ( category 3 )
// Test axis a00
originDistance0 = triangle.point0.z * triangle.point1.y
- triangle.point0.y * triangle.point1.z;
originDistance2 = triangle.point1.z *( triangle.point1.y - triangle.point0.y )
- triangle.point1.z * ( triangle.point1.z - triangle.point0.z );
projectionRadius = extent1 * Math.abs( edge0.z ) + extent2 * Math.abs( edge0.y );
if ( Math.max( -Math.max( originDistance0, originDistance2 ), Math.min( originDistance0, originDistance2 ) ) > projectionRadius ) {
return false; // Axis is a separating axis
}
// Repeat similar tests for remaining axes a01..a22
这是对第一个轴的测试。根据这本书,这些是轴:
a00
=
u0×f0
=
(1,0,0)×f0
=
(0,-f0z,f0y)
a01
=
u0×f1
=
(1,0,0)×f1
=
(0,-f1z,f1y)
a02
=
u0×f2
=
(1,0,0)×f2
=
(0,-f2z,f2y)
a10
=
u1×f0
=
(0,1,0)×f0
=
(f0z,0,-f0x)
a11
=
u1×f1
=
(0,1,0)×f1
=
(f1z,0,-f1x)
a12
=
u1×f2
=
(0,1,0)×f2
=
(f2z,0,-f2x)
a20
=
u2×f0
=
(0,0,1)×f0
=
(-f0y,f0x,0)
a21
=
u2×f1
=
(0,0,1)×f1
=
(-f1y,f1x,0)
a22
=
u2×f2
=
(0,0,1)×f2
=
(-f2y,f2x,0)
============
p0
=
V0·a00
p1
=
V1·a00=V1=p0
p2
=
V2·a00=V2
图例:u=中心向量,f=三角形边向量。p=从原点到三角形顶点投影到法线的距离。V=三角形点
如何计算后续的轴测试?也许如果有人能做一个,我就可以更好地了解其余的,但只有一个例子,我被卡住了。。谢谢
编辑:我尝试了以下方法。。对于没有运气的a00-a22,测试仍然通过。
首先我添加了这个代码,替换了a00,并添加了a01-a22
// Test axes a00..a22 ( category 3 )
Vector3d a00 = new Vector3d();
Vector3d a01 = new Vector3d();
Vector3d a02 = new Vector3d();
Vector3d a10 = new Vector3d();
Vector3d a11 = new Vector3d();
Vector3d a12 = new Vector3d();
Vector3d a20 = new Vector3d();
Vector3d a21 = new Vector3d();
Vector3d a22 = new Vector3d();
a00.cross( u0, edge0 );
a01.cross( u0, edge1 );
a02.cross( u0, edge2 );
a10.cross( u1, edge0 );
a11.cross( u1, edge1 );
a12.cross( u1, edge2 );
a20.cross( u2, edge0 );
a21.cross( u2, edge1 );
a22.cross( u2, edge2 );
// Test axes a00-a22
originDistance0 = triangle.point0.dot( a00 );
originDistance2 = triangle.point2.dot( a00 );
projectionRadius = extent1 * Math.abs( edge0.z ) + extent2 * Math.abs( edge0.y );
if ( Math.max( -Math.max( originDistance0, originDistance2 ), Math.min( originDistance0, originDistance2 ) ) > projectionRadius ) {
return false; // Axis is a separating axis
}
...
编辑2:我也尝试了以下方法,这让我更接近了,但仍然没有得到所有交叉点,也没有得到不应该得到的交叉点
更新:仍然无法获得正确的交叉点结果。查看了Eli的代码,但它似乎是针对2d数据的,并且术语不同,所以我没有找到我的代码和他的代码之间的联系
更新2:其他尝试一直在尝试代码,这与事实标准类似。我得到一个交点,应该有4个交点,其中2个包含三角形的点,3个包含边,1个只是平面
捕捉的交点有一个点和两条边(加上平面)。还有一个对象具有相同的特征,但位置不同,不被视为相交。这是我正在处理的数据,突出显示的“体素”是在与三角形相交时返回的数据
以下测试类别返回的交叉点结果:
体素1:无,全部通过,返回默认值“true”。体素2:类别2
体素3:类别3
体素4:类别3
体素5:类别3 更新3:另一个实施,更好的结果 好的,在阅读了William Bittle在codezealot.org上的文章后,我实现了以下内容:
public static boolean testTriangleAABB( Triangle triangle, BoundingBox boundingBox, double size ) {
Vector3d[] triangleAxes = getAxes( triangle.getPoints() );
Vector3d[] aabbVertices = getVertices( boundingBox, size );
Vector3d[] aabbAxes = getAxes( aabbVertices );
// loop over the triangleAxes
for( int i = 0; i < triangleAxes.length; i++ ) {
Vector3d axis = triangleAxes[ i ];
// project both shapes onto the axis
Projection p1 = project( triangle.getPoints(), axis );
Projection p2 = project( aabbVertices, axis );
// do the projections overlap?
if ( !p1.overlap( p2 ) ) {
// then we can guarantee that the shapes do not overlap
return false;
}
}
// loop over the aabbAxes
for( int i = 0; i < aabbAxes.length; i++ ) {
Vector3d axis = aabbAxes[ i ];
axis.normalize();
// project both shapes onto the axis
Projection p1 = project( triangle.getPoints(), axis );
Projection p2 = project( aabbVertices, axis );
// do the projections overlap?
if ( !p1.overlap( p2 ) ) {
// then we can guarantee that the shapes do not overlap
return false;
}
}
// if we get here then we know that every axis had overlap on it
// so we can guarantee an intersection
return true;
}
现在我正在使用另一个数据集来全面测试交叉点,因为我从上一个数据集中得到了一些误报
三角形0:真三角形1:正确
三角形2:正确您可以检查我的c#(在本例中几乎与java相同…)植入到我不久前制作的一个游戏中。 寻找方法:IsSATCollision
为简单起见,将它接受的参数看作是具有顶点的参数。我的测试得到误报的原因与三角形测试有关 要测试三角形,即三维空间中的平面,必须针对4个轴(也称法线)进行测试
- 三角形两条边之间的叉积
- 曲面法线和边1之间的叉积
- 曲面法线和边2之间的叉积
- 曲面法线和边3之间的叉积
public static boolean testTriangleAABB( Triangle triangle,
Vector3d origin, double size ) {
setTriangleNormal( triangle.getNormal( true ) );
Vector3d[] aabbVertices = calculateAABBVertices( origin, size );
// Triangle Normal axis test, false = No Collision.
if( !testTriangleNormal( triangle, aabbVertices ) ) {
return false;
}
// Triangle Edge Normals axis test, false = No Collision.
if( !testTriangleEdgeNormals( triangle, aabbVertices ) ) {
return false;
}
// Axis-Aligned Bounding Box X, Y, Z axis test, false = No Collision.
if( !testAABBAxis( triangle, aabbVertices ) ) {
return false;
}
// if we get here then we know that every axis had overlap on it
// so we can guarantee an intersection
return true;
}
...
private static boolean testTriangleEdgeNormals( Triangle triangle, Vector3d[] aabbVertices ) {
Vector3d edge = new Vector3d();
Vector3d edgeNormal = new Vector3d();
// loop over the triangle edge normals
Vector3d[] points = triangle.getPoints();
for( int i = 0; i < points.length; i++ ) {
int iOverflow = i + 1 == points.length ? 0 : i + 1;
edge.sub( points[ i ], points[ iOverflow ] );
edge.normalize();
edgeNormal.cross( getTriangleNormal(), edge );
// project both shapes onto the axis
projectionAABB = project2D1D( aabbVertices, edgeNormal );
projectionTriangle = project2D1D( triangle.getPoints(), edgeNormal );
// do the projections overlap?
if ( !projectionAABB.hasOverlap( projectionTriangle ) ) {
// then we can guarantee that the shapes do not overlap
return false;
}
}
return true;
}
是不是
Vector2
,只是一个2d向量,所以它只有一个x和一个y(没有z)?没错(这是一个XNA的东西。)你使用Vector2
是因为这是2d游戏吗?喂,你有完整的代码吗?“testTriangleNormal”是做什么的?
public boolean overlap( Projection projection ) {
double test1;
double test2;
// and test if they are touching
test1 = min - projection.max; // test min1 and max2
test2 = projection.min - max; // test min2 and max1
if( ( ( test1 > 0 ) || ( test2 > 0 ) ) ) { // if they are greater than 0, there is a gap
return false; // just quit }
}
return true;
}
public static Vector3d[] getAABBAxes( Vector3d[] vertices ) {
Vector3d[] axes = new Vector3d[ 6 ];
// loop over the vertices
for ( int i = 0; i < 6; i++ ) {
// get the current vertex
Vector3d p1 = vertices[ i ];
// get the next vertex
Vector3d p2 = vertices[ i + 1 == vertices.length ? 0 : i + 1 ];
Vector3d p4 = vertices[ i + 3 == vertices.length ? 0 : i + 3 ];
Vector3d edge1 = new Vector3d();
Vector3d edge2 = new Vector3d();
edge1.sub( p2, p1 );
edge2.sub( p4, p1 );
// subtract the two to get the edge vector
// edge vector can be skipped since we can get the normal by cross product.
// get either perpendicular vector
Vector3d normal = new Vector3d();
normal.cross( edge2, edge1 );
normal.normalize();
axes[ i ] = normal;
}
return axes;
}
public static boolean testTriangleAABB( Triangle triangle,
Vector3d origin, double size ) {
setTriangleNormal( triangle.getNormal( true ) );
Vector3d[] aabbVertices = calculateAABBVertices( origin, size );
// Triangle Normal axis test, false = No Collision.
if( !testTriangleNormal( triangle, aabbVertices ) ) {
return false;
}
// Triangle Edge Normals axis test, false = No Collision.
if( !testTriangleEdgeNormals( triangle, aabbVertices ) ) {
return false;
}
// Axis-Aligned Bounding Box X, Y, Z axis test, false = No Collision.
if( !testAABBAxis( triangle, aabbVertices ) ) {
return false;
}
// if we get here then we know that every axis had overlap on it
// so we can guarantee an intersection
return true;
}
...
private static boolean testTriangleEdgeNormals( Triangle triangle, Vector3d[] aabbVertices ) {
Vector3d edge = new Vector3d();
Vector3d edgeNormal = new Vector3d();
// loop over the triangle edge normals
Vector3d[] points = triangle.getPoints();
for( int i = 0; i < points.length; i++ ) {
int iOverflow = i + 1 == points.length ? 0 : i + 1;
edge.sub( points[ i ], points[ iOverflow ] );
edge.normalize();
edgeNormal.cross( getTriangleNormal(), edge );
// project both shapes onto the axis
projectionAABB = project2D1D( aabbVertices, edgeNormal );
projectionTriangle = project2D1D( triangle.getPoints(), edgeNormal );
// do the projections overlap?
if ( !projectionAABB.hasOverlap( projectionTriangle ) ) {
// then we can guarantee that the shapes do not overlap
return false;
}
}
return true;
}
private static final Vector3d[] AABB_AXES = {
new Vector3d( -1.0, 0.0, 0.0 ),
new Vector3d( 0.0, -1.0, 0.0 ),
new Vector3d( 0.0, 0.0, -1.0 ) };