PhysicsSpace - first update of run

I'm currently working on an architecture that will allow the simulation of planetary systems, and have run into a snag.



After creating an earth and a satellite that should be orbiting the planet, the satellite just start jumping around randomly. Stepping through the gravity and physics updates, it seems that the first update isn't properly clearing the force applied to the satellite and updating its velocity.



Can anyone spot something in my code that i'm missing?



GravTester:


public class GravTester extends GameWrapper {
   private PhysicsSpace physicsSpace;
   private GravitySystem gravSys;
   private Node rootNode;
   private float timeflow = 5.0f;
   private InputHandler input;
   private Camera camera;
   private DynamicPhysicsNode satphys;
   private boolean gravupdate = false;

   protected void initGame() {
      gravSys = new GravitySystem();
      physicsSpace = PhysicsSpace.create();
      physicsSpace.setDirectionalGravity( Vector3f.ZERO );
      renderer.setBackgroundColor( ColorRGBA.black );
      rootNode = createRootNode( "rootNode" );

      float earthradius = 6371f;
      float earthmass = (float) (5.9736*Math.pow(10,24));
      URL earthtex = Activator.class.getClassLoader().getResource("com/phoenix/orbital/textures/earthTex.jpg");
      DynamicPhysicsNode earthPhys = physicsSpace.createDynamicNode();
      Globe earth = new Globe( "earth", earthtex, null, earthradius );
      earth.setModelBound( new BoundingSphere() );
      earth.updateModelBound();
      earthPhys.setMass(earthmass);
      earthPhys.attachChild(earth);
      earthPhys.updateModelBound();
      earthPhys.generatePhysicsGeometry();
      gravSys.registerBody(earthPhys);
      rootNode.attachChild(earthPhys);
      earthPhys.setLocalTranslation(0,0,0);
      earthPhys.setLinearVelocity(Vector3f.ZERO);

      float satmass = 1f;
      float satradius = 500f;
      satphys = physicsSpace.createDynamicNode();
      Globe sat = new Globe( "sat", null, null, satradius );
      sat.setModelBound( new BoundingSphere() );
      sat.updateModelBound();
      satphys.setMass( satmass );
      satphys.attachChild( sat );
      satphys.updateModelBound();
      satphys.generatePhysicsGeometry();
      gravSys.registerBody( satphys );
      rootNode.attachChild( satphys );
      satphys.setLocalTranslation( 7000, 0, 0 );
      satphys.setLinearVelocity( new Vector3f(0,0,7.5461f) );

//      float moonradius = 1737f;
//      float moonmass = (float) (73.48*Math.pow(10,21));
//      URL moontex  = Activator.class.getClassLoader().getResource("com/phoenix/orbital/textures/moonTex.jpg");
//      DynamicPhysicsNode moonPhys = physicsSpace.createDynamicNode();
//      Globe moon = new Globe( "moon", moontex, null, moonradius );
//      moon.setModelBound( new BoundingSphere() );
//      moon.updateModelBound();
//      moonPhys.setMass(moonmass);
//      moonPhys.attachChild(moon);
//      moonPhys.updateModelBound();
//      moonPhys.generatePhysicsGeometry();
//      gravSys.registerBody(moonPhys);
//      rootNode.attachChild(moonPhys);
//      moonPhys.setLocalTranslation( 363104, 0, 0 );
//      moonPhys.setLinearVelocity( new Vector3f(0,0,1.0829f) );

      int camheight = 80000;
      camera = createCamera(0.1f, (float) (camheight*Math.sqrt(2)), true, 45.0f);
      camera.setLocation( new Vector3f(1,camheight,0) );
      camera.lookAt(Vector3f.ZERO, Vector3f.UNIT_Y);
      renderer.setCamera(camera);

      input = new FirstPersonHandler(camera, camheight/10, .5f);

      float interpolation = 0.1f;
      rootNode.updateGeometricState(interpolation, true);
      rootNode.updateWorldData(interpolation);
      rootNode.updateRenderState();
//      physicsSpace.update(interpolation);
   }

   protected void reinit() {
      // TODO reinit?
   }

   protected void update(float interpolation) {
      input.update(interpolation);

      if ( gravupdate ) {
         System.out.println("before update (satloc): "+satphys.getLocalTranslation());
            gravSys.update();                  // gravupdate
         System.out.println(" F : "+satphys.getForce(null));
            physicsSpace.update(interpolation);      // physupdate
         System.out.println("CLRF:"+satphys.getForce(null));
         System.out.println("CLRF:"+satphys.getForce(null));
         System.out.println(" v : "+satphys.getLinearVelocity(null));
         System.out.println("|v|: "+satphys.getLinearVelocity(null).length());
         System.out.println("after update (satloc): "+satphys.getLocalTranslation());
         System.out.println("


");

         rootNode.updateGeometricState(interpolation, true);
         rootNode.updateWorldData(interpolation);
         rootNode.updateRenderState();
         gravupdate = false;
      }
   }

   protected void render(float interpolation) {
      renderer.clearStatistics();
      renderer.clearBuffers();
      renderer.draw(rootNode);
      renderer.displayBackBuffer();
   }

   protected void setupKeybinds() {
      KeyBindingManager keymanager = KeyBindingManager.getKeyBindingManager();
      keymanager.set( "gravupdate", KeyInput.KEY_U );
      keymanager.set( "exit", KeyInput.KEY_ESCAPE );
   }

   protected void checkKeybinds() {
      KeyBindingManager keymgr = KeyBindingManager.getKeyBindingManager();
      if ( keymgr.isValidCommand("gravupdate", false) )
         gravupdate = true;
      if ( keymgr.isValidCommand("exit") )
         finish();
   }

   protected void cleanup() {
      // TODO cleanup?
   }

   public static void main(String[] args) {
      new GravTester().start();
   }
}



GravitySystem:


public class GravitySystem {
   private double GRAV_CONST = 6.6742*Math.pow(10,-20);   // km^3/(kg * s^2)
   private List<DynamicPhysicsNode> bodies;

   /**
    * Default constructor.
    */
   public GravitySystem() {
      bodies = new ArrayList<DynamicPhysicsNode>();
   }

   /**
    * @param physicsBody the body to incorporate into gravitational computations
    */
   public void registerBody( DynamicPhysicsNode physicsBody ) {
      bodies.add( physicsBody );
   }

   public void update() {
      for ( int i = 0; i < bodies.size(); i++ ) {
         double Gi = GRAV_CONST*bodies.get(i).getMass();
         for ( int j = i+1; j < bodies.size(); j++ ) {
            Vector3f r = bodies.get(j).getLocalTranslation();
            r.subtractLocal( bodies.get(i).getLocalTranslation() ).normalizeLocal();
            double magnitude = ( Gi*bodies.get(j).getMass() )/(r.lengthSquared());
            if ( j == 1 ) {
               System.out.println(" r : " + r.normalize());
               System.out.println("|r|: " + magnitude);
            }
            bodies.get(j).addForce( r.normalize().mult( (float) -magnitude ) );
            bodies.get(i).addForce( r.normalize().mult( (float) magnitude ) );
         }
      }
   }
}



Note: GameWrapper is essentially a BaseSimpleGame that does some specific displaysystem setup and has the createCamera and createRootNode fucntions with create a camera and set up a rootnode with zbufferstate and cullstate, etc.

Running the application and stepping through the grav/physics updates a few times provides this ouput:


before update (satloc): com.jme.math.Vector3f [X=7000.0, Y=0.0, Z=0.0]
r : com.jme.math.Vector3f [X=1.0, Y=0.0, Z=0.0]
|r|: 398690.0051943765
F : com.jme.math.Vector3f [X=-398690.0, Y=0.0, Z=0.0]
CLRF:com.jme.math.Vector3f [X=-398690.0, Y=0.0, Z=0.0]
CLRF:com.jme.math.Vector3f [X=-398690.0, Y=0.0, Z=0.0]
v : com.jme.math.Vector3f [X=0.0, Y=0.0, Z=7.5461]
|v|: 7.5461
after update (satloc): com.jme.math.Vector3f [X=1.0, Y=0.0, Z=0.0]
before update (satloc): com.jme.math.Vector3f [X=1.0, Y=0.0, Z=0.0]
r : com.jme.math.Vector3f [X=1.0, Y=0.0, Z=0.0]
|r|: 398690.0051943765
F : com.jme.math.Vector3f [X=-797380.0, Y=0.0, Z=0.0]
CLRF:com.jme.math.Vector3f [X=0.0, Y=0.0, Z=0.0]
CLRF:com.jme.math.Vector3f [X=0.0, Y=0.0, Z=0.0]
v : com.jme.math.Vector3f [X=137256.02, Y=26.606236, Z=188.2806]
|v|: 137256.14
after update (satloc): com.jme.math.Vector3f [X=1373.5602, Y=0.26606235, Z=1.882806]
before update (satloc): com.jme.math.Vector3f [X=1373.5602, Y=0.26606235, Z=1.882806]
r : com.jme.math.Vector3f [X=0.9999991, Y=1.9370257E-4, Z=0.0013707476]
|r|: 398690.0289581541
F : com.jme.math.Vector3f [X=-398689.7, Y=-77.22728, Z=-546.5034]
CLRF:com.jme.math.Vector3f [X=0.0, Y=0.0, Z=0.0]
CLRF:com.jme.math.Vector3f [X=0.0, Y=0.0, Z=0.0]
v : com.jme.math.Vector3f [X=133269.12, Y=25.833963, Z=182.81557]
|v|: 133269.25
after update (satloc): com.jme.math.Vector3f [X=2706.2515, Y=0.52440196, Z=3.7109616]


From this, it can be seen that the forces on the satellite aren't cleared, and that the physics update moves the satellite straight toward the planet, where it should move in the positive z direction more, and only slightly towards the planet.

If someone with another set of eyes could spot something, tha'd be helpful, otherwise im just gonna keep tryin to figure this out.

Thanks!

You do a subtractLocal() on the bodies LocalTranslation.

'r' is a reference to the translation, try to clone() if you want to make a copy.


Vector3f r = bodies.get(j).getLocalTranslation();
r.subtractLocal( bodies.get(i).getLocalTranslation() ).normalizeLocal();

Aha! That fixed it - thanks a lot!!!

I knew it was gonna be some stupid bug like that.