Crazy Camera Happenings When Pointing Straight Down

Started by
10 comments, last by Roof Top Pew Wee 18 years, 10 months ago
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?
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.
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?
"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?
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.
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.
Here I think I found it: clicky.
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;
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
moe.ron
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--

This topic is closed to new replies.

Advertisement