Camera rotation (MyFlyByCamera), how to lift height and rotate on start?

Hi,
exteded FlyByCamera to get a sort of RTSCamera, with LefltMouseButton-drag: shifts my map and RMB-drag: rotates the view. So far so nice.

But I failed to init my cameras position on start. Also I wonder what myCam.setCenter(new Vector3f(0,0.5f,0)); should do, it seems to do nothing on FlyByCams?

How do I lift my camera on init and turn the view a bit down to view my map from above?

Show us what you tried. Can you post the class?

sure, its a copy of FlyByCamera with some changes on LMB and RMB behavior

[java]

import com.jme3.collision.CollisionResults;
import com.jme3.collision.MotionAllowedListener;
import com.jme3.input.InputManager;
import com.jme3.input.Joystick;
//import com.jme3.input.JoystickAxis;
import com.jme3.input.KeyInput;
import com.jme3.input.MouseInput;
import com.jme3.input.controls.*;
import com.jme3.math.FastMath;
import com.jme3.math.Matrix3f;
import com.jme3.math.Quaternion;
import com.jme3.math.Ray;
import com.jme3.math.Vector3f;
import com.jme3.math.Vector2f;
import com.jme3.renderer.Camera;
import com.jme3.scene.Node;

/**

  • A first person view camera controller.

  • After creation, you must register the camera controller with the

  • dispatcher using #registerWithDispatcher().

  • Controls:

    • Move the mouse to rotate the camera
    • Mouse wheel for zooming in or out
    • WASD keys for moving forward/backward and strafing
    • QZ keys raise or lower the camera
      */
      public class MyFlyByCamera implements AnalogListener, ActionListener {

    public Node shootables;

    private static String[] mappings = new String[]{
    “FLYCAM_Left”,
    “FLYCAM_Right”,
    “FLYCAM_Up”,
    “FLYCAM_Down”,

        "FLYCAM_StrafeLeft",
        "FLYCAM_StrafeRight",
        "FLYCAM_Forward",
        "FLYCAM_Backward",
    
        "FLYCAM_ZoomIn",
        "FLYCAM_ZoomOut",
        "FLYCAM_RotateDrag",
        "FLYCAM_MoveDrag",
    
        "FLYCAM_Rise",
        "FLYCAM_Lower",
       
        "FLYCAM_InvertY"
    };
    

    protected Camera cam;
    protected Vector3f initialUpVec;
    protected float rotationSpeed = 1f;
    protected float moveSpeed = 20f;
    protected float zoomSpeed = 10f;
    private Vector3f center = new Vector3f();
    protected MotionAllowedListener motionAllowed = null;
    protected boolean enabled = true;
    protected boolean dragToMove = true;
    protected boolean dragToRotate = true;
    protected boolean canRotate = false;
    protected boolean canMove = false;
    protected boolean invertY = false;
    protected InputManager inputManager;

    /**

    • Creates a new MyFlyByCamera to control the given Camera object.
    • @param cam
      */
      public MyFlyByCamera(Camera cam){
      this.cam = cam;
      initialUpVec = cam.getUp().clone();
      }

    /**

    • Sets the up vector that should be used for the camera.
    • @param upVec
      */
      public void setUpVector(Vector3f upVec) {
      initialUpVec.set(upVec);
      }

    public void setCenter(Vector3f center) {
    //Debug.text("----- camera setCenter " + center);
    this.center.set(center);
    }

    public void setMotionAllowedListener(MotionAllowedListener listener){
    this.motionAllowed = listener;
    }

    /**

    • Sets the move speed. The speed is given in world units per second.
    • @param moveSpeed
      */
      public void setMoveSpeed(float moveSpeed){
      this.moveSpeed = moveSpeed;
      }

    /**

    • Gets the move speed. The speed is given in world units per second.
    • @return moveSpeed
      */
      public float getMoveSpeed(){
      return moveSpeed;
      }

    /**

    • Sets the rotation speed.
    • @param rotationSpeed
      */
      public void setRotationSpeed(float rotationSpeed){
      this.rotationSpeed = rotationSpeed;
      }

    /**

    • Gets the move speed. The speed is given in world units per second.
    • @return rotationSpeed
      */
      public float getRotationSpeed(){
      return rotationSpeed;
      }

    /**

    • Sets the zoom speed.
    • @param zoomSpeed
      */
      public void setZoomSpeed(float zoomSpeed) {
      this.zoomSpeed = zoomSpeed;
      }

    /**

    • Gets the zoom speed. The speed is a multiplier to increase/decrease
    • the zoom rate.
    • @return zoomSpeed
      */
      public float getZoomSpeed() {
      return zoomSpeed;
      }

    /**

    • @param enable If false, the camera will ignore input.
      */
      public void setEnabled(boolean enable){
      if (enabled && !enable){
      if ( (inputManager!= null && (!dragToRotate || (dragToRotate && canRotate))) ||
      (inputManager!= null && (!dragToMove || (dragToMove && canMove))) ){
      inputManager.setCursorVisible(true);
      }
      }
      enabled = enable;
      }

    /**

    • @return If enabled
    • @see MyFlyByCamera#setEnabled(boolean)
      */
      public boolean isEnabled(){
      return enabled;
      }

    /**

    • @return If drag to rotate feature is enabled.
    • @see MyFlyByCamera#setDragToRotate(boolean)
      /
      /
      public boolean isDragToRotate() {
      return dragToRotate;
      }*/

    /**

    • Set if drag to rotate mode is enabled.
    • When true, the user must hold the mouse button
    • and drag over the screen to rotate the camera, and the cursor is
    • visible until dragged. Otherwise, the cursor is invisible at all times
    • and holding the mouse button is not needed to rotate the camera.
    • This feature is disabled by default.
    • @param dragToRotate True if drag to rotate mode is enabled.
      */
      /public void setDragToRotate(boolean dragToRotate) {
      this.dragToRotate = dragToRotate;
      if (inputManager != null) {
      //inputManager.setCursorVisible(dragToRotate);
      }
      }
      /

    /**

    • Registers the MyFlyByCamera to receive input events from the provided

    • Dispatcher.

    • @param inputManager
      */
      public void registerWithInput(InputManager inputManager){
      this.inputManager = inputManager;

      // both mouse and button - rotation of cam
      //no idea why this causes an error:
      inputManager.addMapping(“FLYCAM_Left”, new MouseAxisTrigger(MouseInput.AXIS_X, true),
      new KeyTrigger(KeyInput.KEY_LEFT));

      inputManager.addMapping(“FLYCAM_Right”, new MouseAxisTrigger(MouseInput.AXIS_X, false),
      new KeyTrigger(KeyInput.KEY_RIGHT));

      inputManager.addMapping(“FLYCAM_Up”, new MouseAxisTrigger(MouseInput.AXIS_Y, false),
      new KeyTrigger(KeyInput.KEY_UP));

      inputManager.addMapping(“FLYCAM_Down”, new MouseAxisTrigger(MouseInput.AXIS_Y, true),
      new KeyTrigger(KeyInput.KEY_DOWN));

      // mouse only - zoom in/out with wheel, and rotate drag
      inputManager.addMapping(“FLYCAM_ZoomIn”, new MouseAxisTrigger(MouseInput.AXIS_WHEEL, false));
      inputManager.addMapping(“FLYCAM_ZoomOut”, new MouseAxisTrigger(MouseInput.AXIS_WHEEL, true));
      inputManager.addMapping(“FLYCAM_RotateDrag”, new MouseButtonTrigger(MouseInput.BUTTON_RIGHT));
      inputManager.addMapping(“FLYCAM_MoveDrag”, new MouseButtonTrigger(MouseInput.BUTTON_LEFT));

      // keyboard only WASD for movement and WZ for rise/lower height
      inputManager.addMapping(“FLYCAM_StrafeLeft”, new MouseAxisTrigger(MouseInput.AXIS_X, false),
      new KeyTrigger(KeyInput.KEY_A));
      inputManager.addMapping(“FLYCAM_StrafeRight”, new MouseAxisTrigger(MouseInput.AXIS_X, true),
      new KeyTrigger(KeyInput.KEY_D));

      inputManager.addMapping(“FLYCAM_Forward”, new MouseAxisTrigger(MouseInput.AXIS_Y, true),
      new KeyTrigger(KeyInput.KEY_W));
      inputManager.addMapping(“FLYCAM_Backward”, new MouseAxisTrigger(MouseInput.AXIS_Y, false),
      new KeyTrigger(KeyInput.KEY_S));
      inputManager.addMapping(“FLYCAM_Rise”, new KeyTrigger(KeyInput.KEY_Q));
      inputManager.addMapping(“FLYCAM_Lower”, new KeyTrigger(KeyInput.KEY_Z));

      inputManager.addListener(this, mappings);
      //inputManager.setCursorVisible(isEnabled());
      inputManager.setCursorVisible(true);

      Joystick[] joysticks = inputManager.getJoysticks();
      if (joysticks != null && joysticks.length > 0){
      for (Joystick j : joysticks) {
      //mapJoystick(j);
      }
      }
      }

    protected void mapJoystick( Joystick joystick ) {
    /*
    // Map it differently if there are Z axis
    if( joystick.getAxis( JoystickAxis.Z_ROTATION ) != null && joystick.getAxis( JoystickAxis.Z_AXIS ) != null ) {

        // Make the left stick move
        joystick.getXAxis().assignAxis( "FLYCAM_StrafeRight", "FLYCAM_StrafeLeft" );
        joystick.getYAxis().assignAxis( "FLYCAM_Backward", "FLYCAM_Forward" );
       
        // And the right stick control the camera                      
        joystick.getAxis( JoystickAxis.Z_ROTATION ).assignAxis( "FLYCAM_Down", "FLYCAM_Up" );
        joystick.getAxis( JoystickAxis.Z_AXIS ).assignAxis(  "FLYCAM_Right", "FLYCAM_Left" );
    
        // And let the dpad be up and down          
        joystick.getPovYAxis().assignAxis("FLYCAM_Rise", "FLYCAM_Lower");
    
        if( joystick.getButton( "Button 8" ) != null ) {
            // Let the stanard select button be the y invert toggle
            joystick.getButton( "Button 8" ).assignButton( "FLYCAM_InvertY" );
        }                
       
    } else {            
        joystick.getPovXAxis().assignAxis("FLYCAM_StrafeRight", "FLYCAM_StrafeLeft");
        joystick.getPovYAxis().assignAxis("FLYCAM_Forward", "FLYCAM_Backward");
        joystick.getXAxis().assignAxis("FLYCAM_Right", "FLYCAM_Left");
        joystick.getYAxis().assignAxis("FLYCAM_Down", "FLYCAM_Up");
    }  */              
    

    }

    /**

    • Registers the MyFlyByCamera to receive input events from the provided

    • Dispatcher.

    • @param inputManager
      */
      public void unregisterInput(){

      if (inputManager == null) {
      return;
      }

      for (String s : mappings) {
      if (inputManager.hasMapping(s)) {
      inputManager.deleteMapping( s );
      }
      }

      inputManager.removeListener(this);
      //inputManager.setCursorVisible(!dragToRotate);
      inputManager.setCursorVisible(true);

      Joystick[] joysticks = inputManager.getJoysticks();
      if (joysticks != null && joysticks.length > 0){
      Joystick joystick = joysticks[0];

       // No way to unassing axis
      

      }
      }

    protected void rotateCamera(float value, Vector3f axis){
    if (dragToRotate){
    if (canRotate){
    // value = -value;
    }else{
    return;
    }

    Matrix3f mat = new Matrix3f();
    mat.fromAngleNormalAxis(rotationSpeed * value, axis);
    
    Vector3f up = cam.getUp();
    Vector3f left = cam.getLeft();
    Vector3f dir = cam.getDirection();
    
    mat.mult(up, up);
    mat.mult(left, left);
    mat.mult(dir, dir);
    
    Quaternion q = new Quaternion();
    q.fromAxes(left, up, dir);
    q.normalizeLocal();
    
    cam.setAxes(q);
            }
    

    }

    protected void zoomCamera(float value){
    // derive fovY value
    float h = cam.getFrustumTop();
    float w = cam.getFrustumRight();
    float aspect = w / h;

    float near = cam.getFrustumNear();
    
    float fovY = FastMath.atan(h / near)
              / (FastMath.DEG_TO_RAD * .5f);
    fovY += value * 0.1f * zoomSpeed;
    
    h = FastMath.tan( fovY * FastMath.DEG_TO_RAD * .5f) * near;
    w = h * aspect;
    
    cam.setFrustumTop(h);
    cam.setFrustumBottom(-h);
    cam.setFrustumLeft(-w);
    cam.setFrustumRight(w);
    

    }

    protected void riseCamera(float value){

    Vector3f vel = new Vector3f(0, value * moveSpeed/50, 0);
    Vector3f pos = cam.getLocation().clone();
    
    if (motionAllowed != null)
        motionAllowed.checkMotionAllowed(pos, vel);
    else
        pos.addLocal(vel);
    
    cam.setLocation(pos);
    

    }

    protected void shiftCamera(float value){
    if(dragToMove){
    if (canMove){
    // value = -value;
    }else{
    return;
    }

    Vector3f vel = new Vector3f(0, 0, value * moveSpeed);
    Vector3f pos = cam.getLocation().clone();
    
    if (motionAllowed != null)
        motionAllowed.checkMotionAllowed(pos, vel);
    else
        pos.addLocal(vel);
    
    cam.setLocation(pos);
    }
    

    }

    protected void moveCamera(float value, boolean sideways){

    if(dragToMove){
        if (canMove){
    

// value = -value;
}else{
return;
}

    Vector3f vel = new Vector3f();
    Vector3f pos = cam.getLocation().clone();

    if (sideways){
        //links/rechts
        cam.getLeft(vel);
    }else{
        //nach oben/unten
        cam.getDirection(vel);
    }
    vel.multLocal(value * moveSpeed);

    if (motionAllowed != null)
        motionAllowed.checkMotionAllowed(pos, vel);
    else
        pos.addLocal(vel);

    cam.setLocation(pos);
    }
}

public void update(final float tpf) {
        
        
    cam.lookAt(center, new Vector3f(0,1,0));
}

public void onAnalog(String name, float value, float tpf) {
    if (!enabled)
        return;

    if (name.equals("FLYCAM_Left")){
        rotateCamera(value, initialUpVec);
    }else if (name.equals("FLYCAM_Right")){
        rotateCamera(-value, initialUpVec);
    }else if (name.equals("FLYCAM_Up")){
        rotateCamera(-value * (invertY ? -1 : 1), cam.getLeft());
    }else if (name.equals("FLYCAM_Down")){
        rotateCamera(value * (invertY ? -1 : 1), cam.getLeft());
    }else if (name.equals("FLYCAM_Forward")){
        shiftCamera(-value); //moveCamera(value, false);
    }else if (name.equals("FLYCAM_Backward")){
        shiftCamera(value); //moveCamera(-value, false);
    }else if (name.equals("FLYCAM_StrafeLeft")){
        moveCamera(value, true);
    }else if (name.equals("FLYCAM_StrafeRight")){
        moveCamera(-value, true);
    }else if (name.equals("FLYCAM_Rise")){
        riseCamera(value);
    }else if (name.equals("FLYCAM_Lower")){
        riseCamera(-value);
    }else if (name.equals("FLYCAM_ZoomIn")){
        riseCamera(value); //zoomCamera(value);
    }else if (name.equals("FLYCAM_ZoomOut")){
        riseCamera(-value); //zoomCamera(-value);
    }
}

public void onAction(String name, boolean value, float tpf) {
    Debug.text("----- action? " + name + "-----"+value+ " "+tpf);

    if (!enabled)
        return;

     // Convert screen click to 3d position
    /*Vector2f click2d = inputManager.getCursorPosition();
    Vector3f click3d = cam.getWorldCoordinates(new Vector2f(click2d.x, click2d.y), 0f).clone();
    Vector3f dir = cam.getWorldCoordinates(new Vector2f(click2d.x, click2d.y), 1f).subtractLocal(click3d).normalizeLocal();
    // 1. Reset results list.
    CollisionResults results = new CollisionResults();
    // 2. Aim the ray from cam loc to cam direction.
    //Ray ray = new Ray(cam.getLocation(), cam.getDirection());
    // Aim the ray from the clicked spot forwards.
    Ray ray = new Ray(click3d, dir);

    // 3. Collect intersections between Ray and Shootables in results list.
    shootables.collideWith(ray, results);
     // 4. Print the results
    Debug.text("----- Collisions? " + results.size() + "-----");
    for (int i = 0; i < results.size(); i++) {
      // For each hit, we know distance, impact point, name of geometry.
      float dist = results.getCollision(i).getDistance();
      Vector3f pt = results.getCollision(i).getContactPoint();
      String hit = results.getCollision(i).getGeometry().getName();
      Debug.text("* Collision #" + i);
      Debug.text("  You shot " + hit + " at " + pt + ", " + dist + " wu away.");
      
    }*/

    
    if (name.equals("FLYCAM_RotateDrag")){
        canRotate = value;
        //macht cursor unsichtbar: dadurch kann auch usserhalb des fensters gedragged werden
        inputManager.setCursorVisible(!value);
        dragToRotate = true;
        dragToMove=false;
    } else if (name.equals("FLYCAM_MoveDrag")) {
        canMove = value;
        inputManager.setCursorVisible(!value);
        dragToMove = true;
        dragToRotate=false;
        //moveCamera(1, true);
    } else if (name.equals("FLYCAM_InvertY")) {
        // Toggle on the up.
        if( !value ) {  
            invertY = !invertY;
        }
    }       
}

}

[/java]

So where in there do you try to set the initial camera position?

Also, an aside… it looks like you go through a lot of effort to avoid http://hub.jmonkeyengine.org/javadoc/com/jme3/math/Quaternion.html#fromAngleNormalAxis(float,%20com.jme3.math.Vector3f)

…is there a reason?

I didn’t look at your code, but are you aware of this?

http://hub.jmonkeyengine.org/forum/topic/rts-camera-control/

On my main init I found a solution now:
to set the cam before I init the MyFlyByCam, is a bit strange but seems to work.
Maybe I have to write something I can set Location and lookAt directly for MyFlyByCam.
[java]
public void simpleInitApp() {

    flyCam.setEnabled(false);
    cam.lookAt(new Vector3f(0,-5,0),new Vector3f(0,1,0));
    cam.setLocation(new Vector3f(9,8,27));

    final MyFlyByCamera myCam = new MyFlyByCamera(cam);
    myCam.registerWithInput(inputManager);
    myCam.setCenter(new Vector3f(0,0.5f,0));

[/java]

Thanx on the quaternion-hint.
It was something from JME2 times I have moved to JME3.

Thank you Wesley for the RTS Camera-thread, I will have to check.
:slight_smile:

You might find this helpful:
https://wiki.jmonkeyengine.org/legacy/doku.php/jme3:intermediate:simpleapplication

Then scroll down to:
“Defaults and Customization”

To see how to remove the existing fly cam from your app and avoid fighting with it. Then you should be able to set the initial camera position wherever you want… like in the constructor of MyFlyByCamera if you like.

I don’t really understand what the original problem was, though.