【问题标题】:Dynamic OBB Collision Detection (Separating Axis Theorem): Find the Time That Collision Occurred?动态 OBB 碰撞检测(分离轴定理):找出碰撞发生的时间?
【发布时间】:2017-03-18 06:16:17
【问题描述】:

现在,我正在尝试使用分离轴定理在 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。假设我什至正确理解如何正确实现分离轴定理,我哪里错了?

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

最后说明:

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

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

“数学”是我自己的静态类。假设它工作正常。直到我做出来之后,我才意识到 Vector3f 拥有所有这些有用的功能。

This 是我正在使用的 PDF。我在 2.3.1 的第 9 页卡住了。

【问题讨论】:

    标签: java collision-detection


    【解决方案1】:

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

    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

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2015-06-26
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2014-08-12
      相关资源
      最近更新 更多