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


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;

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


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);
   private CameraNode createCameraNode(final float boxExtent) {
      // movable object
      Box box = new Box("Box", Vector3f.ZERO.clone(), boxExtent,boxExtent,boxExtent);
        box.setModelBound(new BoundingBox());
        Node boxNode = new Node("node");
            ((BoundingBox) boxNode.getWorldBound()).zExtent*10F
      CameraNode camNode = new CameraNode("view",DisplaySystem.getDisplaySystem().getRenderer().getCamera());
      camNode.setLocalTranslation(0F, 10F, 0F);

      camNode.getCamera().setFrustumPerspective(55F, (float) DisplaySystem.getDisplaySystem().getWidth() / (float) DisplaySystem.getDisplaySystem().getHeight(), frustumNear, frustumFar);
      return camNode;
   private void addLightNode() {
      PointLight light = new PointLight();
        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));
        LightState lightState = DisplaySystem.getDisplaySystem().getRenderer().createLightState();
   public TestGS() {
      // world grid
      this.addGridNode(gridFactor/10F, gridFactor*100F);
      // camera node
      CameraNode cameraNode = this.createCameraNode(0.1F);
        TestController controller = new TestController(cameraNode);
      super.getRootNode().updateGeometricState(0, true);

   public void update(float tpf) {
   public void render(float 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,
   protected GameControlManager manager;
   protected void bindKey(ETravelAction action, int...keys) {
        final GameControl control = manager.getControl(;
        for (int key : keys) {
          control.addBinding(new KeyboardBinding(key));
   protected float enumValue(ETravelAction action) {
        return manager.getControl(;

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()) {
        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);  
   public void update(float time) {
        if (enumValue(ETravelAction.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).

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