2

I'm trying to set up a 3D camera with the gluLookAt method. So I have got a 10x10x10 cube and now i want to move the camera inside that cube. I have something like that:

gluLookAt( camera->x,camera->y,camera->z, camera->eyeX, camera->eyeY, camera->eyeZ, 0, 1, 0 );

now I'm moving forward/backward:

if(GetKeyState(VK_UP) <0)
               {    
                    camera->x += sin(camera->angleX)*0.1f;
                    camera->eyeX += sin(camera->angleX)*0.1f;               
                    camera->z -= cos(camera->angleX)*0.1f;
                    camera->eyeZ -= cos(camera->angleX)*0.1f;
            }

now I'm rotating left/right:

if(GetKeyState(VK_LEFT) <0)
            {   
                camera->angleX -=0.1f;
                camera->eyeX = sin(camera->angleX) +camera->x;
                camera->eyeZ = -cos(camera->angleX) + camera->z;
            }

So that all works perfectly but now i want to rotate up/down while the SHIFT button is pressed. So i have something like that:

if(GetKeyState(VK_SHIFT) <0)
            {   
                if(GetKeyState(VK_UP)<0)
                {
                    camera->angleY +=0.1f;                  
                    camera->eyeY = sin(camera->angleY) +camera->y;                  
                }

And actually something strange happens. The camera keeps bouncing up and down all the time and slowly moving forward. Additionaly I want to add that when I look up and move forward the camera actually goes there where it looks. So basicaly the situation looks like that: I'm a ghost trapped in a 10x10x10 cube and can walk wherever I want. I want to move to the upper right corner? I JUST GO THERE. So... any ideas what should I change/add?

L3M0L
  • 429
  • 8
  • 23

1 Answers1

3

EDIT: I am starting my reply from scratch as I may have assumed too much familiarity with the subject.

The problem you are facing is that your formulas are basically not correct : your formula for rotating left/right are correct under the assumption that the "up" vector (the vector pointing upward from the camera) is always [0 1 0]... which is not the case if you also want to rotate up/down. And your formula for rotating up down is not correct since it only modifies the Y component and rotations do not work that way.

The correct way to handle that is:

  • to store 3 variables that represent the camera position (as you did). Let's call them Px, Py, Pz
  • to store 3 variables that represent the camera view direction (instead of your eyeX/Y/Z that encode the point the camera is looking at). Let's call them Vx, Vy, Vz
  • to store 3 variables that represent the camera right vector (or up vector, as you wish). Let's take the right vector, and call it Rx, Ry, Rz.

Alternatively, you can have a nice "Vector" class that represent vectors instead of storing 3 variables each time. This is a detail at this point.

Now, your method to move your camera forward just becomes:

Px += Vx;
Py += Vy;
Pz += Vz;

You can use, for example, Rodrigues formula to rotate (hoping nobody will launch at you the "quaternion" magic word to express their cleverness ;) ). The general self-contained code to rotate around an arbitrary axis would then be:

// rotate the vector (vx, vy, vz) around (ax, ay, az) by an angle "angle"

void rotate(double &vx, double &vy, double &vz, double ax, double ay, double az, double angle) {
  double ca = cos(angle);
  double sa = sin(angle);
  double crossx = -vy*az + vz*ay;
  double crossy = -vz*ax + vx*az;
  double crossz = -vx*ay + vy*ax;
  double dot = ax*vx + ay*vy + az*vz;
  double rx = vx*ca + crossx*sa + dot*ax*(1-ca);
  double ry = vy*ca + crossy*sa + dot*ay*(1-ca);
  double rz = vz*ca + crossz*sa + dot*az*(1-ca);
  vx = rx; 
  vy = ry; 
  vz = rz;
}

And make sure to keep normalized coordinates for your camera vectors.

Now, to specifically rotate your camera up/down when you press a button:

// rotate up:
rotate(Vx, Vy, Vz, Rx, Ry, Rz, some_CONSTANT_angle);
// rotate down:
rotate(Vx, Vy, Vz, Rx, Ry, Rz, - some_CONSTANT_angle);

To rotate left/right, you first need to compute the "Up" vector that doesn't need to be stored (unless you want to, but it is redundant), and rotate both your view direction and right vectors:

// find up vector using a cross product:
  double Ux = Ry*Vz - Rz*Vy;
  double Uy = Rz*Vx - Rx*Vz;
  double Uz = Rx*Vy - Ry*Vx;

//rotate left
    rotate(Rx, Ry, Rz, Ux, Uy, Uz, some_CONSTANT_angle);
    rotate(Vx, Vy, Vz, Ux, Uy, Uz, some_CONSTANT_angle);
// rotate right
    rotate(Rx, Ry, Rz, Ux, Uy, Uz, - some_CONSTANT_angle);
    rotate(Vx, Vy, Vz, Ux, Uy, Uz, - some_CONSTANT_angle);

Setting up your camera matrix now becomes:

  gluLookAt( Px, Py, Pz, Px+Vx, Py+Vy, Pz+Vz, Rx, Ry, Rz); // or is it Ux, Uy, Uz at the end? don't remember.

Of course, I didn't test any of this code, and wrote it now. Hope it works!

nbonneel
  • 3,286
  • 4
  • 29
  • 39
  • I try to do something with the up vector however I don't think that's the problem... I woulrd rather say I'm missing something like camera->y = and camera->eyeY = Any other ideas what i might add/change? – L3M0L Apr 07 '13 at 10:05
  • I actually changed to: camera->eyeY = tan(camera->angleY) +camera->y; and it's not bouncing anymore but now i want to move in that direction. Any ideas? – L3M0L Apr 07 '13 at 10:47
  • moving in the direction of the camera consists in adding the components of eyeX-x, eyeY-y and eyeZ-z to the camera coordinates x,y,z – nbonneel Apr 07 '13 at 16:48
  • Sorry for my late response... but i was busy coding my Asteroid game (deadline) Well... actually I don't get it quite well... I do understand what you mean with the " doing that also destroys the eyeX variable that you just updated when moving left/right." and therefore i asume the whole "thinking" with the cos and sin like in a 2D game is useless right? However i dont get your formula X' = x*cos(theta)-y*sin(theta) (and the Y') could you explain it better... like for a total newbie? Maybe provide some links or code? It would be great! :) – L3M0L Apr 09 '13 at 10:47
  • I'll update my answer later today. But by "destroys the eyeX" variable, I mean that when you rotate to the left, you're changing the variable eyeX to a particular value. This value is not preserved when you use the first code to rotate up/down. Hence the second formula that appropriately preserves the value. – nbonneel Apr 09 '13 at 18:28
  • I know what you mean with the destroy eyeX :) The problem is where does the other formula come from? How does it exactly look? Do i have to change something in the gluLookAt method?(i don't get this: adding the components of eyeX-x, eyeY-y and eyeZ-z for example :P ) If you would provide some links, examples something that would be really great and helpfull :) – L3M0L Apr 09 '13 at 19:59
  • ouch sorry... I'm still busy today for a deadline ; I'll promise I'll get back to you! :s These formula basically just come from standard rotation formulas (see http://en.wikipedia.org/wiki/Rotation_(mathematics) for example) and are just applied to the current view direction. An even better way is to use Rodrigues' formula. I'll improve my answer. – nbonneel Apr 12 '13 at 19:04
  • I re-wrote entirely my answer with some code. Hope this helps! – nbonneel Apr 14 '13 at 00:29
  • Hmmm, there is either something wrong with this formula (I mean your code) or I'm doing something wrong... I created a Vector class where i have double x,y,z then I normalize them. Here's my first question: What should I do when I have a zero vector? How to normalize it? The lenght of a zero vector is 0 and we can't divide by 0 :/ ) My next step is to create a camera class having the P, V and R with the normalized values then I put everything together like shown in your code (the rotate func and the gluLookAt) and... something is working however thats definitely not that what it should be – L3M0L Apr 14 '13 at 14:38
  • You should never have a zero vector : the view direction and right direction should never be zero (you start for example with (0, 0, 1) and (1, 0, 0) respectively, and rotating them will never make them zero). However, the camera position (Px, Py, Pz) should never be normalized, of course. What does your code produce ? – nbonneel Apr 14 '13 at 20:10
  • I just changed a sign which I think was wrong in the rotation formula. – nbonneel Apr 14 '13 at 20:15
  • I changed now the sign and the Px, Py and Pz coordinates (cuz they were also normalized in my code) and now... woah... the effect is crazy... well I don't know how to explain it... emm lets say when i try to rotate left it starts rotating left but then it goes back and starts rotating right and then left again (repeat until key pressed :P ). When I move forward is ok but when I rotate and then move forward... then magic happens and bassicaly its hard to control the camera in any way :/ – L3M0L Apr 14 '13 at 20:57
  • note the "some_CONSTANT_angle" in the code. It should be a small value like 0.02. It should not be a variable called "angle" that is incremented each time ; it should really be constant. My guess is that it's your issue... – nbonneel Apr 14 '13 at 22:04
  • I know, I have it at 0.1 and changing it to 0.02 doesnt change much ;) – L3M0L Apr 14 '13 at 22:28
  • I briefly tested my code : http://ideone.com/Y8oDtx (codepad seems to be down right now) and it seems to produce correct results, so I think you have either copied it wrong, or do not understand what it does (which I think is the case if you tried to normalize the camera position). Try to remove any normalization, and test at every frame the dot product between all vectors (V, U and R): they should always be 0 or 1. If you want to slow down your camera when you move, just do Px+=0.01*Vx; (same for y and z). To my knowledge, the code above is correct. Try to understand the code first. – nbonneel Apr 15 '13 at 02:36
  • Ok, your code seems to work better than mine which is strange because mine looks almost the same in general (but it's more object oriented, I look for mistakes in my code later today) HOWEVER! I implemented your code in my OpenGL file and it seems to work BUT not in 100% the way I wanted... I guess... somehow I have the illusion that sometimes the camera does not go there where I want, maybe just an illusion.. I will test the program better later today. For now I will say that the problem is SOLVED. Thanks a lot man! And sorry for my newbie questions and behavior ;) WILL TRY TO IMPROVE MYSELF! – L3M0L Apr 15 '13 at 08:17
  • I think the problem is my gluPerspective... that's where the illusion comes from. I will try to fix it later :) Again, thanks a lot for all the helpful informations! :) – L3M0L Apr 15 '13 at 11:52