动态 OBB 碰撞检测(分离轴定理):找到碰撞发生的时间?
Dynamic OBB Collision Detection (Separating Axis Theorem): Find the Time That Collision Occurred?
现在,我正在尝试使用分离轴定理在 Java 中实现动态 3-D OBB 碰撞测试。我试图找到每个分离轴的实体从 0 到 1 的交点时间,0 是帧的开始,1 是帧的结束。
这是我的代码:
private float calculateITime(OBB obb,
Vector3f axis /*the separating axis we are testing*/,
Vector3f d /*Current OBB's origin minus other OBB's origin*/,
float ra /*the first obb's projection*/,
float rb /*the second obb's projection*/,
float r /*what I understand to be the total length of the combined projections*/) {
//Find the time, from 0 (the beginning of the frame) to 1 (the end of the frame), that the obb's first intersected.
float intersectionLength = r - Math.abs(ra) - Math.abs(rb); //The measure of how much the two projections overlap
Vector3f aVelocity = this.getCollisionPacket().getVelocity();
Vector3f bVelocity = obb.getCollisionPacket().getVelocity();
double aMagnitude = Mathematics.dotProduct(axis, Mathematics.crossProduct(aVelocity, d));
double bMagnitude = Mathematics.dotProduct(axis, Mathematics.crossProduct(bVelocity, d));
double totalDistanceCovered = 0;
if(aMagnitude <= 0 && bMagnitude <= 0) {
totalDistanceCovered = Math.abs(aMagnitude - bMagnitude);
} else if((aMagnitude >= 0 && bMagnitude <= 0) || (aMagnitude <= 0 && bMagnitude >= 0)) {
totalDistanceCovered = Math.abs(aMagnitude + bMagnitude);
} else if(aMagnitude >= 0 && bMagnitude >= 0) {
totalDistanceCovered = Math.abs(aMagnitude - bMagnitude);
}
System.out.println("PotentialITime: " + Math.abs(intersectionLength / totalDistanceCovered));
return (float) Math.abs(intersectionLength / totalDistanceCovered);
}
但是,我得到的值远高于 1。假设我什至正确理解如何正确实施分离轴定理,我哪里出错了?
如果您认为自己有答案,但如果我发布 class 的其余部分(虽然它很长)会有所帮助,请告诉我,我会为您完成。谢谢!
最后的笔记:
此功能在 OBB class 中。因此,"this" 指的是 OBB,"obb" 指的是另一个 OBB。
collisionPacket.getVelocity() returns 如果没有碰撞,单帧中发生的总位移。
"Mathematics"是我自己的静态class。假设它正常工作。直到我制作它之后,我才意识到 Vector3f 具有所有这些有用的功能。
This 是我正在使用的 PDF。我卡在第 9 页,2.3.1。
几周后,我想出了如何做我想做的事情。实际上我几周前就想到了这个,但我现在才想到 post 我的解决方案。
private boolean determineCollision(OBB obb, Vector3f separatingAxis, double velocityMagnitude, float ra, float rb, float r) {
//Find the time, from 0 (the beginning of the frame) to 1 (the end of the frame), that the obb's first intersected.
//If r is negative, the first OBB is to the "right." Otherwise, it is to the "left."
collisionRightSide.add(r < 0);
boolean currColRightSide = collisionRightSide.get(collisionRightSide.size() - 1);
double timeRange[] = new double[2]; //From 0 (beginning of frame) to 1 (end of frame)
//Perform a regular static test if there is no movement for optimization's sake
boolean noStaticOverlap = Math.abs(r) > (ra + rb);
if(velocityMagnitude == 0) {
timeRange[0] = 0; timeRange[1] = 1;
axisTimes.add(timeRange);
return !noStaticOverlap;
}
double spaceBetweenProjections = Math.abs(r) - Math.abs(ra) - Math.abs(rb);
//Note that if velocity magnitude is negative, the first OBB is moving "right," and the other way for positive.
if(currColRightSide) {
if(velocityMagnitude < 0) {
if(noStaticOverlap) {
// System.out.println("(Right side) OBBs are moving away");
return false;
} else {
timeRange[0] = 0;
timeRange[1] = Math.abs(spaceBetweenProjections / velocityMagnitude);
}
} else if(velocityMagnitude > 0) {
if(noStaticOverlap) {
timeRange[0] = Math.abs(spaceBetweenProjections / velocityMagnitude);;
timeRange[1] = Math.abs((spaceBetweenProjections + 2 * rb) / velocityMagnitude);
} else {
timeRange[0] = 0;
timeRange[1] = Math.abs((spaceBetweenProjections + 2 * rb) / velocityMagnitude);
}
}
} else {
if(velocityMagnitude > 0) {
if(noStaticOverlap) {
// System.out.println("(Left side) OBBs are moving away");
return false;
} else {
timeRange[0] = 0;
timeRange[1] = Math.abs(spaceBetweenProjections / velocityMagnitude);
}
} else if(velocityMagnitude < 0) {
if(noStaticOverlap) {
timeRange[0] = Math.abs(spaceBetweenProjections / velocityMagnitude);
timeRange[1] = Math.abs((spaceBetweenProjections + 2 * rb) / velocityMagnitude);
} else {
timeRange[0] = 0;
timeRange[1] = Math.abs((spaceBetweenProjections + 2 * rb) / velocityMagnitude);
}
}
}
//Clamp values
if(timeRange[0] < 0) timeRange[0] = 0;
if(timeRange[1] > 1) timeRange[1] = 1;
//Switch so that the greater value comes last
if(timeRange[0] > timeRange[1]) {
double temp = timeRange[0];
timeRange[0] = timeRange[1];
timeRange[1] = temp;
}
if(timeRange[0] > 1 && timeRange[1] < 0) return false;
axisTimes.add(timeRange);
return true;
}
感谢 Whosebug 为我提供了这个问题的 Tumbleweed 徽章。如果有人提出更好或更优化的方法,请告诉我。谢谢! :D
现在,我正在尝试使用分离轴定理在 Java 中实现动态 3-D OBB 碰撞测试。我试图找到每个分离轴的实体从 0 到 1 的交点时间,0 是帧的开始,1 是帧的结束。
这是我的代码:
private float calculateITime(OBB obb,
Vector3f axis /*the separating axis we are testing*/,
Vector3f d /*Current OBB's origin minus other OBB's origin*/,
float ra /*the first obb's projection*/,
float rb /*the second obb's projection*/,
float r /*what I understand to be the total length of the combined projections*/) {
//Find the time, from 0 (the beginning of the frame) to 1 (the end of the frame), that the obb's first intersected.
float intersectionLength = r - Math.abs(ra) - Math.abs(rb); //The measure of how much the two projections overlap
Vector3f aVelocity = this.getCollisionPacket().getVelocity();
Vector3f bVelocity = obb.getCollisionPacket().getVelocity();
double aMagnitude = Mathematics.dotProduct(axis, Mathematics.crossProduct(aVelocity, d));
double bMagnitude = Mathematics.dotProduct(axis, Mathematics.crossProduct(bVelocity, d));
double totalDistanceCovered = 0;
if(aMagnitude <= 0 && bMagnitude <= 0) {
totalDistanceCovered = Math.abs(aMagnitude - bMagnitude);
} else if((aMagnitude >= 0 && bMagnitude <= 0) || (aMagnitude <= 0 && bMagnitude >= 0)) {
totalDistanceCovered = Math.abs(aMagnitude + bMagnitude);
} else if(aMagnitude >= 0 && bMagnitude >= 0) {
totalDistanceCovered = Math.abs(aMagnitude - bMagnitude);
}
System.out.println("PotentialITime: " + Math.abs(intersectionLength / totalDistanceCovered));
return (float) Math.abs(intersectionLength / totalDistanceCovered);
}
但是,我得到的值远高于 1。假设我什至正确理解如何正确实施分离轴定理,我哪里出错了?
如果您认为自己有答案,但如果我发布 class 的其余部分(虽然它很长)会有所帮助,请告诉我,我会为您完成。谢谢!
最后的笔记:
此功能在 OBB class 中。因此,"this" 指的是 OBB,"obb" 指的是另一个 OBB。
collisionPacket.getVelocity() returns 如果没有碰撞,单帧中发生的总位移。
"Mathematics"是我自己的静态class。假设它正常工作。直到我制作它之后,我才意识到 Vector3f 具有所有这些有用的功能。
This 是我正在使用的 PDF。我卡在第 9 页,2.3.1。
几周后,我想出了如何做我想做的事情。实际上我几周前就想到了这个,但我现在才想到 post 我的解决方案。
private boolean determineCollision(OBB obb, Vector3f separatingAxis, double velocityMagnitude, float ra, float rb, float r) {
//Find the time, from 0 (the beginning of the frame) to 1 (the end of the frame), that the obb's first intersected.
//If r is negative, the first OBB is to the "right." Otherwise, it is to the "left."
collisionRightSide.add(r < 0);
boolean currColRightSide = collisionRightSide.get(collisionRightSide.size() - 1);
double timeRange[] = new double[2]; //From 0 (beginning of frame) to 1 (end of frame)
//Perform a regular static test if there is no movement for optimization's sake
boolean noStaticOverlap = Math.abs(r) > (ra + rb);
if(velocityMagnitude == 0) {
timeRange[0] = 0; timeRange[1] = 1;
axisTimes.add(timeRange);
return !noStaticOverlap;
}
double spaceBetweenProjections = Math.abs(r) - Math.abs(ra) - Math.abs(rb);
//Note that if velocity magnitude is negative, the first OBB is moving "right," and the other way for positive.
if(currColRightSide) {
if(velocityMagnitude < 0) {
if(noStaticOverlap) {
// System.out.println("(Right side) OBBs are moving away");
return false;
} else {
timeRange[0] = 0;
timeRange[1] = Math.abs(spaceBetweenProjections / velocityMagnitude);
}
} else if(velocityMagnitude > 0) {
if(noStaticOverlap) {
timeRange[0] = Math.abs(spaceBetweenProjections / velocityMagnitude);;
timeRange[1] = Math.abs((spaceBetweenProjections + 2 * rb) / velocityMagnitude);
} else {
timeRange[0] = 0;
timeRange[1] = Math.abs((spaceBetweenProjections + 2 * rb) / velocityMagnitude);
}
}
} else {
if(velocityMagnitude > 0) {
if(noStaticOverlap) {
// System.out.println("(Left side) OBBs are moving away");
return false;
} else {
timeRange[0] = 0;
timeRange[1] = Math.abs(spaceBetweenProjections / velocityMagnitude);
}
} else if(velocityMagnitude < 0) {
if(noStaticOverlap) {
timeRange[0] = Math.abs(spaceBetweenProjections / velocityMagnitude);
timeRange[1] = Math.abs((spaceBetweenProjections + 2 * rb) / velocityMagnitude);
} else {
timeRange[0] = 0;
timeRange[1] = Math.abs((spaceBetweenProjections + 2 * rb) / velocityMagnitude);
}
}
}
//Clamp values
if(timeRange[0] < 0) timeRange[0] = 0;
if(timeRange[1] > 1) timeRange[1] = 1;
//Switch so that the greater value comes last
if(timeRange[0] > timeRange[1]) {
double temp = timeRange[0];
timeRange[0] = timeRange[1];
timeRange[1] = temp;
}
if(timeRange[0] > 1 && timeRange[1] < 0) return false;
axisTimes.add(timeRange);
return true;
}
感谢 Whosebug 为我提供了这个问题的 Tumbleweed 徽章。如果有人提出更好或更优化的方法,请告诉我。谢谢! :D