Rotating camera around player origin

Started by
7 comments, last by JohnnyCode 11 years, 11 months ago
I can't quite figure out current how to Transform the lookAt and up vector by the rotation matrix so the view is rotated about the player origin.

Cheers


up.x = 0.0f;
up.y = 1.0f;
up.z = 0.0f;
// Set the yaw (Y axis), pitch (X axis), and roll (Z axis) rotations in radians.
pitch = m_rotationX * 0.0174532925f;
yaw = m_rotationY * 0.0174532925f;
roll = m_rotationZ * 0.0174532925f;
D3DXVECTOR3 rotation = D3DXVECTOR3(m_rotationX, m_rotationY, m_rotationZ);
D3DXVECTOR3 camera[3] = { D3DXVECTOR3(m_fCameraX, m_fCameraY, m_fCameraZ),//Eye
D3DXVECTOR3(m_fLookatX, m_fLookatY, m_fLookatZ),//LookAt
up };//Up
// Create the rotation matrix from the yaw, pitch, and roll values.
D3DXMatrixRotationYawPitchRoll(&rotationMatrix, yaw, pitch, roll);
//Translate in the direction of player rotation
D3DXVec3TransformCoord(&camera[0], &camera[0], &rotationMatrix);
// Transform the lookAt and up vector by the rotation matrix so the view is correctly rotated at the origin.
D3DXVec3TransformCoord(&camera[1], &camera[1], &rotationMatrix);
D3DXVec3TransformCoord(&camera[2], &camera[2], &rotationMatrix);
camera[1] = camera[0] + camera[1];
D3DXMatrixLookAtLH(&in_viewMatrix, &camera[0], &camera[1], &camera[2]);
Advertisement
Do you need a 3rd person camera rotating around the player?

If so, I recommend you to use quaternions. It's much easier.

If not, can you describe what you want more clearly?

Btw, I don't recommend you to deal with LookAt and Eye vectors. You can define a world transform for your camera because it's quite easy to perform some transformations (translate, rotate etc.) over a world matrix. And when you need a view matrix, just take the inverse of this world matrix.
There's no "hard", and "the impossible" takes just a little time.
Thanks for the reply!

I'm trying to implement an FPS-style camera. I am able to move on a set axis, and rotate about the local camera origin, but I cannot update the movement direction in relation to the camera facing angle. So what I want to achieve, is look in a direction and translate in that direction.

Here is my revised code I've been working on.


float yaw, pitch, roll;
//D3DXMATRIX rotationMatrix;
D3DXMATRIX yawMatrix;
D3DXMATRIX pitchMatrix;
D3DXMATRIX rollMatrix;
D3DXMATRIX upLocal;
D3DXVECTOR3 Direction;
// Set the yaw (Y axis), pitch (X axis), and roll (Z axis) rotations in radians.
pitch = m_rotationX * 0.0174532925f;
yaw = m_rotationY * 0.0174532925f;
roll = m_rotationZ * 0.0174532925f;
position.x = m_fCameraX;
position.y = m_fCameraY;
position.z = m_fCameraZ;
up = D3DXVECTOR3(0.0f, 1.0f, 0.0f);//Create the up vector
right = D3DXVECTOR3(1.0f, 0.0f, 0.0f);
lookat = D3DXVECTOR3(0.0f, 0.0f, 1.0f);
rotation = D3DXVECTOR3(m_rotationX, m_rotationY, m_rotationZ);
// Setup matrices to rotate around axes
D3DXMatrixRotationAxis(&yawMatrix, &up, yaw);
D3DXMatrixRotationAxis(&pitchMatrix, &right, pitch);
//D3DXMatrixRotationAxis(&rollMatrix, &lookat, roll);
//move lookat vector
D3DXVec3TransformCoord(&lookat, &lookat, &pitchMatrix);
D3DXVec3TransformCoord(&lookat, &lookat, &yawMatrix);
D3DXVec3Normalize(&lookat, &lookat);
//Get the direction vector from camera to target, normalise it.
D3DXVec3Normalize(&Direction, &(lookat - right));
//Get the UP vector (in the world) and determine the cross product, to give us our right (left) hand vector.
D3DXVec3Cross(&right, &up, &lookat);
D3DXVec3Normalize(&right, &right);
//Cross product the right vector and direction vector, to determine up relative to the camera.
D3DXVec3Cross(&up, &lookat, &right);//Should be direction instead of lookat
//lookat = Direction + right;//Avoid gimble locking
D3DXMatrixIdentity(&in_viewMatrix);
in_viewMatrix._11 = right.x;
in_viewMatrix._21 = right.y;
in_viewMatrix._31 = right.z;
in_viewMatrix._12 = up.x;
in_viewMatrix._22 = up.y;
in_viewMatrix._32 = up.z;
in_viewMatrix._13 = lookat.x;
in_viewMatrix._23 =lookat.y;
in_viewMatrix._33 = lookat.z;
in_viewMatrix._41 = -D3DXVec3Dot(&position, &right);
in_viewMatrix._42 = -D3DXVec3Dot(&position, &up);
in_viewMatrix._43 = -D3DXVec3Dot(&position, &lookat);
Update:

So I was aware that I needed to create a direction from the position and rotation, but unsure of the method. Here is the progress I have made with that:


direction = atan2((double)rotation.x, (double)position.x);
velocity.x = (sin(direction) * 5.0f);
velocity.z = (cos(direction ) * 5.0f);

And then I apply the velocity to the right vector as such:

in_viewMatrix._41 = -D3DXVec3Dot(&(position + velocity), &right);


So the final result I am trying to accomplish is create a new position based off of the rotation. It however doesn't accomplish this.
Use parenting so that the player's avatar model is the parent of the camera. Then the camera's world transformation C[sub]W[/sub] is
C[sub]W[/sub] = C[sub]L[/sub] * P[sub]W[/sub]
where C[sub]L[/sub] means the camera's local position and orientation w.r.t. the avatar's model, and P[sub]W[/sub] means the model's position and orientation in the world. Hence, if you alter the model, the camera will follow automatically.

You may want to use variations, e.g. a constant height of the camera above the ground. This can be done by setting the respective component manually.

If you want to change the camera's relation to the model, i.e. C[sub]L[/sub], then use orbiting. In orbiting you rotate both the orientation as well as the position of the camera. That means
C[sub]L[/sub]' = C[sub]L[/sub] * R
perhaps using negated angles when computing R.

It may be that the origin of the model shouldn't be exactly the center of rotation / orbiting, e.g. in the models's head instead of the center of body. In that case you may want to have a distant rotational center O (also relative to the model's space) and hence will do orbiting like so:
C[sub]L[/sub]' = C[sub]L[/sub] * O[sup]-1[/sup] * R * O
Herein O is simply the translation matrix from the model's origin to the center of rotation.

If you want to compute the direction where the model should move, please avoid the use of angles. It is much more convenient and efficient to use the forward vector of the model (or perhaps the camera) instead. You can use a projection of it if you want the movement vector parallel to the ground. You can further apply a small rotation for curved movement.
I always have yaw, pitch, and roll variables, then every frame I update them with the controller or whatever, then I create a quaternion using those variables, then I transform the "backward" vector with that quaternion. Make the camera position that vector (multiply it by whatever distance you want it to be from the player), add the player position to that vector, then set the target to the character position.

It's really not hard to do, and I would provide some sample code, but I'm a little lazy right now :P

Aww, hell, here's some pseudo-code:

float yaw, pitch, roll;//Some variables that will be in your camera class or wherever you want them
//You could also just use a quaternion rather than those variables, then just multiply the quaternions.
//I feel it's a little better to use yaw, pitch, and roll since you can keep track of your camera's rotations a little better (doesn't really matter if it's a free camera anyway)

//I really don't know which is which with yaw pitch roll, but only two are important (I think yaw and pitch, yaw being up/down, pitch being rotation?)
//Anyway, doesn't matter. Just find out which is which, add to them using input from a controller/keyboard, then create your quaternion

Quaternion rotator = Quaternion.FromYawPitchRoll(yaw,pitch,roll);

float camDistance = 5.0f;
vector3 back = Vector3.Backward;

back = Vector3.Transform(back, rotator);//Rotate our vector
rotator *= distance;//Push it out a distance from the player)
rotator += playerPosition;//Add the position

View = Matrix.CreateLookAt(back, playerPosition, upVector);


I always have yaw, pitch, and roll variables, then every frame I update them with the controller or whatever, then I create a quaternion using those variables, then I transform the "backward" vector with that quaternion. Make the camera position that vector (multiply it by whatever distance you want it to be from the player), add the player position to that vector, then set the target to the character position.

It's really not hard to do, and I would provide some sample code, but I'm a little lazy right now tongue.png

Aww, hell, here's some pseudo-code:

float yaw, pitch, roll;//Some variables that will be in your camera class or wherever you want them
//You could also just use a quaternion rather than those variables, then just multiply the quaternions.
//I feel it's a little better to use yaw, pitch, and roll since you can keep track of your camera's rotations a little better (doesn't really matter if it's a free camera anyway)

//I really don't know which is which with yaw pitch roll, but only two are important (I think yaw and pitch, yaw being up/down, pitch being rotation?)
//Anyway, doesn't matter. Just find out which is which, add to them using input from a controller/keyboard, then create your quaternion

Quaternion rotator = Quaternion.FromYawPitchRoll(yaw,pitch,roll);

float camDistance = 5.0f;
vector3 back = Vector3.Backward;

back = Vector3.Transform(back, rotator);//Rotate our vector
rotator *= distance;//Push it out a distance from the player)
rotator += playerPosition;//Add the position

View = Matrix.CreateLookAt(back, playerPosition, upVector);




Thanks for this, really helpful. I have managed to create an orbit and FPS camera, but there is room for improvement, I will factor in this concept.
I solved my problems however, and I created my FPS camera with head bobbing. This is the final code:


bool dxCamera::keyHeldA;
bool dxCamera::keyHeldS;
bool dxCamera::keyHeldW;
bool dxCamera::keyHeldD;
void dxCamera::perspectiveCamera(D3DXMATRIX &in_projectionMatrix, D3D10_VIEWPORT &in_viewPort, D3DXMATRIX &in_worldMatrix,
D3DXMATRIX &in_viewMatrix)
{
float yaw, pitch, roll;
D3DXMATRIX yawMatrix;
D3DXMATRIX pitchMatrix;
D3DXMATRIX rollMatrix;
D3DXMATRIX upLocal;
D3DXVECTOR3 Direction;
D3DXMATRIX directionMatrix;
// Set the yaw (Y axis), pitch (X axis), and roll (Z axis) rotations in radians.
rotation.x = m_rotationX * 0.0174532925f;
rotation.y = m_rotationY * 0.0174532925f;
rotation.z = m_rotationZ * 0.0174532925f;
//rotation.x = pitch;
//rotation.y = yaw;
//rotation.z = roll;
up = D3DXVECTOR3(0.0f, 1.0f, 0.0f);//Create the up vector
right = D3DXVECTOR3(1.0f, 0.0f, 0.0f);
lookat = D3DXVECTOR3(0.0f, 0.0f, 1.0f);
//D3DXVECTOR3 inputMoveVec[2] = {position, rotation};
// Setup matrices to rotate around axes
D3DXMatrixRotationAxis(&yawMatrix, &up, rotation.y);
D3DXMatrixRotationAxis(&pitchMatrix, &right, rotation.x);
//move lookat vector
D3DXVec3TransformCoord(&lookat, &lookat, &pitchMatrix);
D3DXVec3TransformCoord(&lookat, &lookat, &yawMatrix);
D3DXVec3Normalize(&lookat, &lookat);
//Get the direction vector from camera to target, normalise it.
//D3DXVec3Normalize(&Direction, &(lookat - right));
//Get the UP vector (in the world) and determine the cross product, to give us our right (left) hand vector.
D3DXVec3Cross(&right, &up, &lookat);
D3DXVec3Normalize(&right, &right);
//Cross product the right vector and direction vector, to determine up relative to the camera.
D3DXVec3Cross(&up, &lookat, &right);
//Useful for generation of direction looking at for future cameras
direction = atan2((double)lookat.z, (double)lookat.x);
velocity.x = (sin(direction));
velocity.y = 30.0f;
velocity.z = (cos(direction ));
D3DXMatrixIdentity(&in_viewMatrix);
in_viewMatrix._11 = right.x;
in_viewMatrix._21 = right.y;
in_viewMatrix._31 = right.z;
in_viewMatrix._12 = up.x;
in_viewMatrix._22 = up.y;
in_viewMatrix._32 = up.z;
in_viewMatrix._13 = lookat.x;
in_viewMatrix._23 = lookat.y;
in_viewMatrix._33 = lookat.z;
in_viewMatrix._41 = -D3DXVec3Dot(&(position), &right);
in_viewMatrix._42 = -D3DXVec3Dot(&(position), &up);
in_viewMatrix._43 = -D3DXVec3Dot(&(position), &lookat);
D3DXMatrixPerspectiveFovLH(&in_projectionMatrix, (float)D3DX_PI * 0.5f,
(float)in_viewPort.Width/(float)in_viewPort.Height, 0.1f, 5000.0f);
}
void dxCamera::initialiseFPSCamera(float in_headHeight, float in_bobPeriod, float in_bobScale)
{
bobPeriod = in_bobPeriod;
bobScale = in_bobScale;
headHeight = in_headHeight;
}
void dxCamera::walk(float speed, float sin)
{
bob = headHeight + sinf(sin * bobPeriod) * bobScale;
if(keyHeldW == true)
{
position.x += lookat.x * speed;
position.y = bob;
position.z += lookat.z * speed;
}
if(keyHeldS == true)
{
position.x -= lookat.x * speed;
position.y = bob;
position.z -= lookat.z * speed;
}
keyHeldW = false;
keyHeldS = false;
}
void dxCamera::strafe(float speed)
{
if(keyHeldA == true)
{
position -= right * speed;
}
if(keyHeldD == true)
{
position += right * speed;
}
keyHeldA = false;
keyHeldD = false;
}
void dxCamera::translateCamera(float &in_CameraX, float in_CameraY, float in_CameraZ)
{
position.x = in_CameraX;
position.y = in_CameraY;
position.z = in_CameraZ;
}
void dxCamera::rotateCamera(float &in_rotationX, float & in_rotationY, float &in_rotationZ)
{
m_rotationX = in_rotationX;
m_rotationY = in_rotationY;
m_rotationZ = in_rotationZ;
}
I'm glad I was able to help. I wrote all that code from memory, so I'm actually a little surprised that you were able to get it to do what you want.
elegant technique to ratate cemara around point is to first rotate it at the point and then offset camera postion in that direction back. This could also solve your movement direction computation.
1- rotate camera at position: DXLookAt(at,position,up)
2- offset camera in the direction it is looking at : DXLookAt(at,position-normalize(position-at)*length,up)
3- if you want to move in the direction camera is looking , add the normalize(position-at)*length vector to camera position vector, or some other desired position vector. DXLookAt() functions wants vectors in world space, so you can use these vectors to update world space vectors such as positions of objects.

This topic is closed to new replies.

Advertisement