Camera Issues

I was playing with initializing the camera for my terrain utility this weekend, and ran into some problems. By ‘initialize’ I mean get it in a good starting location and setting it up so it behaves intelligently.



You’ll have to forgive me, I don’t have my code here, so this is from memory…



I’m using the FirstPersonHandler to get standard keyboard and mouse support… that works fine, normally.



I can place the starting location of the camera just fine, too… off to one corner of the terrain. My issues come from setting the direction the camera is facing so it’s looking at the center of the terrain.



A few issues:



If I call ‘setDirection’ on the camera and point it at (0,0,0), the camera will point correctly, but my mouse movement is all funky. It will rotate to the left and right, which is not normal for a FPS. (If I don’t do the setDirection, everything is fine) I thought this might have something to do with locking the axis, but I don’t see how to do that… Plus, it was already done once by the FirstPersonHandler. It seems like it’s getting overwritten.



Is that normal behavior, or do I need to do this a different way?



I also tried using ‘lookAt’. That will point me in the right direction as well, but with worse control problems. I can’t recall exactly what it was doing, but I think I couldn’t move back and forth any more, and the camera would only spin clockwise/counterclockwise… no other movement would work. Also, if I do that… until I move the mouse slightly, the view is black. Ie, it’s not painting itself initially or something… just after I move it.



So… how do I do this? I just want the user to be looking toward a specific point without altering how the user controls the camera in any way. I’m sure I will want to do this in games as well, where performance is much more of an issue.



Any guidance?





–K

ummm, all my "demos/games" have had a cameraNode which you can just set the localRotation of it and the camera follows.



Its quite neat really:



CameraNode camNode;

private void initCamera() {
  camNode = new CameraNode("Camera Node", cam);
  Quaternion q = new Quaternion();
  float angle = 20;
  angle -= 90;
  angle *= -1 * FastMath.DEG_TO_RAD;
  q.fromAngleAxis(angle, new Vector3f(0, 1, 0));
  camNode.setLocalRotation(q);
}



that code should do it, hopefully I haven't mispelled anything.

DP

Ahhhh…



So basically, you wrap the camera in a CameraNode object, then manipulate the node instead of modifying the ‘Camera’ object directly.



Okay… I’ll play with that next chance I get.



Thanks, DP!





–K

While, I do recommend using a CameraNode for all your camera needs, it should still work as you described. Could you post your camera creation code?

Could you post your camera creation code?


Next chance I get.

I've already switched things over to use a CameraNode, and that seems to work. I think I left the old code commented out in my own.. so I should be able to reproduce it here.

One thing that would be nice to have (and maybe it does.. I just didn't see it?) would be a 'lookAt' method for the CameraNode.. so you can have your camera look to a specific point.. Or, maybe another 'look at' method that would allow it to point at a specific object:


/**
  *  Causes the camera node to rotate so the camera plane
  *  is facing the given point.
  */
CameraNode.lookAt(Vector3f point);

/**
  *  Causes the camera node to rotate so the camera plane
  *  is facing the approximate center of the given node's
  *  location.
  */
CameraNode.lookAt(Node n);



Could possibly add some additional option for a 'speed' that would cause the camera to move gradually from its current position to the new one.

Thoughts on this?


--K

Now your talking about animation which is not in a Camera’s definition. You could create a KeyFrameController to migrate between the positions, and attach that to the cameraNode.



A “lookAt” function can easily be accomplished using your code rather than jME’s core code:



// assuming Z is the dir, and -x is left:
public void lookAt(Vector3f pos) {
  Vector3f target = (Vector3f)pos.clone();

  // obtain the difference in direction
  float z = pos.z - camNode.getLocalTranslation().z;
  float x = pos.x - camNode.getLocalTranslation().x;

  // if the difference in x is not equal to 0, then continue, else,
  if (x != 0) {
    // obtain the angle difference using trig
    float angleInRadians = (float)Math.atan(z/x);

    // if x is less than 0, add 90 to compensate for original rotation
    if (x <= 0) {
      angleInRadians += 90 * FastMath.DEG_TO_RAD;
    } else {
      // else if x > 0, take away 90
      angleInRadians -= 90 * FastMath.DEG_TO_RAD;
    }
    // multiply by -1 because the caestarian coordiantes's x are the opposite of ours
    angleInRadians *= -1;
  }

  // create a new quaternion and apply to node
  Quaternion q1 = new Quaternion();
  q1.fromAngleAxis(angleInRadians, new Vector3f(0, 1, 0));
   
  camNode.setLocalRotation(q1);
}



Now this will rotate the camera to look at the node about the Y axis, you will need a similar calculation (using y instead of z ) to calculate the rotation about the X axis. Then multiply the two quaternions together to obtain a finalQuaternion which you set the camNode rotation to.

If you can't figure this out, tell me and Il post the rest of the code for you. :)

DP

Cool… thanks, DP.



Not to sound like a broken record… but I’ll play with it the next chance I get. :smiley:





–K

"DarkProphet" wrote:
ummm, all my "demos/games" have had a cameraNode which you can just set the localRotation of it and the camera follows.

Its quite neat really:


CameraNode camNode;

private void initCamera() {
  camNode = new CameraNode("Camera Node", cam);
  Quaternion q = new Quaternion();
  float angle = 20;
  angle -= 90;
  angle *= -1 * FastMath.DEG_TO_RAD;
  q.fromAngleAxis(angle, new Vector3f(0, 1, 0));
  camNode.setLocalRotation(q);
}



that code should do it, hopefully I haven't mispelled anything.

DP

Hi.. it happens to me the same crazy-camera if a use cam.setDirection.
I copy/paste the code above but it does absolutly nothing! even if i change any of the values!

I posted about this on a different thread and now can’t seem to find it. The direction, left and up vectors define the make up of the camera. They all have to be 90 degrees off each other. So, if you just change a single value (direction) you are going to get very strange results. That is, your direction vector is changing but your up and left are the original values.



so you need to also set the left and up to reflect the change in the direction. Cep21 did this. You must take the cross product and normalize. It was in a thread discussing lookAt.

"mojomonk" wrote:
I posted about this on a different thread and now can't seem to find it. The direction, left and up vectors define the make up of the camera. They all have to be 90 degrees off each other. So, if you just change a single value (direction) you are going to get very strange results. That is, your direction vector is changing but your up and left are the original values.

so you need to also set the left and up to reflect the change in the direction. Cep21 did this. You must take the cross product and normalize. It was in a thread discussing lookAt.

sorry, but i dont get the up or left thing. What are needed for an up and left vectors? The camera direction isnt one? I see the 90º need between xyz but not the other :?

Is some code in the jmetests?

A camera needs three vectors to define the orientation of the camera. Simply it’s coordinate system in relation to the scene. These vectors are the direction it is facing, the left facing of the camera and the up facing of the camera. This will define not only where the camera is looking (direction) but how it is oriented (up and left). This must be 90 degrees of each other for the frame calculations and culling calculations to be correct. so if you change one you must change the other two. i.e. left = up cross direction. etc.



This is why it’s not advisable to set these axes directly, but to use rotations and translations.