Skip to main content
GameDev.net gamedev.net
🔒 Locked

gluLookAt problem

Started by tre Mar 20, 2009 at 11:08 AM 13 replies 3.3k views
Original Post
tre
tre
Searching this forum I found a thread with a link to www.ultimategameprogramming.com which would contain a tutorial on gluLookAt and camera movement but the site is down. I have some problems with my gluLookAt function. It skips around when moving the camera. The desirable behaviour is for the camera to move in the x, y, z-directions when pressing the right mouse button and moving the mouse. This is working. Sort of. It's like the camera has decided to skip way too many degrees when moving the mouse. Code snippets regarding the camera: Global

#define PI		(3.14159265359f)
#define DEG2RAD(a)	(PI/180*(a))
#define EYE_RADIUS	40.0f

int dx;
int dy;
void RightMouseMove(int dx, int dy);

float m_fRotTheta 	= 0;
float m_fRotPhi		= 0;

int DrawGLScene(GLvoid)

float 	fEyeX = EYE_RADIUS * cos(m_fRotTheta) * sin(m_fRotPhi),
        fEyeY = EYE_RADIUS * sin(m_fRotTheta) * sin(m_fRotPhi),
	fEyeZ = EYE_RADIUS * cos(m_fRotPhi);

gluLookAt(fEyeX, fEyeY, fEyeZ,  0.0f, 0.0f, 0.0f,  0.0f, -1.0f, 0.0f);

m_fRotTheta += DEG2RAD((float)dx/3.0f);
m_fRotPhi   += DEG2RAD((float)dy/3.0f);

LRESULT CALLBACK

case WM_RBUTTONDOWN:
	bMouseRBDown = true;
	return 0;
			
			
case WM_RBUTTONUP:
	bMouseRBDown = false;
	return 0;

		
case WM_MOUSEMOVE:
	if(bMouseRBDown){
		RightMouseMove(LOWORD(lParam), HIWORD(lParam));
	}
	iOldMouseX = LOWORD(lParam);
	iOldMouseY = HIWORD(lParam);

I guess you can tell what a newbie I am :) Still, I'm learing fast but I just can't get a grip around this. Why is my camera skipping around/rotating waaaaay too fast? I'm trying to get the camera to orbit a sphere (planet). If you need more code, just ask. Thanks! Marcus
zedz
zedz
Im not sure what u mean
It could be 'gimbal lock' (google)

or perhaps u want to do something like

m_fRotTheta += DEG2RAD((float)dx/3.0f);
m_fRotPhi += DEG2RAD((float)dy/3.0f);

dx *= 0.8;
dy *= 0.8;
tre
tre
Hi zedz,
I've now tried what you recommended, but I still can't get this to work.
I understand that it's difficult to get what I mean, it's sort of difficult to explain.

The movement of the camera is working, but not as expected. It skips around but in a perfect circle (no zooming in or out).
If I, for example, move the mouse down, the camera skips seemingly randomly. I could be watching Africa from space, when I move the mouse it skips to Greenland. This is not what I'm after. I want to smoothly move the camera to wherever I want.

The globe itself is spinning and being lit by "the sun" and rotating the entire scene proved to give me more problems than trying to just move the gluLookAt-camera.
knighty
knighty
What exactly does RightMouseMove()?

According to MSDN:
Quote:

lParam
The low-order word specifies the x-coordinate of the cursor. The coordinate is relative to the upper-left corner of the client area.

The high-order word specifies the y-coordinate of the cursor. The coordinate is relative to the upper-left corner of the client area.


It's up to you to find the bug now ;)
tre
tre
Quote:
Original post by knighty
What exactly does RightMouseMove()?

According to MSDN:
Quote:

lParam
The low-order word specifies the x-coordinate of the cursor. The coordinate is relative to the upper-left corner of the client area.

The high-order word specifies the y-coordinate of the cursor. The coordinate is relative to the upper-left corner of the client area.


It's up to you to find the bug now ;)


That did the trick! :)
I had forgotten to subtract the old position.

However, this generated something else. I think my up value in gluLookAt ...

[edit]Never mind. I think I just messed up the dy, dx values in RightMouseMove().

This is great! I'm finally making progress :) Now... gameplay[/edit]
tre
tre
I've been wrestling with two other problems since the last one got solved.
The first one was that X and Y became inverted on the negative side of the sphere, that is now solved with a few if-statements. If you have a better solution, please let me know.

The last one, that I can't bend my mind around is that if the camera is at any position from (0, 0) to (6.0, 0.0), I can't rotate the camera on the Y axis.
Think of the sphere as two hemispheres (|), the line in the middle is where the sun creates night and day. On this line, the camera refuses to rotate on the Y axis and is actually striving to a 0.0f value on m_fRotPhi.
So rotating the camera around the poles, for example, isn't working, if I position the camera close to the poles and rotate on the X axis the camera drops on the Y axis so that X can become 0.0f.
The value of the Y axis (m_fRotTheta) is still incrementing! Which is really weird since the camera is moving down, which in a normal case would be a decrementing action.

There's something I'm not getting.
I've been touching up on my trigonometry, but I don't know if this is a problem with my trig calculations in the code or if it's an erratic behaviour of gluLookAt.

I hope you can help me with this as well.

All the best,
Marcus
tre
tre
Allright!
It was as I thought, the calculation of fEyeY was wrong. I needed to multiply by cos() and not sin(). It took a good god damn long time to figure out, though. Guess I was a bit tired.

Now I'm heading to the math forum with my next question (something else went wrong when I changed sin to cos... now I'm zooming in and out by moving on the X-axis :))) ).

Thanks to everyone who's been helping.

Take care!
tre
tre
And I'm back.
I wonder if someone could point me in the direction of a good resource for Euler to Quaternion convertions?

After asking in the math forums I found out that I'm indeed facing a gimbal lock. Great! Now, I've just got to solve it. I'm having trouble writing functions for converting my fEyeX, fEyeY and fEyeZ values into quaternion values and the information I'm reading doesn't have any real examples.

I hope someone can help.
knighty
knighty
From the red book (chapter 3):
To read and understand

There you will find all what you need. Quaternions are not necessary for an orbiting camera.
tre
tre
@knighty
I see. Thanks! I've now got a working camera!
This project is growing, though, so I think I might look into quaternions anyway since I guess that understanding them and being able to use them practically will help further on.
I'm looking at either some sort of space rts or something in the line of that nuke-the-planet game.

I'm having real fun with my first OpenGL program. It's taking a lot of studying and late nights, but I'm finding that the rewards of picking off the problems are well worth it.

I'll probably be back with more questions, haha :)

All the best,
Marcus
tre
tre
This is insane!
Now I'm getting errors with my code based on knighty's recommendations as well. And I've done absolutely nothing with this code.

The same problem has risen to the occation again in my new "testing" program.
If I'm at Y 1.5 and trying to cross X on 0 or 3.0, Y moves towards 0 and when I'm trying to compensate for this by moving up on Y again, nothing happens until I move positive or negative from X 0.
gluLookAt error

The blue line is where I want to go, the red line is what actually happens.

My quaternation conversions are going nowhere since I can't find any decent information on quats. I could really need a good tutorial with C++ source code to read and follow.
Does anyone know of any tutorials/lessons of that kind? Doesn't seem like NeHe has anything.

Man, this is annoying.

[Edited by - tre on March 26, 2009 2:56:08 AM]
knighty
knighty
gluLookAt() sucks at the poles ;=))

I think that is what you need (From the red book. chapter 3):


Suppose your application involves orbiting the camera around an object that's centered at the origin. In this case, you'd like to specify the viewing transformation by using polar coordinates. Let the distance variable define the radius of the orbit or how far the camera is from the origin. (Initially, the camera is moved distance units along the positive z-axis.) The azimuth describes the angle of rotation of the camera about the object in the xy-plane, measured from the positive y-axis. Similarly, elevation is the angle of rotation of the camera in the yz-plane measured from the positive z-axis. Finally, twist represents the rotation of the viewing volume around its line of sight.

Show that the following routine could serve as the viewing transformation:

void polarView{GLdouble distance, GLdouble twist,   		      GLdouble elevation, GLdouble azimuth){   glTranslated(0.0, 0.0, -distance);   glRotated(-twist, 0.0, 0.0, 1.0);   glRotated(-elevation, 1.0, 0.0, 0.0);   glRotated(azimuth, 0.0, 0.0, 1.0);}

[/quote]

In that function you can simply give a zero value to twist or just remove it.
Here the elevation angle is the angle between the line of sight and the positive z axis so if elevation==0.0 you will see the globe from above and if elevation==0.5*PI you will face the equator.

For the azimuth: I would personally rather do: glRotated(-azimuth... you can try both and decide wich is more "natural".
Because you are rendering a globe (nice picture btw ;) I gess you want (when your programm starts) to be facing latitude==0 and longitude==0. then your initial values should be: elevation=0.5*PI and azimuth=PI.

Now You need to limit the values of elevation to [0.0, PI] if you don't want your globe to be upside down.

I've told you that quaternions are not necessary! :)

You should also re-think the way you retrive elevation (phi) and azimuth (theta).
tre
tre
Okay, that was very different from the transformation I got from reading that chapter, where did you even find that text? I thought I read through it all. Let's say I was tired and leave it at that? ;)

This was exactly what I needed. I will read through this again and implement it and make sure I understand it before moving on.

You said I should rethink the way I'm getting phi and theta, what other ways are there than getting the X and Y values from WM_MOUSEMOVE?
I recently restructured my code and now I'm loading a structure with a bool value if the mouse is moving and also storing the X and Y positions in it. I've also got a "left click" check and a "right click" check (booleans) in there.

Knighty, I'm really grateful, thank you a thousand times. I've been wrestling with this camera for way too long.
knighty
knighty
You're welcome.

Quote:

You said I should rethink the way I'm getting phi and theta, what other ways are there than getting the X and Y values from WM_MOUSEMOVE?


I was thinking about our first code.

This is a sketch of the way I do it (I'm not a professionnal programmer, not even a good one, just to be clear):

In global scope:we declare static globals theta and phi and initialize them properly.In the message loop: -On Mouse left button down:   dragging=true    save current mouse position (say: cmx,cmy)   save current theta and phi  (say: ltheta,lphi)-On Mouse left button up:   dragging=false-On Mouse move:   if (dragging):       current mouse position: mx,my       disx=mx-cmx; disy=my-cmy;       theta=ltheta+(disx*A) //A is a parameter to tweek       phi=lphi+(disy*B) // B: the same as A (they should be equal, I think)       clamp phi to [0 , PI]   endif

That's all.

There are many other ways to do it but this should suffice for now :)

Oh! BTW, this have nothing to do with OpenGL :P
tre
tre
That's how I did it when I just had reconstructed my code. Called external statics from the main.cpp file. Now I'm storing all the needed information in a typedef struct in much the same manner that NeHe stores the key presses and releases.
That way I can just call the adress of Mouse and get what's inside. It works really well and is easy to expand to take the MK_ commands as well. I hope it works as I think it will :)

Topic Locked

This topic has been locked by a moderator. New replies are not allowed.

Sign in to reply to this topic.