In my engine, I have an implementation of the LookAt() function from MESA, and in that logic I retain the camera’s basis vectors for use later.
Here’s my logic:
// --------------------------------------------------------------------------
// This routine will generate a lookAt matrix provided that the eye position,
// a viewing target have been set. An internal “up” vector may also be set,
// but defaults to the {0,1,0} vector. The result is stored in m_viewMat:
// --------------------------------------------------------------------------
inline void LookAt( void )
{
// create a rotation matrix by calculating a camera direction vector,
// and then using that to generate the remaining vectors for a rotation mat:
// m_basisZ vector is the direction vector from target to the eye:
m_basisZ = m_eye - m_target;
m_basisZ.Normalize();
// make sure the source data for the up vector is not modified:
m_basisY = m_up;
// m_basisX = m_basisY % m_basisZ; // cross product... same as my old CrossProductFVector( &y, &z, &x ); x is the result
// m_basisY = m_basisZ % m_basisX; // cross x & z to insure that we're perpendictular
//
m_basisX = m_basisY.Cross( m_basisZ );
m_basisY = m_basisZ.Cross( m_basisX );
// normalize these guys:
m_basisX.Normalize();
m_basisY.Normalize();
// directly set the values to construct a rotation matrix:
// glow::Mat4f rotMat;
CMat4f rotMat;
rotMat.SetVal( 0,0, m_basisX.GetX() ); rotMat.SetVal( 0,1, m_basisX.GetY() );
rotMat.SetVal( 1,0, m_basisY.GetX() ); rotMat.SetVal( 1,1, m_basisY.GetY() );
rotMat.SetVal( 2,0, m_basisZ.GetX() ); rotMat.SetVal( 2,1, m_basisZ.GetY() );
rotMat.SetVal( 3,0, 0.0f ); rotMat.SetVal( 3,1, 0.0f );
rotMat.SetVal( 0,2, m_basisX.GetZ() ); rotMat.SetVal( 0,3, 0.0f );
rotMat.SetVal( 1,2, m_basisY.GetZ() ); rotMat.SetVal( 1,3, 0.0f );
rotMat.SetVal( 2,2, m_basisZ.GetZ() ); rotMat.SetVal( 2,3, 0.0f );
rotMat.SetVal( 3,2, 0.0f ); rotMat.SetVal( 3,3, 1.0f );
// construct a translation matrix:
// glow::Mat4f tranMat;
CMat4f tranMat;
tranMat.SetTranslation( -m_eye.GetX(), -m_eye.GetY(), -m_eye.GetZ() );
// finally generate our lookAt matrix:
// m_viewMat = rotMat * tranMat;
m_viewMat = rotMat.CMat4fMult( tranMat );
}
// -------------------- get the last calculated x,y,z basis vectors -----------------
inline void GetBasisVectors( CVec3f *leftRight, CVec3f *upDown, CVec3f *inOut )
{
*leftRight = m_basisX;
*upDown = m_basisY;
*inOut = m_basisZ;
}
Note that ‘leftRight’ points to the right, ‘upDown’ points up and ‘inOut’ points into the camera (out of the screen.)
These are normalized vectors, so you can simply get these basis vectors, and then you’ll know your various directions relative to the current camera view.
This logic right here will calculate the 4 corners of your screen at that near clipping plane in world coordinates:
// calculate the x,y max,min bounds for the near clipping plane:
double ymax = gApp->GetCameraZNear() * tan( gApp->GetCameraFOV() * CMath: [img]http://www.opengl.org/discussion_boards/ubb/tongue.gif[/img]i / 360.0 );
double ymin = -ymax;
double xmin = ymin * gApp->GetCameraAspect();
double xmax = ymax * gApp->GetCameraAspect();
// get direction vectors for the current view:
CVec3f leftRight, upDown, inOut;
gApp->GetCameraBasis( &leftRight, &upDown, &inOut );
// 'inOut' points in, towards the camera but we want it to point outwards:
inOut.Negate();
// figure out the coord that is the world space screen center:
CVec3f cameraPosition = gApp->GetCameraPosition();
CVec3f worldSpaceScreenCenter( cameraPosition );
worldSpaceScreenCenter += (inOut * gApp->GetCameraZNear());
// calculate the near clip plane frustum corner coordinates:
CVec3f topLeft( worldSpaceScreenCenter ),
topRight( worldSpaceScreenCenter ),
botLeft( worldSpaceScreenCenter ),
botRight( worldSpaceScreenCenter );
// project the 'top' points up:
topLeft += (upDown * ymax);
topRight += (upDown * ymax);
// project the 'bottom' points down:
botLeft += (upDown * ymin);
botRight += (upDown * ymin);
// project the 'left' points left:
topLeft += (leftRight * xmin);
botLeft += (leftRight * xmin);
// project the 'right' points right:
topRight += (leftRight * xmax);
botRight += (leftRight * xmax);
There may be easier ways to calculate this, but it seemed so simple, I like this method.
Once you have the 4 corners at the near clip plane, just nudge them back a tad (so they don’t get clipped) and draw your hud. (Nudge back further if you have a 3D hud )
-Blake