Moving a CameraNode with a low world unit object causes a "jumping" on all axis

Hello,



I prepared a test with a cameranode, input keys are arrows to select direction and z to apply speed,

pratically when I turn in any direction the object starts to jump… please can you help me to find

why the object is jumping?



package test;

import static com.jme.input.KeyInput.*;

import java.util.ArrayList;
import java.util.logging.Logger;

import com.jme.bounding.BoundingBox;
import com.jme.input.controls.GameControl;
import com.jme.input.controls.GameControlManager;
import com.jme.input.controls.binding.KeyboardBinding;
import com.jme.light.PointLight;
import com.jme.math.Quaternion;
import com.jme.math.Vector3f;
import com.jme.renderer.ColorRGBA;
import com.jme.renderer.Renderer;
import com.jme.scene.CameraNode;
import com.jme.scene.Controller;
import com.jme.scene.Geometry;
import com.jme.scene.Line;
import com.jme.scene.Node;
import com.jme.scene.shape.Box;
import com.jme.scene.state.LightState;
import com.jme.system.DisplaySystem;
import com.jmex.game.StandardGame;
import com.jmex.game.state.BasicGameState;
import com.jmex.game.state.BasicGameStateNode;
import com.jmex.game.state.GameStateManager;

public class TestGame {
   
   private static StandardGame instance;
   
    public static void main(String[] args) {
        
        Runtime.getRuntime().addShutdownHook(new Thread(){
            public void run() {
                System.runFinalizersOnExit(true);
            }
        });
        
        
        instance = new StandardGame("Test Game", StandardGame.GameType.GRAPHICAL, null);
        instance.start();
        
        BasicGameStateNode<BasicGameState> base = new BasicGameStateNode<BasicGameState>("Test View");
        GameStateManager.getInstance().attachChild(base);
                
        TestGS stateTest = new TestGS();
        stateTest.setActive(true);
        base.attachChild(stateTest);
        

        base.setActive(true);
        
    }
}

class TestGS extends BasicGameState {

   private static final long serialVersionUID = 1L;
   
   private static final Logger LOGGER = Logger.getLogger(TestGS.class.getName());
   
   private float gridFactor = 1000F;
   private float frustumNear = 0.00000001F;
   private float frustumFar =  1000000000F;
   
   private void addGridNode(float spacing, float extent) {
      //Node gridNode = ObjectLibrary.createGridNode(Vector3f.ZERO.clone(), gridFactor*100F, gridFactor);
      Node gridNode = new Node("grid");
      ArrayList<Vector3f> regularVertices = new ArrayList<Vector3f>();
      for (int i = 0; i * spacing <= extent; i++) {
            regularVertices.add(new Vector3f(-extent, 0, i * spacing));
            regularVertices.add(new Vector3f(extent, 0, i * spacing));
            regularVertices.add(new Vector3f(-extent, 0, -i * spacing));
            regularVertices.add(new Vector3f(extent, 0, -i * spacing));
            regularVertices.add(new Vector3f(i * spacing, 0, -extent));
            regularVertices.add(new Vector3f(i * spacing, 0, extent));
            regularVertices.add(new Vector3f(-i * spacing, 0, -extent));
            regularVertices.add(new Vector3f(-i * spacing, 0, extent));
      }
      Geometry regularGrid = new Line("regularLine", regularVertices
                .toArray(new Vector3f[] {}), null, null, null);
        regularGrid.getDefaultColor().set(ColorRGBA.darkGray);
        gridNode.attachChild(regularGrid);
      super.getRootNode().attachChild(gridNode);
   }
      
   private CameraNode createCameraNode(final float boxExtent) {
      
      // movable object
      Box box = new Box("Box", Vector3f.ZERO.clone(), boxExtent,boxExtent,boxExtent);
        box.setModelBound(new BoundingBox());
        box.updateModelBound();
        box.setRandomColors();
        box.setRenderQueueMode(Renderer.QUEUE_OPAQUE);
        
        Node boxNode = new Node("node");
        boxNode.attachChild(box);
        boxNode.updateWorldBound();
              
      boxNode.getLocalTranslation().set(
            0F,
            0F,
            ((BoundingBox) boxNode.getWorldBound()).zExtent*10F
            );
      
      CameraNode camNode = new CameraNode("view",DisplaySystem.getDisplaySystem().getRenderer().getCamera());
      camNode.setLocalTranslation(0F, 10F, 0F);
      camNode.attachChild(boxNode);

      camNode.getCamera().setFrustumPerspective(55F, (float) DisplaySystem.getDisplaySystem().getWidth() / (float) DisplaySystem.getDisplaySystem().getHeight(), frustumNear, frustumFar);
      
      return camNode;
   }
   
   private void addLightNode() {
      PointLight light = new PointLight();
        light.setAttenuate(true);
        light.setDiffuse(new ColorRGBA(1.0F, 1.0F, 0.25F, 1.0F));
        light.setAmbient(new ColorRGBA(0.1F, 0.1F, 0.1F, 1.0F));
        light.setLocation(new Vector3f(0F, 0F, 0F));
        light.setEnabled(true);
        
        LightState lightState = DisplaySystem.getDisplaySystem().getRenderer().createLightState();
        lightState.setEnabled(true);
        lightState.attach(light);
        super.getRootNode().setRenderState(lightState);
   }
   
   public TestGS() {
      super("gsTest");
      
      // world grid
      this.addGridNode(gridFactor/10F, gridFactor*100F);
      
      // camera node
      CameraNode cameraNode = this.createCameraNode(0.1F);
      super.getRootNode().attachChild(cameraNode);
      
        TestController controller = new TestController(cameraNode);
        super.getRootNode().addController(controller);
      
        //light
      this.addLightNode();
        
      super.getRootNode().updateGeometricState(0, true);
      
   }

   @Override
   public void update(float tpf) {
      super.getRootNode().updateWorldData(tpf);
      super.update(tpf);
   }
   
   @Override
   public void render(float tpf) {
      super.render(tpf);
   }
   
}



abstract class AController extends Controller {
   
   private static final long serialVersionUID = 1L;

    private static final Logger LOGGER = Logger.getLogger(AController.class.getName());
    
    enum ETravelAction {
        LEFT, RIGHT, UP, DOWN,
        INCREASE, DECREASE,
        STRAFE_UP,STRAFE_DOWN,STRAFE_LEFT,STRAFE_RIGHT,
        ULTRAZOOMIN, ULTRAZOOMOUT, ZOOMIN, ZOOMOUT,
        TARGET_SHIP,
        EXIT}
    
   
   protected GameControlManager manager;
   
   protected void bindKey(ETravelAction action, int...keys) {
        final GameControl control = manager.getControl(action.name());
        for (int key : keys) {
          control.addBinding(new KeyboardBinding(key));
        }
    }
 
   protected float enumValue(ETravelAction action) {
        return manager.getControl(action.name()).getValue();
    }
    
}


class TestController extends AController {
   
   private static final long serialVersionUID = 1L;

    private static final Logger LOGGER = Logger.getLogger(TestController.class.getName());

   private static final float TURN_SPEED = 2F;
    
    private CameraNode cameraNode;

   private float hAngle;
   private float vAngle;
   
   private float speedcam = 1F;
   
   
   private Quaternion q = new Quaternion();
   
    
    public TestController(CameraNode cameraNodePar) {
       this.cameraNode = cameraNodePar;
       
       this.manager = new GameControlManager();
       
       //create all actions
        for (ETravelAction action : ETravelAction.values()) {
            manager.addControl(action.name());
        }
       
        bindKey(ETravelAction.EXIT, KEY_ESCAPE);
        bindKey(ETravelAction.INCREASE, KEY_Z);
        bindKey(ETravelAction.DECREASE, KEY_X);
        bindKey(ETravelAction.TARGET_SHIP, KEY_SPACE);
        
      bindKey(ETravelAction.ZOOMIN, KEY_ADD);
      bindKey(ETravelAction.ZOOMOUT, KEY_MINUS);
        
        bindKey(ETravelAction.UP, KEY_UP);
        bindKey(ETravelAction.DOWN, KEY_DOWN);
        bindKey(ETravelAction.LEFT, KEY_LEFT);
        bindKey(ETravelAction.RIGHT, KEY_RIGHT);
        bindKey(ETravelAction.STRAFE_UP, KEY_W);
        bindKey(ETravelAction.STRAFE_DOWN, KEY_S);
        bindKey(ETravelAction.STRAFE_LEFT, KEY_A);
        bindKey(ETravelAction.STRAFE_RIGHT, KEY_D);  
        
    }
    
   @Override
   public void update(float time) {
      
        if (enumValue(ETravelAction.EXIT) > 0) {
            System.exit(0);
        }
        
        if (enumValue(ETravelAction.LEFT) > 0||enumValue(ETravelAction.RIGHT) > 0
         ||enumValue(ETravelAction.UP) > 0||enumValue(ETravelAction.DOWN) > 0) {
           hAngle += TURN_SPEED * time * (enumValue(ETravelAction.LEFT) - enumValue(ETravelAction.RIGHT));
          vAngle += TURN_SPEED * time * (enumValue(ETravelAction.DOWN) - enumValue(ETravelAction.UP));
          this.cameraNode.getLocalRotation().set( q.fromAngles(vAngle, hAngle, 0f) );
        }
        
        
        if (enumValue(ETravelAction.INCREASE) > 0
              /*||enumValue(ETravelAction.DECREASE) > 0*/) {
           Vector3f shipDirection = new Vector3f();
           Vector3f observedPosition = this.cameraNode.getLocalTranslation();
           observedPosition.addLocal(this.cameraNode.getLocalRotation().getRotationColumn(2, shipDirection).multLocal(speedcam));
        }
                
   }

}

It is much code…



perhaps it "jumps" (can only guess what you mean) because in this line


           observedPosition.addLocal(this.cameraNode.getLocalRotation().getRotationColumn(2, shipDirection).multLocal(speedcam));


you are missing the time parameter of update(float time) (in the rotation part you applied it).

regards
snareoj2 said:

It is much code...


Never asked to debug, I placed the code only to make visible the "frame jumping" problem,
hoping someone had already encountered and solved this problem.

snareoj2 said:

you are missing the time parameter of update(float time) (in the rotation part you applied it).


It does not fix the problem.

However I see the problem only when I turn the direction of the camera, so probably it is the quaternion operation