Game Development Community

Problems with changing camera rotation in C

by Robert Geiman · in Torque Game Engine · 12/03/2005 (8:03 am) · 4 replies

I implemented Ben Garney's handy Commander Map resource (www.garagegames.com/index.php?sec=mg&mod=resource&page=view&qid=5277) into my game, and it works great.

However, I'd like to rotate the view of the commander map as the player's view rotates. That is, if the player turns right/left, I'd like the commander map to rotate left/right. This way whatever is showing at the top of the commander map is what is directly in front of the player.

Unfortunately all this vector/matrix math confuses the heck out of me (I really should have paid better attention in Trig/Pre-Calc ;)). I've spent hours and hours pouring over resources/forum posts and I still can't get this to work.

The function in GuiCommanderHud that I believe needs to be changed is below, with the two lines that modify position/rotation of the camera bolded:
bool GuiCommanderHud::processCameraQuery(CameraQuery *q)
{
   // Scale ranges based on the highest/lowest point in the terrain
   F32 maxHi = gClientSceneGraph->getCurrentTerrain()->findSquare(8, 0,0)->maxHeight / 10;
   F32 minHi = gClientSceneGraph->getCurrentTerrain()->findSquare(8, 0,0)->minHeight / 10;

   q->object = NULL;
   q->nearPlane = 1;
   q->farPlane  = mFabs(maxHi) + mFabs(minHi);
   q->fov       = mCurZoom;

   // Make us high up, facing straight down.
   [b]q->cameraMatrix = MatrixF(EulerF(3.14/2, 0, 0.5)); // rotate us to look straight down
   q->cameraMatrix.setPosition(Point3F(mCurPan.x,mCurPan.y, maxHi + 100)); // and high enough we won't clip[/b]

   return true;
}

I'm going to make changes to this class to allow the user to pass the player object from script to the GuiCommanderHud, and store in a member variable called 'mPlayerObject' of type GameBase.

So, assuming the player object is stored in mPlayerObject, how can I change those two bolded lines above to not only point the camera down, but also rotate the camera based on the direction the player is facing?

Any help is GREATLY appreciated!

#1
12/03/2005 (8:17 am)
The simplest way is going to be manipulating the params to EulerF().

Right now you have EulerF(PI/2, 0, 0.5). If you are looking straight down then changing EITHER your ROLL or your YAW is going to have the effect of rotating the camera around - so play with the 2nd and 3rd parms and see what effect you get.

Another way to go is to checkout the RADAR resources that are out there. The radar resource does exactly what you want in terms of rotation. It also shows how to find out the rotation of the "control object" which would be the player - so you probly dont have to have a mPlayerObject field like you think.
#2
12/03/2005 (8:24 am)
Oops, those two bolded lines SHOULD have read:
q->cameraMatrix = MatrixF(EulerF(3.14/2, 0, 0)); // rotate us to look straigh
t down
q->cameraMatrix.setPosition(Point3F(mCurPan.x,mCurPan.y, maxHi + 100)); // and hig
h enough we won't clip
Notice the first line the EulerF params are 3.14/2, 0, and 0 (not 0.5). The 0.5 came from my tweaking trying to figure out how to rotate the camera.

The problem is, if I put values (such as 0.5) in either the second OR third param, they tend to do the same thing, which is turn the camera so I'm no longer looking straight down. Either I'm looking up at another section of my map or I'm staring at the sky.

Thanks for the tip about the various radar resources out there! I'll start going through those to see what I can figure out.

If anyone else who has ideas/tips, please let me know!
#3
12/03/2005 (10:32 am)
Ok, even looking at the radar resources, I'm still having troubles. However, thanks to your suggestion, Paul, I'm now using the control object rather than having the user pass the player object from script. So now my function looks like this (changes in bold):

bool GuiCommanderHud::processCameraQuery(CameraQuery *q)
{
   // Other setup code
   ...

   [b]GameConnection* conn;
   conn = GameConnection::getConnectionToServer();
   if (!conn)
      return false;

   // Get the camera matrix for the player
   MatrixF playercam;
   conn->getControlCameraTransform(0, &playercam);[/b]

   // Make us high up, facing straight down.
   q->cameraMatrix = MatrixF(EulerF(3.14/2, 0, 0)); // rotate us to look straight down
   q->cameraMatrix.setPosition(Point3F(mCurPan.x,mCurPan.y, maxHi + 100)); // and high enough we won't clip

   return true;
}
So at this point I have the player camera matrix, and just need to transfer part of the rotation to the commander map camera. I tried doing something like this (changes in bold):
// Other setup code
   ...

   GameConnection* conn;
   conn = GameConnection::getConnectionToServer();
   if (!conn)
      return false;

   // Get the camera matrix for the player
   MatrixF playercam;
   conn->getControlCameraTransform(0, &playercam);

   [b]Point3F rotation;
   playercam.getColumn(1, &rotation);[/b]

   // Make us high up, facing straight down.
   q->cameraMatrix = MatrixF(EulerF(3.14/2, [b]rotation.y[/b], 0)); // rotate us to look straight down
   q->cameraMatrix.setPosition(Point3F(mCurPan.x,mCurPan.y, maxHi + 100)); // and high enough we won't clip

But that's most definately not working. What it does is rotate the command map camera left or right. So if I have my player turn in a complete circle, the commander map camera will turn to show the ground, then sky, then complete the circle to show the ground again.

What I really want is to just keep the camera pointed at the ground, but spin it like a top. I tried instead passing rotation.x but that does the same thing as rotation.z. I even tried passing those params as the THIRD parameter of the EulerF constructor, but again, the camera does the same thing.
#4
12/03/2005 (8:31 pm)
Ok, I finally figured it out. I thought I'd post the code in case anyone was intersted in the solution.

bool GuiCommanderHud::processCameraQuery(CameraQuery *q)
{
   // Scale ranges based on the highest/lowest point in the terrain
   F32 maxHi = gClientSceneGraph->getCurrentTerrain()->findSquare(8, 0,0)->maxHeight / 10;
   F32 minHi = gClientSceneGraph->getCurrentTerrain()->findSquare(8, 0,0)->minHeight / 10;

   q->object = NULL;
   q->nearPlane = 1;
   q->farPlane  = mFabs(maxHi) + mFabs(minHi);
   q->fov       = mCurZoom;

   GameConnection* conn;
   conn = GameConnection::getConnectionToServer();
   if (!conn)
      return false;

   MatrixF playercam, mat1, mat2;
   conn->getControlCameraTransform(0, &playercam); // store camera information

   // Get camera angle
   AngAxisF aa(playercam);
   aa.axis.x = 0.0f;
   aa.axis.y = 0.0f;
   aa.setMatrix(&mat1);

   // Create angle to look straight down
   aa.axis.x = 1.0f;
   aa.axis.y = 0.0f;
   aa.axis.z = 0.0f;
   aa.angle = 3.14/2;
   aa.setMatrix(&mat2);

   // Combine the camera angles
   mat1.mul(mat2);

   // Make sure we're high enough that we we won't clip
   mat1.setColumn(3, Point3F(mCurPan.x, mCurPan.y, maxHi + 100));
   q->cameraMatrix = mat1;

   return true;
}