动态OBB碰撞检测(分离轴定理):找出碰撞发生的时间?

时间:2017-02-20 04:31:09

标签: java collision-detection

现在,我正在尝试使用分离轴定理在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);
}

但是,我的价值观高于一。假设我甚至正确地理解如何正确实现分离轴定理,我哪里出错了?

如果您认为自己有答案,但如果我发布课程的其余部分(虽然时间很长)会有所帮助,请告诉我,我会为您做。谢谢!

最后的笔记:

此功能在OBB类中。因此,“this”指的是OBB,“obb”指的是另一个OBB。

collisionPacket.getVelocity()返回在没有碰撞的情况下将在单个帧中发生的总位移。

“数学”是我自己的静态课程。假设它正常工作。在我做完之前,我没有意识到Vector3f拥有所有这些有用的功能。

This是我正在使用的PDF。我陷入了第9页,即2.3.1。

1 个答案:

答案 0 :(得分:0)

几周后,我想出了如何做我想做的事情。几个星期前我实际想出了这个,但我现在想要发布我的解决方案。

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;
}

感谢StackOverflow为这个问题提供了Tumbleweed徽章。如果有人提出更好或更优化的方法,请告诉我。谢谢! :d