• Advertisement
Sign in to follow this  

Crazy Camera Happenings When Pointing Straight Down

This topic is 4616 days old which is more than the 365 day threshold we allow for new replies. Please post a new topic.

If you intended to correct an error in the post then please contact us.

Recommended Posts

First to qualify I am using C++ and Direct3D 9c. Ok, so If I have a grid of tiles at height zero stretching from 0,0 to 64,64 and then have my camera looking directly down (target{32,0,32}, source{32,128,32}), for some reason it renders nothing. If I shift the camera source slightly (ie target{32,0,32}, source{32,128,31}) it renders. Why does it not render when pointing directly down? I am using the source and target to setup the view matrix using... // set view transform D3DXVECTOR3 vUp(0.0f, 1.0f, 0.0f); D3DXMatrixLookAtLH(&matView, &vSource, &vTarget, &vUp); if (FAILED(InDevice.SetTransform(D3DTS_VIEW, &matView))) return FALSE; Thanks PS, also how do I mark code to show in the window properly?

Share this post


Link to post
Share on other sites
Advertisement
You're forward vector is parallel to your world up vector, which is a problem. The purpose of the world up vector is to select a camera up vector of the correct orientation. Basically, the camera forward vector, up vector, and the world up vector all need to be coplanar. Once you make the forward vector essentially the same as the world up vector, you only really have 2 lines and coplanar becomes no restriction at all; ie. any 2 lines are coplanar if you only have 2 lines (just like there's a straight line between any two points).

Hope I was clear :S.

Share this post


Link to post
Share on other sites
Quote:
Original post by devin_papineau
You're forward vector is parallel to your world up vector, which is a problem. The purpose of the world up vector is to select a camera up vector of the correct orientation. Basically, the camera forward vector, up vector, and the world up vector all need to be coplanar. Once you make the forward vector essentially the same as the world up vector, you only really have 2 lines and coplanar becomes no restriction at all; ie. any 2 lines are coplanar if you only have 2 lines (just like there's a straight line between any two points).

Hope I was clear :S.


Ok, first of all, I am NOT a forward vector. Second of all... huh!?

Only joking! So you're saying that the vector between the camera source and position cannot be the same as my world up vector? You talk about a camera up vector and a world up vector... are these two seperate things?

Share this post


Link to post
Share on other sites
"Up" is not a reference to a direction (0,1,0). It's where the top of your head points to.
So when you're looking down, it points to the front (0,0,1) (actually, it could point at any direction: (sin(x),0,cos(x)) for any x).

For normal world rendering, it has to be orthogonal to your camera direction.

Clearer?

Share this post


Link to post
Share on other sites
Sorry about that. I guess when I type I think mostly in terms of speaking than writing. Anywho:

A rotation matrix on some level corresponds to some vectors in relation to the camera (well for the camera anyway). There's the forward vector, the up vector, and the right vector (pretty much the new z, y, and x directions). Given the camera's position and the point it's looking at, you can determine forward. Up could be any line perpendicular to forward, so we use a world up vector (that's your &vUp) to determine it. We choose the up vector that is coplanar with forward and world up. Then right is basically a cross product. Now with only two lines (which is essentially what happens if your forward and world up vectors are parallel), coplanar becomes meaningless. It could once again be any old line. That's why it's funky, if I understand correctly. If I remembered where I read all this, I'd linkify it. That would probably be more clear than my ramblings.

Share this post


Link to post
Share on other sites
Quote:
Original post by devin_papineau
Sorry about that. I guess when I type I think mostly in terms of speaking than writing. Anywho:

A rotation matrix on some level corresponds to some vectors in relation to the camera (well for the camera anyway). There's the forward vector, the up vector, and the right vector (pretty much the new z, y, and x directions). Given the camera's position and the point it's looking at, you can determine forward. Up could be any line perpendicular to forward, so we use a world up vector (that's your &vUp) to determine it. We choose the up vector that is coplanar with forward and world up. Then right is basically a cross product. Now with only two lines (which is essentially what happens if your forward and world up vectors are parallel), coplanar becomes meaningless. It could once again be any old line. That's why it's funky, if I understand correctly. If I remembered where I read all this, I'd linkify it. That would probably be more clear than my ramblings.


So, you are saying that my camera direction, and my world up are used to calculate some kind of plane that is used for rendering. Because they are both parallel to each other this plane cannot be calculated? Kind of makes sense.

Share this post


Link to post
Share on other sites
Quote:
Original post by devin_papineau
Here I think I found it: clicky.


Ok, gonna take me a while to read through, thanks for the link. I amended my code to make the vUp orthogonal (I am sure there is a much quicker way of doing it, but it seems to work)...

// calculate orthogonal vector for world up (top of head)
D3DXVECTOR3 vHeadUp;
vHeadUp.x=vTarget.x - ((float)(sin(fAngleY-(D3DX_PI/4))*cos(fAngleX)) * fDistance);
vHeadUp.y=vTarget.y + ((float)(cos(fAngleY-(D3DX_PI/4))) * fDistance);
vHeadUp.z=vTarget.z + ((float)(sin(fAngleY-(D3DX_PI/4))*sin(fAngleX)) * fDistance);

// set view transform
D3DXVECTOR3 vUp=vTarget-vHeadUp;
D3DXMatrixLookAtLH(&matView, &vSource, &vTarget, &vUp);
if (FAILED(InDevice.SetTransform(D3DTS_VIEW, &matView)))
return FALSE;

Share this post


Link to post
Share on other sites
just cap your rotation so your forward vector is never equal to the positive or negative world up vector (0,1,0) or (0,-1,0) because the cross product of two vectors that are the same is an undefined behavior



void CCamera::Pitch(float fAngle)
{
D3DXMATRIX mat;
// this is going to be our epsilon to determine
// if the dotproduct is too close to one - this is for our capping value
const float fEpsilon = 0.1f;

D3DXMatrixRotationAxis(&mat, &mRight, fAngle);
D3DXVec3TransformCoord(&mUp, &mUp, &mat);
D3DXVec3TransformCoord(&mAt, &mAt, &mat);

float dotVal = abs(D3DXVec3Dot(&mAt, &vGlobalUp));
float minVal = min(dotVal, 1.0f);
float maxVal = max(dotVal, 1.0f);

// this should cap the rotation if our forward vector gets too close
// to the global up vector (if we look straight up)
// If the dot product of the At-Vector and Global Up is too close to 1
// that means we are close to having the same vector.
if( maxVal - minVal < fEpsilon )
{
// rotate back to where we were before
D3DXMatrixRotationAxis(&mat, &mRight, -fAngle);
D3DXVec3TransformCoord(&mUp, &mUp, &mat);
D3DXVec3TransformCoord(&mAt, &mAt, &mat);
}


}




This is assuming that you are calculating your matrix similar to the following...

void CCamera::GetViewMatrix(D3DXMATRIX *pOut)
{
if( !pOut )return;

D3DXMATRIX &out = *pOut;

D3DXVec3Normalize(&mAt, &mAt);
const D3DXVECTOR3 yaxis(0.0f, 1.0f, 0.0f);

// using the global up (y-axis) keeps our head feeling like it should while doing the
// mouse look...
D3DXVec3Cross(&mRight, &yaxis, &mAt);
D3DXVec3Normalize(&mRight, &mRight);

D3DXVec3Cross(&mUp, &mAt, &mRight);
D3DXVec3Normalize(&mUp, &mUp);

out(0,0) = mRight.x;
out(0,1) = mUp.x;
out(0,2) = mAt.x;
out(0,3) = 0.0f;

out(1,0) = mRight.y;
out(1,1) = mUp.y;
out(1,2) = mAt.y;
out(1,3) = 0.0f;

out(2,0) = mRight.z;
out(2,1) = mUp.z;
out(2,2) = mAt.z;
out(2,3) = 0.0f;

out(3,0) = -D3DXVec3Dot(&mRight, &mPos);
out(3,1) = -D3DXVec3Dot(&mUp, &mPos);
out(3,2) = -D3DXVec3Dot(&mAt, &mPos);
out(3,3) = 1.0f;
}




This is from an old camera class of mine that I don't really use any more, so I'm sure there are plenty of optimizations that can be made.

hth
moe.ron

Share this post


Link to post
Share on other sites
Just out of curiousity, is it necessary that the forward and up vectors be orthogonal? I usually leave my up vector as (0,1,0), and regardless of how my camera is oriented (as log as it's not viewing parallel), it looks around just fine, but stays tilted so that up stays up, if you follow.

--Vic--

Share this post


Link to post
Share on other sites
yes it is. They must be orthogonal or the orientation matrix will be skewed and everything will look quite trippy. If you pass the vectors to D3D (and maybe opengl), then there is a good chance D3D will re-orthogonalise the vectors itself just to make sure. This is where the weird camera behaviour happens if the vectors are parallel, because it's imposible to make two parallel vectors orthogonal. D3D will probably do a fail-safe procedure and set the Up vector from (0, 1, 0) to something like (1, 0, 0).

this is some code to make the vectors orthogonal again and generate a valid orientation matrix.


// right-handed orthogonal system
// vector basis
// ------------------------------
// Z = X x Y
// Y = Z x X
// X = Y x Z

// Camera equivalent
// -----------------
// Up <=> Y
// Dir <=> Z
// Side <=> X

Vector& Y = Up;
Vector& Z = Dir;
Vector X;
Matrix3x3 Orientation;

// make sure vectors are not parallel
// Or the orientation matrix will be completely shagged
// -----------------------------------------------------
if (fabs(Y * Z) > 0.999999f) // '*' <=> vector dot product
{
Assert(false, "Camera Up and dir are parallel!"); // assert

// Set Up to an arbitrary vector
// -----------------------------
if (fabs(Y.y) < 0.99f)
{
Y = Vector(0, 1, 0);
}
else
{
Y = Vector(1, 0, 0);
}
}

// re-orthogonalise the vector basis
// ---------------------------------
// Dir and Up have to be of length one beforehand
// If not, normalise them.
// ---------------------------------
X = Y ^ Z; // '^' <=> vector cross product
X.Normalise(); // re-normalise (should always be valid thanks to the parallel checks)
Y = Z ^ X; // (should always be of length 1).

Assert(ApproxEqual(X.LengthSquared(), 1.0f), "Error in Camera re-orthogonalisation");
Assert(ApproxEqual(Y.LengthSquared(), 1.0f), "Error in Camera re-orthogonalisation");
Assert(ApproxEqual(Z.LengthSquared(), 1.0f), "Error in Camera re-orthogonalisation");

// Set the orietnation to the
// vector basis (for a row-major matrix system).
// --------------------------
Orientation.SetRow(0, X);
Orientation.SetRow(1, Y);
Orientation.SetRow(2, Z);



Share this post


Link to post
Share on other sites
Ok, yeah, that must be it. D3D must automatically do it becasuse I've been just using the same vector for the up angle no matter which way I'm looking. I've just never looked stragiht up or down. Interesting to know.

--Vic--

Share this post


Link to post
Share on other sites
Sign in to follow this  

  • Advertisement