Rotation around object

Hi all,

I have little problem and I need help.



I have my own SimpleCanvasImpl extension with some objects in scene. For move I used FirstPersonHandler (WASD and mouse moving). It looks like this (I missed irelevant code):

public class MyCanvas extends SimpleCanvasImpl {
    private FirstPersonHandler moveHandler;
    private InputHandler input;

    public void simpleSetup() {
        moveHandler = new FirstPersonHandler(cam, 30f, 2f);
        input = moveHandler;
    }

    public void simpleUpdate() {
        rootNode.updateRenderState();
        input.update(tpf);
    }
}



And now my problem. When I press "L" key, I need to change camera direction to one defined scene Spatial and lock view direction on it. So when I press WASD keys or mouse, camera will rotate around that Spatial.

I tried ChaseCamera, but when I do this

chaseCam = new ChaseCamera(cam, selectedObject);
input = chaseCam;


camera location changed (I need only to change direction to selectedObject) and I can't rotate object 360

It sounds like you want something similar to chase camera, but without all its bells and whistles. If I understand you correctly you want:

(1) Camera to rotate about an arbitrary point

(2) Camera to always be focused on that arbitrary point

(3) Only rotate on input from user



You can easily accomplish that with a little planning, and borrowing the spherical coordinate rotation code from the chase camera class. It has everything you need, you just need to simplify. If you get stuck, post what you have and I can help you out.

Thanks for answer!



I began to study ChaseCamera class and I found that provides all what I need EXCEPT one thing - rotation around all axis. First I thought problem is updateIdealAzimuth method, but when I have extended ChaseCamera and override this method I still can't rotate around all axis. Then I found worldUpVec variable, but when I change it, I still can rotate around y axis of 360 degrees only. Around x and z axis I can rotate, but only few degrees   :(

But the worst thing is that I cant find a solution…

I need this:

Spatial location is [1, 1, 1]

Camera location [3, 2, 3] - I want smoothly rotate with camera around Spatial to most far location [-2, -1, -2] and back

Camera location [5, 5, 1] - rotation about Spatial to [-4. -4. 0]





I found lot of tutorial how do something like this, but in all is y coordinate constant during camera movement. But here isn't any coord constant, all are changing.



Is there some class in jme what provide me cyrcle rotation defined by pivot and point locations? Or something else what could help me?



Thanks for answers and sorry for my bad english

I have the same problem as you, and I don't seem to find a real soultion either :frowning:



If you find anything helpfull out, it would be nice if you could post the code/idea, I will do the same

I'll try and post my orbit handler tonight, maybe it's what you need.

Hm I tested a bit around and this is what i came up with.



It's not really working, but i think there might be only a simple mistake I just don't seem to see.

Also it's a quite simple and cheap attempt ^^



public class AdvancedCamera {
   private static AdvancedCamera myself;
   private Camera cam;
   private CameraMode currentmode = CameraMode.Free;

//Rotation Mode Variables
   private float[] RotationAngles = new float[3];
   private Node RotationWorld = new Node("RotationWorld");
   private Node RotationCenter = new Node("RotationCenter");
   private Node RotationCameraPosition = new Node("RotationCameraPosition");
   Quaternion roationquat = new Quaternion();
   private Vector3f WorldUp = new Vector3f(0,1,0);


   public void SetRotationCenter(Vector3f center){
      RotationCenter.setLocalTranslation(center);
      RotationWorld.updateGeometricState(1,true);
      cam.lookAt(RotationCenter.getLocalTranslation(), WorldUp);
   }
   
   public void SetRotationAngles(float pitch,float yaw,float roll){
      RotationAngles[0] = yaw;
      RotationAngles[1] = roll;
      RotationAngles[2] = pitch;
      roationquat.fromAngles(RotationAngles);
      RotationCenter.setLocalRotation(roationquat);
      RotationWorld.updateGeometricState(1,true);
      cam.lookAt(RotationCenter.getLocalTranslation(), WorldUp);
   }
   
   public void SetRotationDistance(float distance){
      RotationCameraPosition.setLocalTranslation(0,distance,0);
      RotationWorld.updateGeometricState(1,true);
      cam.lookAt(RotationCenter.getLocalTranslation(), WorldUp);
   }

}

I tried extend com.jme.math.Ring and here is my result:

public class Cyrcle extends Ring {
   
    private float radius;
    private float position; // starting angle

    public Cyrcle(Vector3f center, Vector3f up, float radius, float angle) {
        this.center = center;
        this.up = up;
        this.radius = radius;
        position = angle;
    }

    public Vector3f getNewPosition (float angle) {
        Vector3f result = new Vector3f();

        float move = position;
        up.cross(Vector3f.UNIT_X, b1);
        if (b1.lengthSquared() < FastMath.FLT_EPSILON) {
            up.cross(Vector3f.UNIT_Y, b1);
        }

        b1.normalizeLocal();
        up.cross(b1, b2);
        result.set(b1).multLocal(radius * FastMath.cos(move)).addLocal(center);
        result.scaleAdd(radius * FastMath.sin(move), b2, result);

        position += angle;
        return result;
    }
}



... and it looks good - getNewLook() method return new camera location based on target location, distance between camera and target, camera up-direction, angle what camera moved and previous camera location.
But I have one more problem with this - if position == 0 then getNewLook() method returns position near target's [0, 0, -z] local coords. And I dont know how found right position angle if I dont want change actual camera location...

Got mine working, without any problems!!



package Engine;

import Interface.Console;

import com.jme.input.FirstPersonHandler;
import com.jme.math.FastMath;
import com.jme.math.Matrix3f;
import com.jme.math.Quaternion;
import com.jme.math.Vector3f;
import com.jme.renderer.Camera;
import com.jme.scene.Controller;
import com.jme.scene.Node;
import com.jme.scene.shape.Box;

public class AdvancedCamera {
   private static AdvancedCamera myself;
   private Camera cam;
   private CameraMode currentmode = CameraMode.Free;

//Rotation Mode Variables
   private float[] RotationAngles = new float[3];
   private Node RotationWorld = new Node("RotationWorld");
   
   public Node getRotationWorld() {
      return RotationWorld;
   }

   private Node RotationCenter = new Node("RotationCenter");
   private Node RotationCameraPosition = new Node("RotationCameraPosition");
   Quaternion roationquat = new Quaternion();
   private Vector3f WorldUp = new Vector3f(0,1,0);
   
   
   private Vector3f FreeLocation = new Vector3f(0,0,0);
   private boolean ignorecollision;

   
   private Quaternion FreeQuaternion = new Quaternion();
   static public enum CameraMode {ThirdPerson,FirstPerson,RotatePoint,Free}   
   
   
   public AdvancedCamera(Camera cam){
      if(myself != null){
         Console.println("Attempting to create second Camera Controller");
         System.exit(100);
      }
      this.cam = cam;
      myself = this;
      RotationWorld.attachChild(RotationCenter);
      RotationCenter.attachChild(RotationCameraPosition);
      Box center = new Box("CenterTestBox",new Vector3f(0,0,0),1,2,1);
      RotationCenter.attachChild(center);
      RotationCenter.updateRenderState();
      
      Box cambox = new Box("CamTestBox",new Vector3f(0,0,0),1,1,2);
      //RotationCameraPosition.attachChild(cambox);
      RotationCameraPosition.updateRenderState();
      
      Quaternion lookatcenterrotation = new Quaternion();
      lookatcenterrotation.fromAngles(FastMath.HALF_PI,FastMath.HALF_PI,0);
      RotationCameraPosition.setLocalRotation(lookatcenterrotation);
      
      
      
      RotationCameraPosition.addController(new Controller(){
         private static final long serialVersionUID = 1L;
         Vector3f axis = new Vector3f(0,1,0);
         float anglep = 0 ;
         float angley = 0 ;
         
         private Matrix3f rotQuat = new Matrix3f();
         @Override
         public void update(float time) {
            anglep =  anglep + 0.02f;
               if (anglep > FastMath.PI) {
                  anglep = - FastMath.PI;
               }
               angley =  angley + 0.02f;
               if (angley > FastMath.PI) {
                  angley = - FastMath.PI;
               }
               SetRotationAngles(anglep,0,angley);
         }
      });
   }
   
   //Rotation Code
   public void SetRotationCenter(Vector3f center){
      Console.println("Rotation Center now at " + center);
      RotationCenter.setLocalTranslation(center);
   }
   
   public void SetRotationAngles(float pitch,float yaw,float roll){
      RotationAngles[0] = yaw;
      RotationAngles[1] = roll;
      RotationAngles[2] = pitch;
      roationquat.fromAngles(RotationAngles);
      RotationCenter.setLocalRotation(roationquat);
      Console.println("Rotation now at " + pitch + " " + yaw + " " + roll);
      Console.println("Rotation now at " + roationquat);
   }
   
   public void SetRotationDistance(float distance){
      RotationCameraPosition.setLocalTranslation(0,distance,0);
      
      Console.println("Rotation Distane now at " + RotationCameraPosition.getLocalTranslation());
   }

   public Vector3f GetRotationCenter() {
      return RotationCenter.getLocalTranslation();
   }

   // Freecam mode
   
   public Vector3f getFreeLocation() {
      return FreeLocation;
   }

   public void setFreeLocation(Vector3f freeLocation) {
      FreeLocation = freeLocation;
   }

   public Quaternion getFreeQuaternion() {
      return FreeQuaternion;
   }

   public void setFreeQuaternion(Quaternion freeQuaternion) {
      FreeQuaternion = freeQuaternion;
   }
   
   
   public static AdvancedCamera Get(){
      return myself;
   }
   
   public void SetMode(CameraMode mode){
      Console.println("Changing CameraMode to " + mode.name());
      currentmode = mode;
      
   }
   
   public void Update(){
      switch(currentmode){
         case Free :{
            cam.setLocation(FreeLocation);
            cam.setAxes(FreeQuaternion);
            break;
         }
         case RotatePoint :{
            RotationWorld.updateGeometricState(1,true);
            Vector3f worldvec = new Vector3f(0,1,0);
            //RotationCameraPosition.lookAt(RotationCenter.getWorldTranslation(),worldvec);
            cam.setFrame(RotationCameraPosition.getWorldTranslation(),RotationCameraPosition.getWorldRotation());
         //   System.out.println(RotationCameraPosition.getWorldTranslation());
            break;
         }
      }
   }


      

}

Example Video

Nice job!

For completeness, I posted my orbit camera handler over here for those who want to check it out.