Third person camera, how to stop it swaying?

Started by
3 comments, last by DanielDoyle 12 years, 10 months ago
Hi (reposting here as it seems more suitable because its a math based problem)
As the topic title says, im having a problem with a third person camera swaying behind the object it is following when the object moves (sways left and right on axis when moving left or right, completly buggers up when the object goes up or down.
At the moment all the camera does it, follow an object that is passed to it via an offset also passed (from constructor or attatchToObject() call) like so:

ThirdPersonCamera::ThirdPersonCamera(AObject* ObjectToFollow, D3DXVECTOR3 offset)
{

attachedObject = ObjectToFollow;

offsetPos = offset;
}


in the cameras update function, i construct a a matrix from the offset and multiply it against the attatchedObjects position matrix (gives me the position to move the camera too, it's lookAt is of course the attatchedObject, but i think the problem is the up vector (the game is 3d (all floating and no gravity etc)) so what im assuming is that the cameras UP vector wants to be the same as the objects, because if the object is upside down, i want the camera to be upside down too.

so i work out the up like so:

void ThirdPersonCamera::updateCamera(LPDIRECT3DDEVICE9 gd3dDevice)
{
//used to update cameras pos
bChanged = true;
PositionData* P = &attachedObject->getPositionData();
PositionData* C = &this->getPositionData();
D3DXMATRIX cM; //offset matrix for the cameras pos

D3DXMatrixIdentity(&cM);

cM._41 = offsetPos.x;
cM._42 = offsetPos.y;
cM._43 = offsetPos.z;

cM = cM * P->PositionMatrix;
//Tried lots of different methods rather than the below bit (all same result)

//calculate the up vector:
// move from cams pos along P's Up vector
D3DXVECTOR3 temp(P->Pos - P->UpPos), p(C->Pos);
D3DXVec3Normalize(&temp, &temp);
temp *= 1.0f;
p += temp;
C->UpPos = p;

C->PositionMatrix = cM;
C->Pos = D3DXVECTOR3(cM._41, cM._42, cM._43);
UpdateVectors©;
PreviousData = *C;
}

The Base class version of updateCamera, Camera::UpdateCamera(LPDIRECT3DDEVICE9 gd3dDevice) gets called in my engines begin scene call (which i dont get access to (in a lib file))
and that builds the view matrix from the cameras vectors.

So, basically what im asking is. am i cocking up somewhere in this bit of code? the base camera class works perfectly, it's just the swaying and iffy up vectors stuff im having problems with here

as another note, if i do
cM = P->PositionMatrix * cM; the camera follow without sitting behind the objects, just facing in z axis, so that works at least
Advertisement
Your code snippet is somewhat confusing me. How is PositionData defined? Why is the up direction stored as a point? And using upper case P for stuff of the targeted object and lower case p for the camera in the same routine doesn't make things more clear, IMHO.

In general one computes a orientation matrix from the forward vector and (as necessary constraint) an up or side vector. This gives a basis, i.e. a couple of 3 direction vectors. Composed to a matrix, the orientation is then multiplied with the position to yield in the local transformation matrix of the camera. In your case this transformation is local to the object to follow. Multiplying it with the local-to-global matrix of the object gives the camera matrix then in global a space. The inverted matrix then gives the view matrix. Is there any reason not to do so in the given use case?
Ah sorry

struct PositionData
{
bool operator ==(const PositionData& rhs)
{
if(this->ForwardPos == rhs.ForwardPos && this->Pos == rhs.Pos && this->RightPos == rhs.RightPos && this->UpPos == rhs.UpPos)
return true;
else
return false;
};
bool operator !=(const PositionData& rhs)
{
if(this->ForwardPos == rhs.ForwardPos && this->Pos == rhs.Pos && this->RightPos == rhs.RightPos && this->UpPos == rhs.UpPos)
return false;
else
return true;
};
PositionData(){D3DXMatrixIdentity(&PositionMatrix); Pos = UpPos = RightPos = ForwardPos = UpVec = RightVec = ForwardVec = D3DXVECTOR3(0,0,0);};
D3DXMATRIX PositionMatrix;
D3DXVECTOR3 Pos, UpPos, RightPos, ForwardPos;
D3DXVECTOR3 UpVec, RightVec, ForwardVec;
};

It's just a basic structure that holds information on verticies, vectors and a position matrix for each object.
UpPos is just a point yes, UpVec is the vector denoting "UP".
and yeah, the lower case p was just to denote "point" i was testing out the method so named it like that for quickness.

and if i'm understanding you correctly, if i invert cM, to get the viewMatrix, i can pass that to the device instead of computing it from
D3DXMatrixLookAtLH(&viewMatrix, &C->Pos, &P->Pos, &C->UpPos); like i do currentl?
Besides all other issues, D3DXMatrixLookAtLH does expect a direction vector as its 4-th argument pUp. If I follow your explanation correctly, C->UpPos cannot be the correct choice because it is a position vector. Instead, C->UpVec should be the correct choice.

I think that none of the UpPos, RightPos, and ForwardPos are needed at all.
ahhh right, i use UpPos because when i did pass a direction vector before it bugged out, but i think ive fixed that code elsewhere now.

And yeah all the pos vectors are not necessary for this camera but it is for the rest of my engine,
my engine's object architecture atm is
AObject //base object class
/ \
AthenaObject Frustum
|
Camera
/ \
ThirdPersonCamera FirstPersonCamera

so any object that is moveable has the base class AObject which has a PositionData variable that holds the information on an object, thats why the camera also has it (will also be needed for a first person camera)

This topic is closed to new replies.

Advertisement