Michael Ludwig avatar Michael Ludwig committed d2c0b4d

Implement a jittering collision algorithm that corrects the missed collisions uncovered by the GravityTest

Comments (0)

Files changed (5)

ferox-physics/src/main/java/com/ferox/physics/collision/DefaultCollisionAlgorithmProvider.java

 import java.util.Map;
 
 import com.ferox.physics.collision.algorithm.GjkEpaCollisionAlgorithm;
+import com.ferox.physics.collision.algorithm.JitteringCollisionAlgorithm;
 import com.ferox.physics.collision.algorithm.SphereSphereCollisionAlgorithm;
 import com.ferox.physics.collision.algorithm.SwappingCollisionAlgorithm;
+import com.ferox.physics.collision.shape.ConvexShape;
 
 /**
  * DefaultCollisionAlgorithmProvider is the default implementation of
         algorithmCache = new HashMap<TypePair, CollisionAlgorithm<?,?>>();
         lookup = new TypePair(null, null);
         
-        register(new GjkEpaCollisionAlgorithm());
+        // wrap the GJK/EPA algorithm with a jittering algorithm to help overcome
+        // numerical instabilities
+        register(new JitteringCollisionAlgorithm<ConvexShape, ConvexShape>(new GjkEpaCollisionAlgorithm()));
         register(new SphereSphereCollisionAlgorithm());
     }
 

ferox-physics/src/main/java/com/ferox/physics/collision/algorithm/JitteringCollisionAlgorithm.java

+package com.ferox.physics.collision.algorithm;
+
+import com.ferox.math.Matrix4;
+import com.ferox.math.Vector3;
+import com.ferox.physics.collision.ClosestPair;
+import com.ferox.physics.collision.CollisionAlgorithm;
+import com.ferox.physics.collision.Shape;
+
+public class JitteringCollisionAlgorithm<A extends Shape, B extends Shape> implements CollisionAlgorithm<A, B> {
+    private static final int MAX_JITTERS = 4;
+    
+    private final CollisionAlgorithm<A, B> wrapped;
+    
+    private final Vector3 jitter;
+    private final Matrix4 jitteredTransform;
+    
+    public JitteringCollisionAlgorithm(CollisionAlgorithm<A, B> wrapped) {
+        if (wrapped == null)
+            throw new NullPointerException("CollisionAlgorithm cannot be null");
+        this.wrapped = wrapped;
+        jitter = new Vector3();
+        jitteredTransform = new Matrix4();
+    }
+    
+    @Override
+    public ClosestPair getClosestPair(A shapeA, Matrix4 transA, B shapeB, Matrix4 transB) {
+        ClosestPair unjittered = wrapped.getClosestPair(shapeA, transA, shapeB, transB);
+        if (unjittered != null) {
+            // no jittering required to find a solution
+            return unjittered;
+        } else {
+            // apply random jitters to one transform
+            for (int i = 0; i < MAX_JITTERS; i++) {
+                jitter.set(Math.random() * shapeA.getMargin(), Math.random() * shapeA.getMargin(), Math.random() * shapeA.getMargin());
+                
+                jitteredTransform.set(transA);
+                jitteredTransform.m03 += jitter.x;
+                jitteredTransform.m13 += jitter.y;
+                jitteredTransform.m23 += jitter.z;
+                
+                ClosestPair jittered = wrapped.getClosestPair(shapeA, jitteredTransform, shapeB, transB);
+                if (jittered != null) {
+                    // remove any jittering from the two closest points
+                    // - since we translated the shape by jitter, the point in a
+                    //   moves in the opposite direction of untranslating the shape
+                    //   by jitter (which is just adding the jitter)
+                    Vector3 newPointOnA = new Vector3(jittered.getClosestPointOnA()).add(jitter);
+                    return new ClosestPair(newPointOnA, jittered.getContactNormal(), jittered.getDistance());
+                }
+            }
+            
+            // jittering did not find a solution
+            return null;
+        }
+    }
+
+    @Override
+    public Class<A> getShapeTypeA() {
+        return wrapped.getShapeTypeA();
+    }
+
+    @Override
+    public Class<B> getShapeTypeB() {
+        return wrapped.getShapeTypeB();
+    }
+}

ferox-physics/src/main/java/com/ferox/physics/dynamics/LinearConstraintSolver.java

     
     public LinearConstraintSolver() {
         shuffler = new Random();
-        setShuffleConstraints(true);
+        setShuffleConstraints(false);
         setShuffleEveryIteration(true);
         setIterationCount(10);
     }

ferox-physics/src/test/java/com/ferox/physics/GravityTest.java

     }
     
     private static void process(EntitySystem system, int numFrames, double time, boolean printStats) {
-        system.getControllerManager().process(1 / 360.0);
+        system.getControllerManager().process(1 / 60.0);
         
         if (printStats) {
             System.out.println("Avg FPS: " + (numFrames / time));

ferox-physics/src/test/java/com/ferox/physics/PhysicsTest.java

     private static final StorageMode COMPILE_TYPE = StorageMode.GPU_STATIC;
     private static final int BOUNDS = 100;
    
-    private static final int NUM_X = 6;
-    private static final int NUM_Y = 6;
-    private static final int NUM_Z = 6;
-    private static final double SCALE_X = 2.0;
+    private static final int NUM_X = 10;
+    private static final int NUM_Y = 10;
+    private static final int NUM_Z = 10;
+    private static final double SCALE_X = 3.0;
     private static final double SCALE_Y = 2.0;
-    private static final double SCALE_Z = 2.0;
+    private static final double SCALE_Z = 3.0;
     
     private static final double MARGIN = .05;
     private static final double PERCENT = .5;
     private static final double RANDOM = 0;
     
     private static final double START_POS_X = -5;
-    private static final double START_POS_Y = 5 + 2 * MARGIN;
+    private static final double START_POS_Y = 1 + 2 * MARGIN;
     private static final double START_POS_Z = -3;
     
     private static final AxisAlignedBox worldBounds = new AxisAlignedBox(new Vector3(-2 * BOUNDS - 1, -2 * BOUNDS - 1, -2 * BOUNDS - 1), 
                                                                          new Vector3(2 * BOUNDS + 1, 2 * BOUNDS + 1, 2 * BOUNDS + 1));
     
-    private static volatile boolean paused = true;
+    private static volatile boolean paused = false;
     
     public static void main(String[] args) throws Exception {
         final Framework framework = LwjglFramework.create();
         final EntitySystem system = new EntitySystem();
         
         // physics handling
-            system.getControllerManager().addController(new com.ferox.physics.controller.ForcesController());
-        
-//          system.getControllerManager().addController(new SpatialIndexCollisionController(new com.ferox.math.bounds.QuadTree<Entity>(worldBounds, 6), new DefaultCollisionAlgorithmProvider()));
-          system.getControllerManager().addController(new SpatialIndexCollisionController(new com.ferox.math.bounds.SimpleSpatialIndex<Entity>(), new DefaultCollisionAlgorithmProvider()));
-//            system.getControllerManager().addController(new SpatialIndexCollisionController(new com.ferox.math.bounds.Octree<Entity>(worldBounds, 6), new DefaultCollisionAlgorithmProvider()));
+        system.getControllerManager().addController(new com.ferox.physics.controller.ForcesController());
 
-            system.getControllerManager().addController(new com.ferox.physics.controller.ConstraintSolvingController());
-            system.getControllerManager().addController(new com.ferox.physics.controller.MotionController());
+//        system.getControllerManager().addController(new SpatialIndexCollisionController(new com.ferox.math.bounds.QuadTree<Entity>(worldBounds, 6), new DefaultCollisionAlgorithmProvider()));
+//        system.getControllerManager().addController(new SpatialIndexCollisionController(new com.ferox.math.bounds.SimpleSpatialIndex<Entity>(), new DefaultCollisionAlgorithmProvider()));
+        system.getControllerManager().addController(new SpatialIndexCollisionController(new com.ferox.math.bounds.Octree<Entity>(worldBounds, 6), new DefaultCollisionAlgorithmProvider()));
+
+        system.getControllerManager().addController(new com.ferox.physics.controller.ConstraintSolvingController());
+        system.getControllerManager().addController(new com.ferox.physics.controller.MotionController());
         
         system.getControllerManager().addController(new TransformController());
         
     
     private static OnscreenSurface buildSurface(Framework framework, EntitySystem system) {
         OnscreenSurfaceOptions options = new OnscreenSurfaceOptions().setWidth(500)
-                                                                     .setHeight(500)
-                                                                     .setMultiSampling(MultiSampling.FOUR_X);
+                                                                     .setHeight(500);
+//                                                                     .setMultiSampling(MultiSampling.FOUR_X);
         OnscreenSurface surface = framework.createSurface(options);
 //        surface.setVSyncEnabled(true);
 
                     
                     e.add(CollisionBody.ID).getData().setShape(physShape)
                                                      .setTransform(new Matrix4(1, 0, 0, (SCALE_X + 2 * MARGIN) * x + rx + startX,
-                                                                               0, 1, 0, (SCALE_Y + 2 * MARGIN) * y + ry + startY,
+                                                                               0, 1, 0, (SCALE_Y + 2 * MARGIN + (y > NUM_Y / 2 ? 1 : 0)) * y + ry + startY,
                                                                                0, 0, 1, (SCALE_Z + 2 * MARGIN) * z + rz + startZ,
                                                                                0, 0, 0, 1));
                     e.add(RigidBody.ID).getData().setMass(1.0);
Tip: Filter by directory path e.g. /media app.js to search for public/media/app.js.
Tip: Use camelCasing e.g. ProjME to search for ProjectModifiedEvent.java.
Tip: Filter by extension type e.g. /repo .js to search for all .js files in the /repo directory.
Tip: Separate your search with spaces e.g. /ssh pom.xml to search for src/ssh/pom.xml.
Tip: Use ↑ and ↓ arrow keys to navigate and return to view the file.
Tip: You can also navigate files with Ctrl+j (next) and Ctrl+k (previous) and view the file with Ctrl+o.
Tip: You can also navigate files with Alt+j (next) and Alt+k (previous) and view the file with Alt+o.