Search code examples
openglglutglulookat

rotating camera in OpenGL using Glut libraries and gluLookAt


I am trying to implement a software in OpenGl which is able to draw a Lorenz system. I achieved my purpose but in a static way: the system is drawn once and that's all. Now I want to move my camera around the system and show the 3D-ness of the system itself. What I noticed is that I cannot update the drawn image because if I do update the points of the system, they keep changing in each update (Lorenz system is the result of mathematical equations, therefore I have big floats number as results). I then realized that I have to draw the system just once and then move the camera around it somehow. Unfortunately I don't know how to do it. I especially have problems in changing that gluLookAt call for my purposes. Let's say that I want to move the camera according to an input given by keyboard. Can you kindly help me? Here you can have a look to my simple code.

Initialization method:

void myinit() {
glClearColor(0.0f, 0.0f, 0.0f, 1.0f);
glColor4f(1.0f, 0.0f, 0.0f, 0.09f);

glEnable(GL_BLEND);
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);

glEnable(GL_POINT_SMOOTH);
glPointSize(1.0f);

glHint(GL_PERSPECTIVE_CORRECTION_HINT, GL_NICEST);  // Really Nice Perspective Calculations

glViewport(0, 0, 400, 400); //glViewport(0, 0, width_of_window_rendering_area, height_of_window_rendering area);

glMatrixMode(GL_PROJECTION);
glLoadIdentity();
gluPerspective(45.0f,  (GLfloat)400/400, 0.1, 100); //Sets the frustum to perspective mode, sets up the way in which objects

glMatrixMode(GL_MODELVIEW);
glLoadIdentity();
}

Drawing method

void mydisplay() {
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); //if perspective
glLoadIdentity();
gluLookAt(0.0, 0.0, 100.0,  //position
          0.0, 0.0, 0.0,  //where we are looking
          0.0, 1.0, 0.0); //up vector

glBegin(GL_POINTS);
for (int i = 0; i < iterations; i++) {
    if(i == 200000){
        glColor4f(1.0f, 0.0f, 0.0f, 0.09f);
    }
    if(i == 400000){
        glColor4f(1.0f, 0.0f, 1.0f, 0.09f);
    }
    if(i == 600000){
        glColor4f(0.0f, 0.0f, 1.0f, 0.09f);
    }
    if(i == 800000){
        glColor4f(0.0f, 1.0f, 1.0f, 0.09f);
    }

    // compute a new point using the strange attractor equations
    float xnew=x + h*(s*(y - x));
    float ynew=y + h*(x*(p - z) - y);
    float znew=z + h*(x*y - b*z);

    x = xnew;
    y = ynew;
    z = znew;

    glVertex3f(x, y, z);
}
glEnd();

glutSwapBuffers();
}

main

int main (int argc, char **argv){

glutInit(&argc,argv);

glutInitDisplayMode(GLUT_RGBA | GLUT_DOUBLE);

glutInitWindowSize(400, 400);
glutCreateWindow("Strange Attractors in C++ and OpenGL Tutorial");

glutDisplayFunc(mydisplay);
glutKeyboardFunc(mykey);

myinit();
glutMainLoop();

while(esc != true){
    glutDisplayFunc(mydisplay);
}
return 0;
}

This is the result:

prova


Solution

  • Use a timer callback to increment an angle and post a redraw:

    #include <GL/glut.h>
    #include <vector>
    
    struct Vertex
    {
        float x, y, z, w;
        float r, g, b, a;
    };
    std::vector< Vertex > verts;
    
    void fillVerts()
    {
        // calculate vertices
        // http://paulbourke.net/fractals/lorenz/
        double h = 0.01;
        double a = 10.0;
        double b = 28.0;
        double c = 8.0 / 3.0;
    
        Vertex cur;
        cur.a = 0.09f;
    
        double x0 = 0.1;
        double y0 = 0;
        double z0 = 0;
        for( unsigned int i = 0; i < 100000; i++ ) 
        {
            if(i == 20000)
            {
                cur.r = 1.0f;
                cur.g = 0.0f;
                cur.b = 0.0f;
            }
            if(i == 40000)
            {
                cur.r = 1.0f;
                cur.g = 0.0f;
                cur.b = 1.0f;
            }
            if(i == 60000)
            {
                cur.r = 0.0f;
                cur.g = 0.0f;
                cur.b = 1.0f;
            }
            if(i == 80000)
            {
                cur.r = 0.0f;
                cur.g = 1.0f;
                cur.b = 1.0f;
            }
    
            const double x1 = x0 + h * a * (y0 - x0);
            const double y1 = y0 + h * (x0 * (b - z0) - y0);
            const double z1 = z0 + h * (x0 * y0 - c * z0);
            x0 = x1;
            y0 = y1;
            z0 = z1;
    
            if( i > 100 )
            {
                cur.x = x0;
                cur.y = y0;
                cur.z = z0;
                verts.push_back( cur );
            }
        }
    }
    
    float angle = 0;
    void timer( int extra )
    {
        // spin
        angle += 0.5;
    
        glutPostRedisplay();
        glutTimerFunc( 16, timer, 0 );
    }
    
    void display(void)
    {
        glClear( GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT );
    
        glMatrixMode(GL_PROJECTION);
        glLoadIdentity();
        const double w = glutGet( GLUT_WINDOW_WIDTH );
        const double h = glutGet( GLUT_WINDOW_HEIGHT );
        gluPerspective( 60.0, w / h, 1.0, 10000.0 );
    
        glMatrixMode(GL_MODELVIEW);
        glLoadIdentity();
        gluLookAt( 70, 70, 70, 0, 0, 0, 0, 0, 1 );
    
        glRotatef( angle, 0, 0, 1 );
    
        // draw curve
        glEnableClientState( GL_VERTEX_ARRAY );
        glEnableClientState( GL_COLOR_ARRAY );
        glVertexPointer( 3, GL_FLOAT, sizeof( Vertex ), &verts[0].x );
        glColorPointer( 4, GL_FLOAT, sizeof( Vertex ), &verts[0].r );
        glDrawArrays( GL_LINE_STRIP, 0, verts.size() );
        glDisableClientState( GL_VERTEX_ARRAY );
        glDisableClientState( GL_COLOR_ARRAY );
    
        glutSwapBuffers();
    }
    
    int main( int argc, char **argv )
    {
        glutInit( &argc, argv );
        glutInitDisplayMode( GLUT_RGBA | GLUT_DEPTH | GLUT_DOUBLE );
        glutInitWindowSize( 800,600 );
        glutCreateWindow( "Attractor" );
    
        glutDisplayFunc( display );
        glutTimerFunc( 0, timer, 0 );
    
        fillVerts();
    
        glEnable( GL_BLEND );
        glBlendFunc( GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA );
    
        glEnable( GL_POINT_SMOOTH );
        glPointSize(1.0f);
    
        glutMainLoop();
        return 0;
    }
    

    It's also a good idea to calculate the point positions/colors ahead of time instead of in the display callback.