我一直在研究this tutorial之后使用LWJGL在3d游戏引擎中实现SAT碰撞的2d SAT碰撞。
由于本教程是针对2d的,并且我正在尝试进行3d碰撞,因此我需要对代码进行一些更改以适合我的需要,但未能成功完成。
这是SAT课程:
public class SAT {
public static IntersectionData collision(Box box1, Box box2){
float overlap = Float.MAX_VALUE;
Vector3f smallest = null;
Vector3f[] box1Vertices = box1.getExtents();
Vector3f[] box2Vertices = box2.getExtents();
Vector3f[] box1Axes = getAxes(box1Vertices);
Vector3f[] box2Axes = getAxes(box2Vertices);
for (Vector3f axis:box1Axes){
Projection p1 = Projection.project(box1Vertices, axis);
Projection p2 = Projection.project(box2Vertices, axis);
if (!p1.overlap(p2))
return new IntersectionData(false, p1.getDistance(p2));
else {
float o = p1.getOverlap(p2);
if (o < overlap){
overlap = o;
smallest = axis;
}
}
}
for (Vector3f axis:box2Axes){
Projection p1 = Projection.project(box1Vertices, axis);
Projection p2 = Projection.project(box2Vertices, axis);
if (!p1.overlap(p2))
return new IntersectionData(false, p1.getDistance(p2));
else {
float o = p1.getOverlap(p2);
if (o < overlap){
overlap = o;
smallest = axis;
}
}
}
MTV mtv = new MTV(smallest, overlap);
return new IntersectionData(true, mtv.getOverlap());
}
private static Vector3f[] getAxes(Vector3f[] vertices){ // FIXME
Vector3f[] axes = new Vector3f[vertices.length];
for (int i = 0; i < vertices.length; i++){
Vector3f p1 = vertices[i];
Vector3f p2 = vertices[i + 1 == vertices.length ? 0 : i + 1];
Vector3f p3 = vertices[i + 2 >= vertices.length ? 1 : i + 1];
Vector3f edge1 = Vector3f.sub(p2, p1, null);
Vector3f edge2 = Vector3f.sub(p3, p1, null);
Vector3f normal1 = Vector3f.cross(edge1, edge2, null);
normal1.normalise();
axes[i] = normal1;
}
return axes;
}
}
它可以在我创建的其他类中使用,我可以向您保证可以完美地工作(在我开始实施SAT之前就已经在那里,并且已经使用了几次),Vector3f类是在LWJGL和在以下课程中:
投影:
class Projection {
private float min;
private float max;
private Projection(float min, float max) {
this.min = min;
this.max = max;
}
float getOverlap(Projection projection){
if (overlap(projection))
return Math.min(max, projection.max) - Math.max(min, projection.min);
return 0;
}
float getDistance(Projection projection){
if (overlap(projection))
return getOverlap(projection);
else
return Math.max(min, projection.min) - Math.max(max, projection.max);
}
boolean overlap(Projection projection){
return max > projection.min || projection.max > min;
}
static Projection project(Vector3f[] vertices, Vector3f axis){
float min = Vector3f.dot(axis, vertices[0]);
float max = min;
for (Vector3f vertex:vertices){
float p = Vector3f.dot(axis, vertex);
if (p < min)
min = p;
else if (p > max)
max = p;
}
return new Projection(min, max);
}
}
MTV:
class MTV {
private Vector3f axis;
private float overlap;
MTV(Vector3f axis, float overlap) {
this.axis = axis;
this.overlap = overlap;
}
public Vector3f getAxis() {
return axis;
}
float getOverlap() {
return overlap;
}
}
注意:IntersectionData类只是一个用于存储两个对象是否碰撞以及到对象之间的距离的类,该类已经在引擎的其他部分使用,并且可以正常运行。 < / p>
由于某种原因,碰撞将无法正确检测,并且物体彼此正确通过,我怀疑问题的根源是法向矢量的计算方式,因为当我运行模拟(引擎)时,我在行IllegalStateException: Zero length vector
处获得normal1.normalise();
异常。
有人可以帮我找到问题吗?
编辑:解决方案:
问题在于,在函数overlap(Projection projection)
中,返回条件是||
而不是&&
。