Spatial.lookAt again


Ok, i really don't want to open another lookAt topic, but i don't get it.


Is there a reason that my spatial does only correctly look at my mouse origin when the spatial's world translation is set to 0,0,0?

The further the spatial get's moved from the center, the more corrupt the rotation gets.

Is that the normal behaviour and what have i to do to fix that issue?


Thank you,
Maurice

can you show the code part where you use look at?

I sometimes have problems that the World vectors are not up to date, so whenever you access the spatials WorldTranslation, make sure to call updateWorldVector() first.


Sure.

I have tried to add root.updateWorldVectors() at the beginning of the method, but that don't seem to change anything. In my update method i call always root.updateWorldVectors.

This is my code for letting the ship look at the mouse origin. Because i only want to use 2 axes for movement (x,y), z is set to 0. So the mShips up-vector should be Z (mShip is the spatial that will rotate on mouseMove to the target position)


  private void shipLookAtTarget() {
    Ray mouseRay = null;
    Vector2f mousePos = new Vector2f();
    mousePos.x = MouseInput.get().getXAbsolute();
    mousePos.y = MouseInput.get().getYAbsolute();
    mouseRay = display.getPickRay(mousePos, true, mouseRay);
    target = mouseRay.getOrigin();
    target.z=0f;
    target.y *= -1;
    mShip.lookAt(target, Vector3f.UNIT_Z);
  }



MouseMove:


      public void onMove(int xDelta, int yDelta, int newX, int newY) {
        shipLookAtTarget();
      }



Update:


  protected void simpleUpdate() {
    super.simpleUpdate();

    rootNode.updateWorldVectors();
    mShip.updateWorldVectors();
   
    if (!released) {
      Quaternion old = new Quaternion(mShip.getLocalRotation());
      mShip.getLocalRotation().slerp(old, 0.001f);
      mShip.addForce(mShip.getLocalRotation().getRotationColumn(2).mult(0.01f));
    }
  }



Here is the complete code if something is not clear:


package de.okunektion.tuts.test1;

import java.util.logging.ConsoleHandler;
import java.util.logging.Level;
import java.util.logging.Logger;

import com.jme.input.MouseInput;
import com.jme.input.MouseInputListener;
import com.jme.math.Quaternion;
import com.jme.math.Ray;
import com.jme.math.Vector2f;
import com.jme.math.Vector3f;
import com.jme.renderer.ColorRGBA;
import com.jme.scene.shape.Box;
import com.jmex.physics.DynamicPhysicsNode;
import com.jmex.physics.StaticPhysicsNode;

public class Test2 extends CustomGame {

  ColorRGBA[] red = new ColorRGBA[3];

  private static final Logger logger = Logger.getLogger(Test3.class.getName());

  private StaticPhysicsNode staticNode;

  private boolean released;

  private Vector3f target;

  private DynamicPhysicsNode mShip;

  /**
   * Simple Init Game
   */
  protected void simpleInitGame() {
    logger.setLevel(Level.INFO);
    logger.addHandler(new ConsoleHandler());
   
    released = true;

    staticNode = getPhysicsSpace().createStaticNode();
    rootNode.attachChild(staticNode);
    staticNode.getSpace().setDirectionalGravity(new Vector3f(0, 0, 0));

    mShip = getPhysicsSpace().createDynamicNode();
    mShip.createSphere("test").setLocalScale(0.03f);
    rootNode.attachChild(mShip);
    mShip.setLocalTranslation(1, 1, 0);

    red[0] = new ColorRGBA(1, 0, 0, 0.5f);
    red[1] = new ColorRGBA(0, 1, 0, 0.5f);

    Box boxX = new Box("Box2", new Vector3f(0, 0, 0), 20f, 0.01f, 0f);
    Box boxY = new Box("Box1", new Vector3f(0, 0, 0), 0.01f, 20f, 0f);
    boxX.setDefaultColor(red[0]);
    boxY.setDefaultColor(red[1]);
    rootNode.attachChild(boxX);
    rootNode.attachChild(boxY);

    // MOUSE INPUT SYSTEM
    MouseInput.get().setCursorVisible(true);

    MouseInput.get().addListener(new MouseInputListener() {
      public void onButton(int button, boolean pressed, int x, int y) {

        if (button == 1) {
          if (pressed) {
            released = false;
          } else {
            released = true;
          }
        }
      }

      public void onMove(int xDelta, int yDelta, int newX, int newY) {
        shipLookAtTarget();
      }

      public void onWheel(int wheelDelta, int x, int y) {
      }
    });

    this.cam.setLocation(new Vector3f(1, 1, 1f));
    this.cam.setUp(Vector3f.UNIT_Y);
    showPhysics = true;
  }

  protected void simpleUpdate() {
    super.simpleUpdate();

    rootNode.updateWorldVectors();
    mShip.updateWorldVectors();
   
    if (!released) {
      Quaternion old = new Quaternion(mShip.getLocalRotation());
      mShip.getLocalRotation().slerp(old, 0.001f);
      mShip.addForce(mShip.getLocalRotation().getRotationColumn(2).mult(0.01f));
    }
  }

  private void shipLookAtTarget() {
    Ray mouseRay = null;
    Vector2f mousePos = new Vector2f();
    mousePos.x = MouseInput.get().getXAbsolute();
    mousePos.y = MouseInput.get().getYAbsolute();
    mouseRay = display.getPickRay(mousePos, true, mouseRay);
    target = mouseRay.getOrigin();
    target.z=0f;
    target.y *= -1;
    mShip.lookAt(target, Vector3f.UNIT_Z);
  }

  /**
   * Test Main Method
   *
   * @param args
   */
  public static void main(String[] args) {
    Test2 test = new Test2();
    test.setDialogBehaviour(Test1.ALWAYS_SHOW_PROPS_DIALOG);
    test.start();
  }
}




By the way:
Why is the standard Z-value of the mouse origin always 3?


Kind regards,
Maurice

this lookat method seems to work for me, i just changed the vcerticalFlip to false and removed the inverting of y.

to run it, i also changed CustomGame to SimplePhysicsGame


  private void shipLookAtTarget() {
    Ray mouseRay = null;
    Vector2f mousePos = new Vector2f();
    mousePos.x = MouseInput.get().getXAbsolute();
    mousePos.y = MouseInput.get().getYAbsolute();
   
//    mouseRay = display.getPickRay(mousePos, true, mouseRay);
    mouseRay = display.getPickRay(mousePos, false, mouseRay);
    target = mouseRay.getOrigin();
    target.z=0f;
//    target.y *= -1;
    mShip.lookAt(target, Vector3f.UNIT_Z);
  }


HAHAHAHA! That's it!

I don't really know why i have changed flipVertical to true. Damn it.

Thank you very much!
I think i will take a deeper look at the vector mathematics there to figure out why that approach has messed up my rotation.

- Maurice

:expressionless: I think i was a little to optimistic :expressionless:



If you change the camera's position to



this.cam.setLocation(new Vector3f(1, 1, 3f));



you have zoomed out a little bit. While it does seem to work when you are very near to the ship's origin (1,1,0 in our example with camera set to 1,1,1) it is the same error when you just zoom out. Somehow the ships origin has to be recalculated with the changed translation or somnething.

hmmm...

if you also comment out  target.z=0f;  then look at i works as expected i think. i guess the Z value is needed to compute the perspective correctly.



But want that your ship only rotates around the Z axis right ?





I think to get the correct mouse pointer location you have to create a big Quad at Z = 0.

Then you cast a ray to the quad and see where it intersects, now you have the correct WorldLocation to look at.





edit: changed Y to Z axis


Well i think i have to rotate the ship around the Z-axis, because it should be the same controls as in Asteroids (Horizontal Axis is X, Vertical is Y, so the ship should rotate around Z. I'm thinking of the Z-Axis as a nail which pins down the ship to the XY-plane or something like that).

For me it isn't clear why the Javadoc says the following about the 'lookAt' method:


It computes the rotation to transform the z-axis to point onto 'position' and the y-axis to 'up'.


Is that the standard behaviour or why can i specify this with the second parameter? If it internally ONLY works that way the code will not work like i have written it.

When i comment out the "target.z=0f;" line AND set the cameras Z position to 4 it _seems_ to work. Using 5 causes the Ship to fly along the Z-Axis.

As you have said, that could be a perspective refreshing problem. Unfortunalety, i'm a beginner at jME, so i have to take a more detailed look at this. I think your workaround will work, but it seems not to be a "it should be like that" solution...

Well, i see what i will find out :)

Thank you
- Maurice

That is what i want to do:







Rotate the ship around the Z-Axis and move it along the x,y coords.

The camera is the standard cam with UP = y.



-Maurice

I haven't really looked at the code as I don't have physics set up.

iirc lookAt is really simple so you could prob modify it if it doesn't work the way you need.



Alternatively, in two dimensions like that it should be easy enough just to do with a single angle?

  • Subtract the ship's position from the mouse's to get the vector heading you want
  • Normalize it
  • Find the angle between that vector and the ship's forward vector
  • Rotate the ship by that angle

    Prob could also do it with fromaxes since you have two known axes.

Yeah, i will try this and a few other things.

In my opinion it should not be a problem at all, but i think i have to make some vector-based homework at first and take a deeper look to the engine's methods.

Thank you,
- Maurice

I have done a little bit of debugging and i think i know what the problem is:



  private void shipLookAtTarget() {
    Ray mouseRay = null;
    Vector2f mousePos = new Vector2f();
    mousePos.x = MouseInput.get().getXAbsolute();
    mousePos.y = MouseInput.get().getYAbsolute();
    mouseRay = display.getPickRay(mousePos, false, mouseRay);
    target = mouseRay.getOrigin();
    target.z=0f;
    mShip.lookAt(target, Vector3f.UNIT_Z);
  }



The lookAt() method DOES work, as well as the other methods.

BUT:


mouseRay = display.getPickRay(mousePos, false, mouseRay);
target = mouseRay.getOrigin();



Is returning always the same target-ccordinates.
Even if i zoom out (set the camera's z - position) to a high level and click again to do a findPick, the values of target have NOT changed (for example i'm clicking right below the x-axis and i get the positive values from the initial screen before zooming out).

In my case, getPickRay returns only the initial values calculated from the initial settings.

Is there anything i have to update regarding the display / camera etc.?