   Camera Problems in OGL
  Having fixed up and finished my DX8 input functions I moved onto the next logical thing.... the camera. This is something that has eluded me since I first looked at OGL years ago.I've been able to get it "working" to a level consistent with my programs which were pretty rudimentary. Now I'm looking to make it move in a 3D world. I've spent most of today trying to figure it out with little progress.I read the following article here: http://www.gamedev.net/reference/articles/article2160.aspThat actually made things worse. This is probably a math problem more then anything else :/Here's some code to paint a picture of what's happening.void CKeyboardModule::ProcessInput(){KEYSTROKE vKeyPress;while(!m_vpKeysPressed.IsEmpty()) {vKeyPress = m_vpKeysPressed.Remove();switch(vKeyPress.uiScanCode) {case DIK_LEFT:::g_VideoModule.GetCamera().Translate(fVector3D(0.01f,0.0f,0.0f));break;case DIK_RIGHT:::g_VideoModule.GetCamera().Translate(fVector3D(-0.01f,0.0f,0.0f));break;case DIK_UP:::g_VideoModule.GetCamera().Translate(fVector3D(0.0f,0.0f,0.01f));break;case DIK_DOWN:::g_VideoModule.GetCamera().Translate(fVector3D(0.0f,0.0f,-0.01f));break;}}}void CMouseModule::ProcessInput(void) {::g_VideoModule.GetCamera().Rotate(fVector3D(m_vMouseState.lY,m_vMouseState.lX,0.0f));}void CCamera::Rotate(fVector3D v){    m_fvRotation += v;    double dCosY = ::cos(m_fvRotation.y);    m_fvTar.x = m_fvPos.x+(float)(dCosY*::cos(m_fvRotation.x));    m_fvTar.y = m_fvPos.y+(float)(::sin(m_fvRotation.y));    m_fvTar.z = m_fvPos.z+(float)(dCosY*::sin(m_fvRotation.x));   m_fvUp.x = m_fvPos.x-m_fvTar.x;    m_fvUp.y = ::fabs(m_fvPos.y+(float)(::sin(m_fvRotation.y+PI_OVER2))) ;    m_fvUp.z = m_fvPos.z-m_fvTar.z;}void CCamera::Translate(fVector3D v){float fWMotion;double dCosY;//m_fvPosition += v;if(v.z) {fWMotion = v.z*0.02f;dCosY = ::cos(m_fvRotation.y);m_fvPos.x += fWMotion*(float)(dCosY*::cos(m_fvRotation.x));m_fvPos.y += fWMotion*(float)::sin(m_fvRotation.y);m_fvPos.z += fWMotion*(float)(dCosY*::sin(m_fvRotation.x));Rotate(fVector3D());}if(v.x || v.y) {fWMotion = v.x*0.2f;m_fvPos.x += fWMotion*(float)::cos(m_fvRotation.x+PI_OVER2);m_fvPos.y += v.y*0.2f;m_fvPos.z += fWMotion*(float)::sin(m_fvRotation.x+PI_OVER2);Rotate(fVector3D());}}void CCamera::Update(){glMatrixMode(GL_MODELVIEW);glLoadIdentity();/*glFrustum(-.5,.5,-0.75,0.75,0.1,500.0);glRotatef(m_fvRotation.z,0.f,0.f,1.0f);glRotatef(m_fvRotation.x,1.0f,0.f,0.f);glRotatef(m_fvRotation.y,0.f,1.0f,0.f);glTranslatef(m_fvPos.x,m_fvPos.y,m_fvPos.z);*/gluLookAt(m_fvPos.x,m_fvPos.y,m_fvPos.z,m_fvTar.x,m_fvTar.y,m_fvTar.z,m_fvUp.x,m_fvUp.y,m_fvUp.z);glMatrixMode(GL_PROJECTION);glLoadIdentity();}The DX8 functions haven't changed. The camera functions have changed a bunch. They were originally 1 line... simply Camera::vector += otherVector. The update function, which is called just before the objects are placed in the render function originally set the mode to projection, executed the commented code and returned. That yielded something equivalent to an avatar walking north, south, east and west that could look at any direction.I wanted the camera to move along the direction is was looking. So then I introduced the MODELVIEW 1st, did rotations, PROJECTION mode, did translation. I'm not sure what that did as my colored single quad floor and floating triangle got clipped a lot.Then I did some more reading (the articles I mentioned) and then my Rotate, Translate and Update functions changed to the current state. Which makes everything move around a lot. Basically at this point I'm pretty lost.... the best results so far was with my initial code.Thanks for the assistance.   
  Doesn't the projection have to be done before the Modelview matrix?   ;  Doh!!!!To be honest it's been a really long time since I did work with cameras so IDK. It's kinda amazing how a 12 hour break can enlighten the mind (or maybe not). Should I be making a "right" vector for my camera to go along with the up and target? And using those in Update() instead of the x-, y-, z-axis in my Rotate calls and then use glFrustum instead of gluLookAt?Doing scenegraphs, multithreading, networking.... I can, and have whittled my way through that with little outside help in other projects. This camera thing has got me stumped. I don't need code for the solution just an outline of the steps to get it done should be good.Actually, it may not have been perfect but it was closer to the end goal... the original way I had my camera setup with just the rotation and position vectors += othervector. That seemed good. Only thing it needed was to adjust Translate() to move along the rotated vector instead of -/+x, -/+z-axes.To Translate would I?: 1. rotate vector passed to Translate according to stored info in CCamera2. Add result to CCamera position vectorIf anything this might show how bad my math is. I'm sure there's a much better way of doing that. But I think it should work. It seems kinda redundant to rotate the movement vector in code... then rotate the world in hardware using the same info. Is that how it's done?   ;  Whats v in "CCamera::Rotate(fVector3D v)" is that just radian angles? like pitch yaw roll?   ;  fVector3D is a typedef for a 3 dimensional vector template class.... using floats. It just stores the values obtained from the mouse state and does not change them. If I remember right the unit of mouse movement is called a mickey. That's what the vector stores. Originally this worked out ok. After I changed the code to what it is now I initially see a black screen and when I move the mouse around stuff flicks in and out from the edges.Prior to that, the way I describe how it worked orginally, the camera pointed down the -z axis. I saw my single quad floor, floating triangle, Could walk N, E, W, S and look anywhere..... Things rotated smoothly. I just wasn't walking where I looked.I'm going to try out the steps I laid out and see what happens. I'm just not up to speed on my math anymore. I prefer to do things the "better" way rather than just get it working... this would be one of the times when I'm not sure if what I'm doing is the "better" way (and if my steps actually work).[Edited by - Robione on May 15, 2009 6:30:21 AM];  Try breaking the behavior you want down into smaller more error proof calls, cameras can be a pain, maybe use some math utility classes along with vector class to perform the rotation functionality, so you know it works, while keeping motion and timing values stored within the class or passed in so it can be changed easily. Overall just break everything down to a level where you can see right away what might be wrong. Something similar to this might help if you are doing a free look cameraFrame Starts//....Get Mouse/Key input// apply input to camera, using calls...struct xform // remember to initialize{quat Rotation;vec3 Translation;} mLocal, mWorld;Yaw(float degrees) // look left right{mYaw += TORAD(degrees);// sum pitch yaw and roll each, use em when neededWrap2PI(mYaw);rotationInvalid = true;} // same for pitch rollMoveTo(vec3 pos)// absolute reposition{mLocal.Translation = pos;}MoveHorz(float amount) // strafe left right (+/-){MoveTo(GetPosition() + (GetRight() * amount));// Get*() is local info// GetRight() = mLocal.Rotation * VEC3_UNITX}MoveVert(float amount) // up down  (+/-) like floating or jumping along local up{MoveTo(GetPosition() + (GetUp() * amount));// Get*() is local info// GetUp() = mLocal.Rotation * VEC3_UNITY}MoveForward(float amount) // forward back  (+/-) along direction pointing{MoveTo(GetPosition() + (GetDirection() * amount));// Get*() is local info// GetDirection() = GetUp().Cross(GetRight());}// some update at later time, before renderingUpdateCamera(){quat qpitch, qyaw;qpitch.FromAxisAngle(VEC3_UNITX, mPitch);// pitch around Xqyaw.FromAxisAngle(VEC3_UNITY, mYaw);// yaw around YmLocal.Rotation = qyaw * qpitch;quat qrollqroll.FromAxisAngle(VEC3_UNITZ, mRoll);// roll around Z (dir)mLocal.Rotation = qroll * mLocal.Rotation;// cameras parent is world (ie not attached to anything so...), mWorld = mLocal}// render usingglMatrixMode(GL_MODELVIEW);glPushMatrix();glLoadIdentity();vec3 pos = camera->GetWorldPos()// mWorld.Translatonvec3 up = camera->GetWorldUp()// mWorld.Rotation * VEC3_UNITY// mWorld.Rotation * VEC3_UNITX == GetWorldRight()vec3 dir = camera->GetWorldDir()// GetWorldUp().Cross(GetWorldRight())vec3 target = pos + dirgluLookAt(pos, target, up);glPopMatrix();Frame Ends- Move*() calls act on last frames state- Yaw*() Pitch*() Roll*() further rotate last frames angles- Update() applies this frames rotation angles by recalculating new absolute orientation- then use new orientation to render after update- repeat;  NumberXaero thank you very much for your help. Your example provided that added benefit of quaternions :) For some strange reason I thought they were used a little differently. Seeing the Move* functions was very useful. I only have two questions:(deleted... figured it out)Your MoveVert function.... I guess this depends on what kind of camera it is but does the math as you implemented it say that if I pitch the camera up, MoveVert will move the camera up and back?.....Oh!!! And how do you get your code in the nice box? I used square-bracket code, /code tagsin my first post. I like how you posted code better.[Edited by - Robione on May 19, 2009 11:47:41 PM];  Just posting the "working" code in case anyone gets stuck like I did.Some potential issues:if you want to have a "flying" camera in CCamera::Move() use m_fvUp x m_fvRight instead of UNIT_VECY x m_fvRightnot sure if roll is working right as I don't plan on using it atm so it's untestedalso y movement will later have to be adjusted to terrain height something that I don't have to worry about yetMy variable naming scheme is somewhat generic when it comes to anything but the basic types.... m_fv, fv are floating vectors (i.e. arrays) so quaternions, vectors and matrices all use that prefix. m_fvRotation is now a quaternion. m_fvPYR represents what the old m_fvRotation did... pitch, yaw, roll.An article I was reading a week or so ago (whenever I first posted this) might help with the internals of the quaternion (http://gpwiki.org/index.php/OpenGL:Tutorials:Using_Quaternions_to_represent_rotation). I used that for vector rotation and conjugate operations. The rest I got from one of the older Game Programming Gems books.... years ago. :/I put in a radian wrapping function like NumberXaero had in case I use a lookup table for sin/cos values otherwise it isn't needed really....... well who knows maybe some problems could occur if you sat and span around for a really long time LOL :) I noticed no real change w/o it.Hope this helps... and if anyone notices anything please let me know.... One last thing, in case anyone is curious why I'm not using any glu* calls I'm trying to keep the executable size down if I can.void CKeyboardModule::ProcessInput(){KEYSTROKE vKeyPress;fVector3D fvMove;while(!m_vpKeysPressed.IsEmpty()) {vKeyPress = m_vpKeysPressed.Remove();switch(vKeyPress.uiScanCode) {case DIK_LEFT:fvMove.x += 0.1;break;case DIK_RIGHT:fvMove.x += -0.1;break;case DIK_UP:fvMove.z += -0.1;break;case DIK_DOWN:fvMove.z += +0.1;break;}}if(!fvMove.IsZero())::g_VideoModule.GetCamera().Move(fvMove);}//Changes were made so a single call to Move is made. As Move() is more expensive then my original Translate()void CMouseModule::ProcessInput(void) {::g_VideoModule.GetCamera().Rotate(fVector3D(-m_vMouseState.lX,-m_vMouseState.lY,0.0f));}//Changed signs here and some in the KB input processing. After implementing quaternions movement flipped on mevoid CCamera::Rotate(fVector3D &v){v *= ::g_Preferences.m_fMouseSensitivity * PI_OVER360;//PI/360 used to precompute values for SetEuler() in Quaternion instead of PI/180m_fvPYR += v;RadianWrap(m_fvPYR);m_fvRotation.SetEuler(m_fvPYR.x,m_fvPYR.y,m_fvPYR.z);}void CCamera::Translate(const fVector3D &v){m_fvPosition += v;}void CCamera::Update(bool bHUDMode){glMatrixMode(GL_PROJECTION);glLoadIdentity();float fvMatrix[16];if(bHUDMode) {glOrtho(m_fvOrthoPlanes[VPLANE_LEFT_INDEX],m_fvOrthoPlanes[VPLANE_RIGHT_INDEX],m_fvOrthoPlanes[VPLANE_BOTTOM_INDEX],m_fvOrthoPlanes[VPLANE_TOP_INDEX],m_fvOrthoPlanes[VPLANE_NEAR_INDEX],m_fvOrthoPlanes[VPLANE_FAR_INDEX]);glMatrixMode(GL_MODELVIEW);glLoadIdentity();} else {glFrustum(m_fvViewPlanes[VPLANE_LEFT_INDEX],m_fvViewPlanes[VPLANE_RIGHT_INDEX],m_fvViewPlanes[VPLANE_BOTTOM_INDEX],m_fvViewPlanes[VPLANE_TOP_INDEX],m_fvViewPlanes[VPLANE_NEAR_INDEX],m_fvViewPlanes[VPLANE_FAR_INDEX]);glMatrixMode(GL_MODELVIEW);glLoadIdentity();m_fvRotation.GetMatrix4D(fvMatrix);glMultMatrixf(fvMatrix);glTranslatef(m_fvPosition.x,m_fvPosition.y,m_fvPosition.z);}}void CCamera::Move(const fVector3D &v){fVector3D fvMove;m_fvRight = m_fvRotation * UNIT_VECX;m_fvUp = m_fvRotation * UNIT_VECY;m_fvTarget = UNIT_VECY.CrossProduct(m_fvRight);if(v.x)fvMove += m_fvRight.Normalize() * v.x;if(v.y)if(m_bAbsVert)fvMove += UNIT_VECY * v.y;elsefvMove += m_fvUp.Normalize() * v.y;if(v.z)fvMove += m_fvTarget.Normalize() * v.z;Translate(fvMove);} [Edited by - Robione on May 20, 2009 2:34:52 AM]