Camera system

The XYZ axis coordinate system you normally use to position objects in a scene.

Ah, ok thanks.

So… would this do the trick?


public static Vector3f getCameraPos(Vector3f currCameraPos, Vector3f targetPos, float r) {
   //1) Get the angles between cameraPos and targetPos.
   float theta = 0;
   float phi = 0;
   
   //2) Use spherical coordinates to get the new camera position.
   float x = r * FastMath.cos(theta) * FastMath.sin(phi);
   float y = r * FastMath.sin(theta) * FastMath.sin(phi);
   float z = r * FastMath.cos(phi);

   return sphericalToCartesian( new Vector3f(x,y,z), new Vector3f() );
}


public static Vector3f sphericalToCartesian(Vector3f sphereCoords, Vector3f store) {
   store.y = sphereCoords.x * FastMath.sin(sphereCoords.z);
   
   float a = sphereCoords.x * FastMath.cos(sphereCoords.z);
   store.x = a * FastMath.cos(sphereCoords.y);
   store.z = a * FastMath.sin(sphereCoords.y);
   
   return store;
}



That is, if I knew how to get the angles ofcourse...

Hmm, it looks like your #2 is already converting cartesian to spherical?



In my code I have a vector representing the ideal postion of the camera in spherical terms. I alter that position based on mouse input and then convert it to cartesian and apply velocities, etc. to determine final camera position. To get the camera to look at the target I take cross products of Y-up and the direction to find left, then the direction and left to find up.

First of all, thanks for all the great replies.


Hmm, it looks like your #2 is already converting cartesian to spherical?


I don't know.. I thought your cartesianToSpherical just converted from the direction of the axis in the picture above to the axis used in jME. In that case, no, mine do not do any conversion. I got the formulas from http://mathworld.wolfram.com/SphericalCoordinates.html

I alter that position based on mouse input and then convert it to cartesian and apply velocities, etc. to determine final camera position.

I was also planning on using mouse input to alter the camera position. My plan was to let the mousemovement alter the angles shown in the above picture. I'm probably not going to do anything other than that, since camera velocity and such would make it hard to aim with the camera (would be like mouse smoothing).

To get the camera to look at the target I take cross products of Y-up and the direction to find left, then the direction and left to find up.

Huh..? I don't get it :)

How would I find those angles between the "old" camera pos and the center of the target?

I probably should just add/post my ThirdPersonController and SimpleChaseCamera rather than reproduce all that code here. hehe :slight_smile:



Let me ask the other Dirt programmer what he thinks first.

that would be great :smiley:

Maybe theres no need for you to post it though. If only I got those angles the method I posted above might would do the trick.

Ok, well basically you just need to determine the offset between the two positions (by subtracting one from the other.) That will give you enough information to have lengths of 2 sides of a triangle along any given plane. Then use trig to solve for the angles. How you do that in the code will depend on which angle you are looking for and so forth.

Ok, the method I posted above locates the camera at a location in the sphere. What it doesn’t do is to make the camera look at the target.



A small code snipplet showing what you tried to explain here:

To get the camera to look at the target I take cross products of Y-up and the direction to find left, then the direction and left to find up.


would be nice :D

ah, sorry.


    Vector 3f dirVec = new Vector3f();
    dirVec.set(targetPos).subtractLocal(camPos).normalizeLocal();

    Vector3f upVec = new Vector3f(0,1,0);
    leftVec = upVec.cross(dirVec).normalizeLocal();
    upVec = dirVec.cross(leftVec).normalizeLocal();

    camera.setAxes(leftVec, upVec, dirVec);
    camera.onFrameChange();



(camPos and targetPos are Vector3fs)

That's not optimized for object creation and so forth, but should do the trick.

Thanks, but it didn’t work :frowning:



So far, this is what I’ve managed to do:



in init i do:

theta = 100;
phi = 100;

camNode = new CameraNode("Camera Node", cam);
camNode.setLocalTranslation(map.getSpawnPoint());
camNode.updateWorldData(0);

player.node.attachChild(camNode);

// Configure input       
KeyBindingManager.getKeyBindingManager().set(
        "theta",
        KeyInput.KEY_O);

KeyBindingManager.getKeyBindingManager().set(
        "phi",
        KeyInput.KEY_P);



And in update I have:

if (KeyBindingManager.getKeyBindingManager().isValidCommand("theta",true)) {
   theta += 0.01;
   if (theta >= 360) {
      theta = 0;
   }
   else if (theta < 0) {
      theta = 359;
   }
}

if (KeyBindingManager.getKeyBindingManager().isValidCommand("phi",true)) {
   phi += 0.01;
   if (phi >= 360) {
      phi = 0;
   }
   else if (phi < 0) {
      phi = 359;
   }
}

System.out.println("theta : " + theta);
System.out.println("phi : " + phi);
   
camNode.setLocalTranslation( getCameraTranslation(
      camNode.getLocalTranslation(),
      player.node.getLocalTranslation(), 50F) );



public Vector3f getCameraTranslation(Vector3f currCameraPos, Vector3f targetPos, float r) {
   //1) Use spherical coordinates to get the new camera position.
   float x = r * FastMath.cos(theta) * FastMath.sin(phi);
   float y = r * FastMath.sin(theta) * FastMath.sin(phi);
   float z = r * FastMath.cos(phi);

   //2) Make camera look at the target.
    Vector3f dirVec = new Vector3f();
    dirVec.set(targetPos).subtractLocal(currCameraPos).normalizeLocal();

    Vector3f upVec = new Vector3f(0,1,0);
    Vector3f leftVec = upVec.cross(dirVec).normalizeLocal();
    upVec = dirVec.cross(leftVec).normalizeLocal();

    cam.setAxes(leftVec, upVec, dirVec);
    cam.onFrameChange();
   
    //cam.lookAt(player.node.getLocalTranslation());
   
   //return sphericalToCartesian( new Vector3f(x,y,z), new Vector3f() );
   return new Vector3f(x,y,z);
}



It works except it doesn't look at the target. If I use your code nothing seems to happen. But if I use cam.lookAt() it cind of works, allthough the player seems to be invisible in most angles.

By the way I'm extending SimpleGame.

Hmm, the problem is that you are using a camera node, which overrides the camera.setFrame() Try using Camera without the node. It’s not necessary anyhow since you are controlling the camera this other way now.

Okey, thank you very much, got it working.



If anyone is interested this is how I did:



init:

theta = 100;
phi = 100;
     
KeyBindingManager.getKeyBindingManager().set("increaseTheta", KeyInput.KEY_O);

KeyBindingManager.getKeyBindingManager().set("increasePhi", KeyInput.KEY_P);



update:

if (KeyBindingManager.getKeyBindingManager().isValidCommand("increaseTheta",true)) {
   theta += 0.05;
   if (theta >= 360) {
      theta = 0;
   }
   else if (theta < 0) {
      theta = 359;
   }
}

if (KeyBindingManager.getKeyBindingManager().isValidCommand("increasePhi",true)) {
   phi += 0.05;
   if (phi >= 360) {
      phi = 0;
   }
   else if (phi < 0) {
      phi = 359;
   }
}
   
updateCamera(50);



updateCamera:

/**
 * Sets the new camera position and direction.
 * @param r The distance between the camera and the target.
 */
public void updateCamera(float r) {      
   Vector3f currCameraPos = cam.getLocation();
   Vector3f targetPos = player.node.getLocalTranslation();
   
   //1) Use spherical coordinates to set the new camera position.
   float x = r * FastMath.cos(theta) * FastMath.sin(phi);
   float y = r * FastMath.sin(theta) * FastMath.sin(phi);
   float z = r * FastMath.cos(phi);
   
   cam.setLocation( targetPos.add(new Vector3f(x,y,z)) );

   //2) Make camera look at the target.
    Vector3f dirVec = new Vector3f();
    dirVec.set(targetPos).subtractLocal(currCameraPos).normalizeLocal();

    Vector3f upVec = new Vector3f(0,1,0);
    Vector3f leftVec = upVec.cross(dirVec).normalizeLocal();
    upVec = dirVec.cross(leftVec).normalizeLocal();

    cam.setAxes(leftVec, upVec, dirVec);
    cam.onFrameChange();
   
    //cam.lookAt(player.node.getLocalTranslation());
}