1. yeah np man, it's good to have different points of views on things (in this case black's method and my method).

can you post your updated code and any necessary data files? maybe we can look through and figure out why it is doing the things you don't want it to do.

2. Yeah, there's a minor problem with my camera code, and I haven't quite figured out how to fix it yet (I also haven't tried to fix it yet) I don't think my method is at fault though - it's something silly.

Silver - if you're never rotating the camera on the Z axis, the strafe vector will always be the X axis (assuming you're using normal coordinate system with X being horizontal) So, you are rotating over X. (I can't think of any reason that your strafe vector would change in camera space other that rotation on Z) If you're only rotating on two axes, though, gimbal lock becomes a little less likely, although not impossible. It could be your problem with looking straight down w/ the collision detection. Here's what could happen.

When you rotate 90 degrees down over the x axis/strafe vector (same thing), you'll be looking straight down. UNLESS you rotate the camera's y axis over the strafe vector at the same time, the camera's Z and X vectors will be lined up, becoming the same axis when you're looking straight down/up. If you're not rolling the camera, you won't notice it, but it could be what's messing up your collision detection. You also won't be able to add camera roll without breaking it.

Right now, I'm not using quaternions with my camera class. I might switch it over to use them, because it might be easier - but first, I'd like to know if there are any ways to optimize their usage in my transformation class (which transforms between object space and world space) I'll write you a short blurb about how quaternions work.

A quaternion has four values - a w, x, y, and a z. Euler came up with some theorem that states that any series of rotations can be represented as one rotation about some axis. So, the x, y, and z of the quaternion are used to store the orientation of this axis. The w component represents how much rotation is needed over this axis. w^2+x^2+y^2+z^2=1. You have to keep your quaternions normal, or they won't work.

The quaternion which represents no rotation is (1,0,0,0) (that's w,x,y,z) It's possible to find the quaternion that represents the total rotation given by two quaternions by multiplying them together. Here's the formula for quaternion multiplication
(Q1*Q2).w = w1w2 - x1x2 - y1y2 - z1z2
(Q1*Q2).x = w1x2 + x1w2 + y1z2 - z1y2
(Q1*Q2).y = w1y2 + y1w2 + z1x2 - x1z2
(Q1*Q2).z=w1z2+z1w2+x1y2-y1x2
It's not communitive. w1*w2 != w2*w1.

Another thing to note about quaternions is this. w,x,y, and z are all real numbers, but in the actual quaternion, all but the w term are imaginary. Q = (w+xi+yj+zk) where i^2=j^2=k^2=-1. I'm not sure why this is important other than perhaps in keeping it normal, and it comes into play with the conjugate (explained below) I'm not sure if this is important or not, because DX handles a lot of the math, and quaternions are pretty new to me.

So, you start off by initializing your quaternion to the identity quaternion (1,0,0,0) Then, suppose that you want to rotate your object over the X axis a bit. You'll have to generate a temporary quaternion, which you will then multiply by the quaternion which represents all your transformations. Let's call them temp and total, just to make this explanation clearer. For rotation over the x axis, the y and z components of temp will (obviously) be 0. The w and x components will be non-zero. And the magnitude of temp sqrt(w^2+x^2+y^2+z^2) (I think that's right) will have to be 1. You'll have to figure out how big the x component and how big the w component each should be. (Sorry, can't help much here - DX does it easily... although I do have the following description from a tutorial. If you can make sense of it, great... I can't.
if the axis of rotation is (ax,ay,az)
and the angle is theta (radians)
then the angle = 2* acos(w)
ax=x/scale
ay=y/scale
az=z/scale
where scale = sqrt(x^2+y^2+z^2)
Anyway, suppose that you figure out how to generate temp correctly. To update total, just do total*=temp, using the multiplication rule I gave you above. Then you'll have the quaternion representing all of your rotations. You'll have to convert it into a matrix in order to use it. This is the way they do it in the tutorial I'm currently looking at, although I'm not sure if it's right or not (once again, DX does it, and I'm not sure which coordinate system this tutorial uses, although I think it's right handed)

Code:
```matrix = [	w^2+x^2-y^2-z^2		2xy=2wz			2xz+2wy
2xy+2wz			w^2-x^2+y^2-z^2		2yz-2wz
2xz-2wy			2yz=2wz			w^2-x^2-y^2+z^2]

using the property of unit quaternions that w^2+x^2+y^2+z^2=1, we can reduce the matrix to

matrix = [	1-2y^2-2z^2		2xy-2wz			2xz+2wy
2xy+2wz			1-2x^2-2z^2		2yz-2wz
2xz-2wy			2yz+2wz			1-2x^2-2y^2 ]

(if I made any typos in that, sorry.  I posted a link to the tutorial, anyway)```
That matrix will be your rotation matrix. Multiply it by a translation matrix to get your world matrix (or I suppose camera matrix) (or just code the transformations into that matrix, since you'll be writing your own class...that would be a better solution. If you can't figure that out, I can tell you what to do, because combining the transformation matrix with the quaternion one isn't hard)

If you want your axes to rotate with the object (or camera), which you most likely do, I found that you'll have to rotate the axes by the temp quaternion, and then use these axes for the next temp quaternion. If anyone knows of a way around this, please let me know, because it seems inefficient to generate that many matrixes and such

So, if you do it like what I just said (have a look at my code if my "tutorial" is a bit unclear), you should have an object which can rotate freely on all three axes, without ever having to worry about gimbal lock. (Note: I'm wondering whether my quaternions will get messed up after a long time, because of floating point innaccuracy. If they do, I think it could be fixed by just normalizing the quaternion occasionally)

Oh, and you asked about the conjugate of the quaternion. It might have been the other thread. Anyway, the conjugate of a quaternion is just like a complex conjugate (since they're based off complex numbers) So Q*=(w-xi-yj-zk)

I think I covered everything.

Sorry if I got something wrong/didn't make sense. I just tried to give blood (they called me and said they desperately needed my blood type) and they frickin' botched it up, so I'm a bit jarred right now. No, thank you nurse, I don't need you to unsuccessfully jab that needle around in my arm anymore, I'll leave now. Oh, and Darksaidin - sorry for kinda taking over your thread with quaternions. You might be able to get some benefit out of it though, if you can follow the math.

3. This is as far as I've gotten:
Silver - if you're never rotating the camera on the Z axis, the strafe vector will always be the X axis
and that's wrong because the Y axis is up not Z (at least in my code)

EDIT: (there will be a lot of edits in this post prolly) and you keep referring to 'X', 'Y', and 'Z'...I know all about object space but the x y and z axes and their respective rotation matrices aren't ever examined in my code

4. Well, I assumed that you were rotating the X axis when you rotated on the Y axis. (X horizontal, Y vertical, Z in/out of screen) So the plane of the camera x vector would always be parallel to the world's x plane.

What, exactly, are you doing in your camera class when you rotate the camera?

5. literally what I said before and the functions I posted, which is rotations about an arbitrary axis.

also I'm 'rolling' the camera from side to side slightly when I hit the strafe keys and everything seems to be working. Exactly why is it bad when the view vector maps onto the vector i'm rotating about, i.e lets say I want to always rotate the view vector about the y axis instead of the up vector (the upvector is calculated every frame, the y axis is a member variable that stays the same at (0, 1, 0)...both methods seem to work fine)

EDIT: and why must you put it into the matrix form again? Why can't you just find the equation form and use that/

EDIT1:
Oh, and you asked about the conjugate of the quaternion. It might have been the other thread. Anyway, the conjugate of a quaternion is just like a complex conjugate (since they're based off complex numbers) So Q*=(w-xi-yj-zk)
which makes sense because tha'ts the only way this could be true:
w^2+x^2+y^2+z^2=1

6. The real problem is when you get the X axis mapped onto the Z axis (or whatever you're using as these axes) Then, instead of having three mutually perpendicular axes, you have two... which doesn't work so hot.
Code:
```RotateVector(XDegRad, &mStrafe, &mView);
Don't you lose all orientation if you rotate so you're looking straight down? How do you tell what direction you're guy should head? (I know you currently have looking straight down disabled. This might be the problem) Think about it... imagine, for a moment, that the strafe vector is lined up with the X axis. Rotate 90 degrees down. The X axis is unchanged - still horizontal. The Y axis hasn't been rotated, so it's still vertical. It should be in/out. The Z should be vertical, but it's still in/out. So, rotating on the Y axis is doing what the Z axis should be doing when you look straight down, and any roll will be on what should be the Y axis. I'm thinking that your code for making the mouse control the camera gets messed up as you look down (or up) and would become very noticable at straight down/up. If you want the Y axis always coming out of the top of your camera, and the X axis coming out of the sides, and the Z axis going through the lens (pretending you have a real video camera), you have to rotate your axes and do subsequent rotations about the modified axes.

Response to edit: Sorry, I forgot momentarily that you weren't using matrices. I guess you could put it into equation form (wouldn't that just be a representation of the matrix, though?), but I'm not sure how the w would go into the equation.

7. Originally posted by Silvercord
literally what I said before and the functions I posted, which is rotations about an arbitrary axis.

also I'm 'rolling' the camera from side to side slightly when I hit the strafe keys and everything seems to be working. Exactly why is it bad when the view vector maps onto the vector i'm rotating about, i.e lets say I want to always rotate the view vector about the y axis instead of the up vector (the upvector is calculated every frame, the y axis is a member variable that stays the same at (0, 1, 0)...both methods seem to work fine)

EDIT: and why must you put it into the matrix form again? Why can't you just find the equation form and use that/

EDIT1:

which makes sense because tha'ts the only way this could be true:
w^2+x^2+y^2+z^2=1
You won't run into any trouble, not even if you roll by rotating up- around view- vector. You could even rotate your strafe-vector around the view vector (which doesn't make any sense in a FPS), but you can't do proper rotations around your new, rotated upvector without ruining your coordinate system. If you want to do that, you need to rotate 2 vectors at a time by a function that locks the angle beween those vectors to 90 degrees.

Sorry if this doesn't make any sense =) Gotta get some sleep now. As for posting the code: I'll try to do that tomorrow if you really want to see it, but there is nothing special about it. btw, there aren't any problems with it. Did I say that?

8. Don't you lose all orientation if you rotate so you're looking straight down? How do you tell what direction you're guy should head
actually no, I've solved this problem. I first made it so that you can't look completely straight down, I make it so that you're withing EPSILON units of looking straight up or down, but it's pretty darn close (you'd basically never notice it). I then calculate the velocity for this frame (by multiplying the time that's passed by the feet per second that i chose to travel). Once I've got that length I project the view vector onto the xz plane. Projecting the vecotr onto the xz plane changes its length, so I make sure it still has a valid length (which is why i made it within EPSILON units of looking straight UP or straight DOWN, because if you could look exactly straight up or down the projection of the view vector onto the xz plane would yield a vector with a length of zero), I then normalize it then multiply it by this frame's velocity.

and yes the matrix form of the equation still represents the equation, but it always adds calculations that need to be performed (row by column and then summing those up when you could just use the original equation that the matrix represents).

EDIT:
I'll try to do that tomorrow if you really want to see it, but there is nothing special about it. btw, there aren't any problems with it. Did I say that?
I thought you implied there were some things you were unsatisfied with. If you don't need help don't post the code, otherwise post it.

9. The reason people use matrices is because it's easy to combine multiple matrices. If you choose to do so, you can represent all the transformations between object space and camera space with a single final matrix. That way, you can take a vertex straight from object space to camera space, including all the translations and rotations. It's easy. And it's not much extra computation - it might even be less when you consider combining them like that. (I know it was an over simplified example, but it's still valid)

10. oh, that's true, it seems like they may be less computations if you combine them beforehand.

sweet now whenever you strafe the camera in my code it 'jinks' because I'm rolling the up vector (but its only done slightly, and only when the d or s keys are hit and not moving the mouse), plus I"ve just got an extremely smooth stair climing method, on top of the invisible ramp stair climing method. I'm actually happy for once today.

11. How does your stair climbing method work? Are you displaying the stairs and having them represented in the collision detection geometry as a sloped plane?

12. I tried that and it works, but I noticed quake doesn't do that. I calculate how much I want to pop the camera up to its actual height, but then i only actually move a fraction of it, here's the code, I just got this working (literally) 5 mins ago
Code:
```TimeInAir = 0;
mAirFraction = 1.0f;

Vector3NewPos=EndIntersect + Vector3(0, DIST_BETWEEN_ENDPOINTS, 0);
NewPos=mPosition + ((NewPos-mPosition) * Fraction)*.1;
if(GetKeyState('V') & 0x80)
{
trace<<mPosition.y -EndIntersect.y << "\n";
trace<<Fraction << "\n";
}
MoveCamera(&NewPos);
return;```
EDIT: and I going to go now, to watch storm of the century

13. Hmmm... it seems like we just wrote 1/3 of a tutorial on how to make Quake For anyone who was about to ask how to do that, take note of this. It's the best answer you're going to get.

Anyway, this has been a pretty great thread. Darksaidin, did we actually get all your questions? I lost track.

14. yeah I lost track too, but ultimately this is still yoru thread dark

15. mhm? ya, I got it all working now. Both cameras. black, if you still have problems with your camera you might want to have a look at this code.

Code:
```// construct our camera
CFlyCamera::CFlyCamera() {
vPosition.set(0.0f, 0.0f, 0.0f);
vView.set(0.0f,0.0f, 1.0f);
vStrafe.set(1.0f, 0.0f, 0.0f);
vUp.set(0.0f, 1.0f, 0.0f);
}

// set basic camera properties
void CFlyCamera::set(CVector3 vCameraPosition, CVector3 vCameraTarget, CVector3 vCameraUp) {
vPosition=	vCameraPosition;
vView=	vPosition -vCameraTarget;
vStrafe=	vCameraUp.cross(vView);
vUp=		vCameraUp;

// normalize our vectors
vStrafe.normalize();
vUp.normalize();
vView.normalize();
}

// translate the camera along it's axes
void CFlyCamera::translate(float fU, float fV, float fN) {
vPosition.x += fU *vStrafe.x +fV *vUp.x +fN *vView.x;
vPosition.y += fU *vStrafe.y +fV *vUp.y +fN *vView.y;
vPosition.z += fU *vStrafe.z +fV *vUp.z +fN *vView.z;
}

// rotate the camera around it's z
void CFlyCamera::roll(float fAngle) {
rotateInPlane(vStrafe, vUp, -PI/180 *fAngle);
}

// rotate the camera around it's x
void CFlyCamera::pitch(float fAngle) {
rotateInPlane(vView, vUp, PI/180 *fAngle);
}

// rotate the camera around it's y
void CFlyCamera::yaw(float fAngle) {
rotateInPlane(vStrafe, vView, PI/180 *fAngle);
}

void CFlyCamera::updateMatrix() {
float m[16];

m[0]= vStrafe.x; m[4]= vStrafe.y; m[8] = vStrafe.z; m[12]= -vPosition.dot(vStrafe);
m[1]= vUp.x;     m[5]= vUp.y;     m[9] = vUp.z;     m[13]= -vPosition.dot(vUp);
m[2]= vView.x;   m[6]= vView.y;   m[10]= vView.z;   m[14]= -vPosition.dot(vView);
m[3]= 0;         m[7]= 0;         m[11]= 0;         m[15]= 1.0;

poRenderer->setMatrix(kMatrixModelview, m);
}```
rotateInPlane is...

Code:
```// rotate 2 vectors in the plane they span
void rotateInPlane(CVector3 &vA, CVector3 &vB, float fAngle) {
float	fCos= cos(fAngle);
float	fSin= sin(fAngle);
CVector3	vTemp;

// calc temp vector between vA and vB in their plane.
// this will be vA later, but we can't yet overwrite it
// since we still need it for vB
vTemp.x=	 fCos *vA.x +fSin *vB.x;
vTemp.y=	 fCos *vA.y +fSin *vB.y;
vTemp.z=	 fCos *vA.z +fSin *vB.z;

// same for vB but -90 degrees
vB.x=		-fSin *vA.x +fCos *vB.x;                  // cos(f+90)=-sin(f) to reduce cos/sin usage
vB.y=		-fSin *vA.y +fCos *vB.y;
vB.z=		-fSin *vA.z +fCos *vB.z;

// now update vA
vA= vTemp;
}```
That works pretty well. Do you see any lock problems here ?