Featured Posts

8. Bump Mapping in GLSL8. Bump Mapping in GLSL Introduction Bump mapping is essential in todays computer games, and computer graphics in general. Would you like to know the best thing about it? It is extremely simple to implement. Bump mapping works...

Read more

Swiftless GLSL Shader DeveloperSwiftless GLSL Shader Developer Swiftless GLSL Shader Developer   Version 0.1a Currently Swiftless GLSL Shader Developer is in it's first public release, and is currently in alpha status, meaning it is not complete and may contain...

Read more

Wordpress Optimization Wordpress Website Optimizations Introduction Wordpress itself is a fairly wonderful tool. Since switching to it, I find it is a lot quicker to make changes to my website and it is also quicker to get...

Read more

36. OpenGL Framebuffers36. OpenGL Framebuffers Introduction Frame buffers are one of those mythical things that we have all heard of, but many beginner OpenGL developers avoid because there is not much information about them, and they can be confusing...

Read more

1. Terrain Class1. Terrain Class Terrain is one of those things that so far, hasn't been perfectly recreated in computer graphics. But it is almost there! Looking over a beautiful landscape can be one of the most amazing feelings in the...

Read more

  • Prev
  • Next

24. OpenGL Camera Part 3

Posted on : 25-03-2010 | By : Swiftless | In : OpenGL

Tags: , , ,

10

In this OpenGL tutorial, we are going to look at creating a third person camera. I searched long and hard on the internet for a way to do this using my old calculations or something at least similar, but I had no luck, so here is what I hope you will find to be a simple way around creating this.

First off, we are going to start off with the code from the second camera tutorial. I am going to start this tutorial, by adding only one new variable for our program, this is going to be the distance that the camera will be from our character/target object:

float cRadius = 10.0f;

Next off, I am going to remove the camera() function. For our third person camera to work, we need to work our camera in two different parts, first is the part that centres the character, and the second part is the part that draws the scenery, so one camera function is not sufficient as our camera code goes around our other code.

The first thing we need to do after our glLoadIdentity call, is to translate our camera behind our character/target by our cRadius value like so:

glTranslatef(0.0f, 0.0f, -cRadius);

Running this, you will see a red square in front of the view. Although now we need to add some rotation ^_^ The next line here is going to rotate our view for *both* our character and our scenery, upon creating this tutorial, it is this little bit that kept messing me up, I had seperate glLoadIdentity calls for our character camera, and our scene camera, but I realised I had to combine the two. This is going to rotate the view on the x axis so you can look down and up around the character (including seeing the top and bottom of the character):

glRotatef(xrot,1.0,0.0,0.0);

The next section of code in this tutorial is just to draw our character, we do this like so:

glColor3f(1.0f, 0.0f, 0.0f);
glutSolidCube(2); //Our character to follow

Now we need to rotate the camera on our y axis to look around the world. In this tutorial, the character/target rotates with the view so you will only ever see the back of it unless you look up and over the character:

glRotatef(yrot,0.0,1.0,0.0); //rotate our camera on the y-axis (left and right)

After this, we need to move our scene like in our previous tutorials, only this time, we are removing the ypos value, this will move the scenery as if you were using a first person camera, but because of the previous rotations and translations, our character/target will always be in the centre of the view:

glTranslated(-xpos,0.0f,-zpos); //translate the screen to the position of our camera

Then finally we just draw all our cubes ^_^

glColor3f(1.0f, 1.0f, 1.0f);
cube(); //call the cube drawing function

This camera not only supports basic movement, it also keeps in tact our strafing movements ^_^ I am still yet to add jumping, running and a bobbing effect (using cycloids).

If you have any questions, email me at swiftless@gmail.com

1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
14.
15.
16.
17.
18.
19.
20.
21.
22.
23.
24.
25.
26.
27.
28.
29.
30.
31.
32.
33.
34.
35.
36.
37.
38.
39.
40.
41.
42.
43.
44.
45.
46.
47.
48.
49.
50.
51.
52.
53.
54.
55.
56.
57.
58.
59.
60.
61.
62.
63.
64.
65.
66.
67.
68.
69.
70.
71.
72.
73.
74.
75.
76.
77.
78.
79.
80.
81.
82.
83.
84.
85.
86.
87.
88.
89.
90.
91.
92.
93.
94.
95.
96.
97.
98.
99.
100.
101.
102.
103.
104.
105.
106.
107.
108.
109.
110.
111.
112.
113.
114.
115.
116.
117.
118.
119.
120.
121.
122.
123.
124.
125.
126.
127.
128.
129.
130.
131.
132.
133.
134.
135.
136.
137.
138.
139.
140.
141.
142.
143.
144.
145.
146.
147.
148.
149.
150.
151.
152.
153.
154.
155.
156.
157.
158.
159.
160.
161.
162.
163.
164.
165.
166.
167.
168.
169.
170.
171.
172.
173.
174.
175.
176.
  #include <GL/gl.h>
#include <GL/glut.h>
#include <stdlib.h>
#include <math.h>

//angle of rotation
float xpos = 0, ypos = 0, zpos = 0, xrot = 0, yrot = 0, angle=0.0;

float cRadius = 10.0f; // our radius distance from our character

float lastx, lasty;

//positions of the cubes
float positionz[10];
float positionx[10];

void cubepositions (void) { //set the positions of the cubes

    for (int i=0;i<10;i++)
    {
    positionz[i] = rand()%5 + 1;
    positionx[i] = rand()%5 + 1;
    }
}

//draw the cube
void cube (void) {
    for (int i=0;i<10 - 1;i++)
    {
    glPushMatrix();
    glTranslated(-positionx[i + 1] * 10, 0, -positionz[i + 1] *
10); //translate the cube
    glutSolidCube(2); //draw the cube
    glPopMatrix();
    }
}

void init (void) {
    cubepositions();
}

void enable (void) {
    glEnable (GL_DEPTH_TEST); //enable the depth testing
    glEnable (GL_LIGHTING); //enable the lighting
    glEnable (GL_LIGHT0); //enable LIGHT0, our Diffuse Light
    glEnable (GL_COLOR_MATERIAL);
    glShadeModel (GL_SMOOTH); //set the shader to smooth shader

}

void display (void) {
    glClearColor (0.0,0.0,0.0,1.0); //clear the screen to 
black

    glClear (GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
//clear the color buffer and the depth buffer
    enable();
    
    glLoadIdentity();
    
    glTranslatef(0.0f, 0.0f, -cRadius);
    glRotatef(xrot,1.0,0.0,0.0);
    glColor3f(1.0f, 0.0f, 0.0f);
    glutSolidCube(2); //Our character to follow
    
    glRotatef(yrot,0.0,1.0,0.0);  //rotate our camera on the 
y-axis (up and down)

    glTranslated(-xpos,0.0f,-zpos); //translate the screen
 to the position of our camera

    glColor3f(1.0f, 1.0f, 1.0f);
    cube(); //call the cube drawing function

    glutSwapBuffers(); //swap the buffers
    angle++; //increase the angle
}

void reshape (int w, int h) {
    glViewport (0, 0, (GLsizei)w, (GLsizei)h); //set the viewport
 to the current window specifications

    glMatrixMode (GL_PROJECTION); //set the matrix to projection

    glLoadIdentity ();
    gluPerspective (60, (GLfloat)w / (GLfloat)h, 0.1, 100.0)
; //set the perspective (angle of sight, width, height, , depth
)

    glMatrixMode (GL_MODELVIEW); //set the matrix back to model

}

void keyboard (unsigned char key, int x, int y) {
    if (key==‘q’)
    {
    xrot += 1;
    if (xrot >360) xrot -= 360;
    }

    if (key==‘z’)
    {
    xrot -= 1;
    if (xrot < -360) xrot += 360;
    }

    if (key==‘w’)
    {
    float xrotrad, yrotrad;
    yrotrad = (yrot / 180 * 3.141592654f);
    xrotrad = (xrot / 180 * 3.141592654f);
    xpos += float(sin(yrotrad));
    zpos -= float(cos(yrotrad));
    ypos -= float(sin(xrotrad));
    }

    if (key==‘s’)
    {
    float xrotrad, yrotrad;
    yrotrad = (yrot / 180 * 3.141592654f);
    xrotrad = (xrot / 180 * 3.141592654f);
    xpos -= float(sin(yrotrad));
    zpos += float(cos(yrotrad));
    ypos += float(sin(xrotrad));
    }

    if (key==‘d’)
    {
    float yrotrad;
    yrotrad = (yrot / 180 * 3.141592654f);
    xpos += float(cos(yrotrad)) * 0.2;
    zpos += float(sin(yrotrad)) * 0.2;
    }

    if (key==‘a’)
    {
    float yrotrad;
    yrotrad = (yrot / 180 * 3.141592654f);
    xpos -= float(cos(yrotrad)) * 0.2;
    zpos -= float(sin(yrotrad)) * 0.2;
    }

    if (key==27)
    {
    exit(0);
    }
}

void mouseMovement(int x, int y) {
    int diffx=x-lastx; //check the difference between the 
current x and the last x position

    int diffy=y-lasty; //check the difference between the 
current y and the last y position

    lastx=x; //set lastx to the current x position
    lasty=y; //set lasty to the current y position
    xrot += (float) diffy; //set the xrot to xrot with the addition
 of the difference in the y position

    yrot += (float) diffx;    //set the xrot to yrot with the addition
 of the difference in the x position

}

int main (int argc, char **argv) {
    glutInit (&argc, argv);
    glutInitDisplayMode (GLUT_DOUBLE | GLUT_DEPTH);
    glutInitWindowSize (500, 500);
    glutInitWindowPosition (100, 100);
    glutCreateWindow (“A basic OpenGL Window);
    init ();
    glutDisplayFunc (display);
    glutIdleFunc (display);
    glutReshapeFunc (reshape);

    glutPassiveMotionFunc(mouseMovement); //check for mouse
 movement

    glutKeyboardFunc (keyboard);
    glutMainLoop ();
    return 0;
}

VN:F [1.9.3_1094]
Please rate so I know where to improve the site. 1 means needs a lot of improvement, 10 means perfect. If you leave a low rating, please state why. I don't want people just coming to bash the site.
Rating: 9.5/10 (4 votes cast)
VN:F [1.9.3_1094]
Rating: +2 (from 2 votes)
24. OpenGL Camera Part 3, 9.5 out of 10 based on 4 ratings

Related posts:

  1. 23. OpenGL Camera Part 2
  2. 22. OpenGL Camera
  3. 19. OpenGL Fullscreen Mode
  4. 4. Terrain Triangle Strips
  5. 2. Terrain Loading

Comments (10)

There is also another method that i found best for me. I used the gluLookAt() to get a good 3rd person view of an object. for instance (Just a snippet from a bigger game)

void UpdateCamera()
{
float yRadians = Player.yrot / 180 * 3.14159;
gluLookAt( Player.xpos – (sin(yRadians)), -0.4, Player.zpos + (cos(yRadians)),
Player.xpos, Player.ypos, Player.zpos, 0.0, 1.0, 0.0);
}
with the Player struct being global.

VN:F [1.9.3_1094]
Rating: 0.0/5 (0 votes cast)
VN:F [1.9.3_1094]
Rating: 0 (from 0 votes)

Hi Shadeirou,

Thats not a bad suggestion you have made there. When I get around to it, I am hoping to write a 4th camera tutorial on using quaternions instead of Eular angles.

You have probably heard of Gimbal lock, this is when your rotations along the different axis have gone in such a way that you lose one degree of freedom.

Therefore, looking straight up and down using this camera system, while it will mostly work, can fail miserably if you want to create something like a flight simulator.

Just a heads up if you plan to keep using this.

Cheers,
Swiftless

VN:F [1.9.3_1094]
Rating: 0.0/5 (0 votes cast)
VN:F [1.9.3_1094]
Rating: 0 (from 0 votes)

Forgot to put this in my last post: the variable “dist” is the distance you want that camera to move forward.

VA:F [1.9.3_1094]
Rating: 0.0/5 (0 votes cast)
VA:F [1.9.3_1094]
Rating: 0 (from 0 votes)

Hey, nice camera tutorials. Just wanted to make a quick suggestion. I was messing around with making a camera class myself and used the your forward movement formulas, but came across a problem: When you look straight up or down an move forward, you don’t move only up or down, but also forward a bit. I decided to do the math myself and came up with a fix. Here is the code I use:

float d = dist * cos( degreeToRadian( xrot ) );
origin_.x += d * cos( degreeToRadian( yrot + 90 ) );
origin_.y += dist * sin( degreeToRadian( xrot ) );
origin_.z += d * sin( degreeToRadian( yrot + 90 ) );

This causes the x and z distances to be affected by the x-axis rotation, or the roll. Take into account that I am using the following coordinate system:

glOrtho( 0, scene_w, scene_h, 0, 0, scene_l );

Anyway, just thought I’d see if this helped anyone.

VA:F [1.9.3_1094]
Rating: 0.0/5 (0 votes cast)
VA:F [1.9.3_1094]
Rating: 0 (from 0 votes)

Excellent website.

One thing, could you post a source file as copy and pasting of the code doesn’t compile straight away on Linux.

Whilst I know that it is necessary to write it yourself to learn how it all works and know how it works but using it as a temporary snippet so is a little bit of a pain.

REALLY good site though :)

Rich

VA:F [1.9.3_1094]
Rating: 0.0/5 (0 votes cast)
VA:F [1.9.3_1094]
Rating: 0 (from 0 votes)

Hi Richard,

Thanks for your feedback.

I used to have source files (and they still exist on the server), but I removed the links when I redid the site recently. I had someone else experience a copy and paste issue, because their IDE support rich text and it copied over the formatting, causing errors.

I am currently in the process of rewriting the tutorials, and it uses a code box, with a copy and paste safe ability, so I don’t see a point in putting the links back up and maintaining those files.

Cheers,
Swiftless

VN:F [1.9.3_1094]
Rating: 0.0/5 (0 votes cast)
VN:F [1.9.3_1094]
Rating: 0 (from 0 votes)

Hi Zero,

That is almost the exact way I check for multiple key presses at a time. I plan to write this into the Keyboard tutorial as I have had it asked before.

Cheers,
Swiftless

VN:F [1.9.3_1094]
Rating: 0.0/5 (0 votes cast)
VN:F [1.9.3_1094]
Rating: 0 (from 0 votes)

I just do this:
static bool keys[256];

void keyup(unsigned char key,int x,int y)
{
keys[key]=false;
}
void keydn(unsigned char key,int x,int y)
{
keys[key]=true;
}

and in main:

glutKeyboardUpFunc(keyup);
glutKeyboardFunc(keydn);

VA:F [1.9.3_1094]
Rating: 0.0/5 (0 votes cast)
VA:F [1.9.3_1094]
Rating: 0 (from 0 votes)

Doh’, its only use glutKeyboardUpFunc();

He he he..

Thank you..

VA:F [1.9.3_1094]
Rating: 0.0/5 (0 votes cast)
VA:F [1.9.3_1094]
Rating: 0 (from 0 votes)

Hi, do you know how to use glutKeyboardFunc and glutSpecialFunc to get two or more keys at same time?

Like press ‘W’ to go front and ‘D’ to go right?

Thank you..

Zero, from Brazil.

VA:F [1.9.3_1094]
Rating: 0.0/5 (0 votes cast)
VA:F [1.9.3_1094]
Rating: 0 (from 0 votes)

Write a comment

Improve the web with Nofollow Reciprocity.