Public Group

# Cameras in a Spherical Game World

This topic is 2503 days old which is more than the 365 day threshold we allow for new replies. Please post a new topic.

## Recommended Posts

Hello everyone!

I've been working on a simple 3D game engine using SDL and OpenGL. There are a lot of things I would like to learn, but right now its the camera that has me stuck. So far I've been using a more-or-less FPS style camera, based on a spherical coordinate system with a fixed up direction.

What I'm trying to do is create a game world centered around a sphere, so that the player can walk on and fly around its surface. To make this work I need a camera that recognizes "up" as meaning "away from the origin" and "down" as meaning "toward the origin". So far my attempts to create such a camera have failed, and I haven't had any luck finding a discussion on how such a system should work.

A few notes before I continue:
- I'm using Z as the vertical axis, so X and Y are horizontal.
- I'm using spherical coordinates (R,E,M) to represent (Radial,Elevation,Azimuth).
- I know radians are more natural, so I will be phasing out the use of degrees in the near future.
- If possible I would like to understand gluLookAt() before trying another method.

Here is what I have so far:

The engine starts by turning the movement of the mouse into a set of spherical coordinates mouseE (elevation) and mouseM (azimuth). In this case radius is irrelevant. This part is working as intended:
 void Engine::OnMouseMove(int mX, int mY, double relX, double relY) { mouseM=mouseM-relX*mouseSpeed; mouseE=mouseE-relY*mouseSpeed; if (mouseM<0) {mouseM=mouseM+360;} if (mouseM>360) {mouseM=mouseM-360;} if (mouseE<-90) {mouseE=-90;} if (mouseE>90) {mouseE=90;} } 

Next the engine converts those spherical coordinates into cartesian coordinates, and prepares them for use with gluLookAt(). This part works well for flying around and viewing the game world, but it doesn't orient itself relative to the origin:
 //Render each frame using OpenGL void Engine::Render() { glEnable(GL_DEPTH_TEST); glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); glLoadIdentity(); //Set aimREM (relative) and aimXYZ (relative) aimR=100; aimE=mouseE*0.0174532925; aimM=mouseM*0.0174532925; aimX=aimR*cos(aimM)*cos(aimE); aimY=aimR*sin(aimM)*cos(aimE); aimZ=aimR*sin(aimE); //Offset aimXYZ by eyeXYZ aimX=aimX+eyeX; aimY=aimY+eyeY; aimZ=aimZ+eyeZ; //Prepare the Camera (eyeX,eyeY,eyeZ,aimX,aimY,aimZ,upX,upY,upZ) gluLookAt(eyeX,eyeY,eyeZ,aimX,aimY,aimZ,0,0,1); //Render XYZ Axes using RGB color code glBegin(GL_LINES); glColor3f(0.5,0.0,0.0); glVertex3f(0,0,0); glVertex3f(-50000000,0,0); glColor3f(1.0,0.0,0.0); glVertex3f(0,0,0); glVertex3f(50000000,0,0); glColor3f(0.0,0.5,0.0); glVertex3f(0,0,0); glVertex3f(0,-50000000,0); glColor3f(0.0,1.0,0.0); glVertex3f(0,0,0); glVertex3f(0,50000000,0); glColor3f(0.0,0.0,0.5); glVertex3f(0,0,0); glVertex3f(0,0,-50000000); glColor3f(0.0,0.0,1.0); glVertex3f(0,0,0); glVertex3f(0,0,50000000); glEnd(); glColor3f(1,1,1); //Render game objects here /* This is where the game objects go =) */ SDL_GL_SwapBuffers(); } 

I've been attempting to modify the camera so that up and down are relative to the origin. I think the simplest way to do this is to rotate the aim coordinates around the eye, based on its position relative to the sphere. That way, mouseE and mouseM would use the vector pointing from the origin to the eye in place of the Z axis, and the rest would fall into place. Unfortunately, I've tried multiple algorithms for this, and none of them have actually worked:
 //Render each frame using OpenGL void Engine::Render() { glEnable(GL_DEPTH_TEST); glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); glLoadIdentity(); //Convert eyeXYZ to spherical eyeREM eyeR=sqrt(pow(eyeX,2)+pow(eyeY,2)+pow(eyeZ,2)); eyeE=asin(eyeZ/eyeR); eyeM=atan2(eyeY,eyeX); //Calculate upXYZ based on eyeREM upX=cos(eyeM)*cos(eyeE); upY=sin(eyeM)*cos(eyeE); upZ=sin(eyeE); //Set aimREM (relative) and aimXYZ (relative) aimR=eyeR; aimE=mouseE*0.0174532925; aimM=mouseM*0.0174532925; aimX=aimR*cos(aimM)*cos(aimE); aimY=aimR*sin(aimM)*cos(aimE); aimZ=aimR*sin(aimE); //Rotate aimXYZ or aimREM to account for global position /* Pointing the mouse downward should look directly toward the origin Pointing the mouse upward should look directly away from the origin Horizontal motion should rotate the camera around the line from origin to eye */ //Offset aimXYZ by eyeXYZ aimX=aimX+eyeX; aimY=aimY+eyeY; aimZ=aimZ+eyeZ; //Prepare the Camera (eyeX,eyeY,eyeZ,aimX,aimY,aimZ,upX,upY,upZ) gluLookAt(eyeX,eyeY,eyeZ,aimX,aimY,aimZ,upX,upY,upZ); //Render XYZ Axes using RGB color code glBegin(GL_LINES); glColor3f(0.5,0.0,0.0); glVertex3f(0,0,0); glVertex3f(-50000000,0,0); glColor3f(1.0,0.0,0.0); glVertex3f(0,0,0); glVertex3f(50000000,0,0); glColor3f(0.0,0.5,0.0); glVertex3f(0,0,0); glVertex3f(0,-50000000,0); glColor3f(0.0,1.0,0.0); glVertex3f(0,0,0); glVertex3f(0,50000000,0); glColor3f(0.0,0.0,0.5); glVertex3f(0,0,0); glVertex3f(0,0,-50000000); glColor3f(0.0,0.0,1.0); glVertex3f(0,0,0); glVertex3f(0,0,50000000); glEnd(); glColor3f(1,1,1); //Render game objects here /* This is where the game objects go =) */ SDL_GL_SwapBuffers(); } 

Three dimensional geometry is relatively new to me, so I'm just trying to make sense of this, and make the camera work in the process. I've posed this as a programming question, but I suppose its really about rotating a spherical coordinate system. Either way, I'm just here to learn.

Any help would be greatly appreciated, especially if it clarifies the geometry of the situation. ~_^

1. 1
2. 2
3. 3
4. 4
Rutin
12
5. 5

• 26
• 10
• 9
• 9
• 11
• ### Forum Statistics

• Total Topics
633694
• Total Posts
3013378
×