Disegnare ed Animare Oggetti con OpenGL

Nella scorsa lezione di questo corso su OpenGL abbiamo introdotto la piattaforma ed abbiamo presentato le librerie principali con cui lavoreremo. Esistono principalmente due approcci per programmare con OpenGL: il primo è quello di appoggiarci a GLUT ed avere una finestra basilare per le piccole applicazioni, il secondo è quello di integrare OpenGL nella programmazione standard del nostro gestore di finestre. All’inizio del corso svilupperemo dei semplici esempi su GLUT, mentre nella seconda parte del corso, quando parleremo di argomenti più complessi, creeremo i disegni 3D nelle finestre create per il nostro gestore standard.
La programmazione in un ambiente grafico, sia esso Windows o Linux, ha come punto focale la gestione degli eventi. In particolare l’applicazione avrà un determinato comportamento a seconda della pressione di un particolare tasto o lo scatenarsi di altro evento di sistema. La strutturazione di un’applicazione assumerà la forma di un ciclo infinito e di tanto in tanto verrà controllata la coda dei messaggi dell’applicazione affinché la stessa possa comportarsi in determinati modi. Questo ciclo viene chiamato event-loop, che GLUT fornisce di default, a noi solo il compito di scrivere il programma di disegno.

// File FirstWin.cpp

#include "GL/glut.h"

float fStep, fPos;

void Init()
{
    fStep = 0.1f;
    fPos = 0.0f;
    glClearColor(0.0, 0.0, 0.0, 0.0);
    glShadeModel(GL_FLAT);
    glEnable(GL_DEPTH_TEST);
}

void Draw()
{
    glClear(GL_COLOR_BUFFER_BIT|GL_DEPTH_BUFFER_BIT);

    glColor3f(0.0, 1.0, 0.0);
    glBegin(GL_TRIANGLES);
     glVertex3f(-45.0, 0.0, 0.0);
     glVertex3f(-35.0, -20.0, 0.0);
     glVertex3f(-35.0, 20.0, 0.0);
     glVertex3f(45.0, 0.0, 0.0);
     glVertex3f(35.0, 20.0, 0.0);
     glVertex3f(35.0, -20.0, 0.0);
    glEnd();
    glColor3f(1.0, 0.0, 0.0);
    glRectf((GLfloat)(-10.0 + fPos), -10.0,
         (GLfloat)(10.0 + fPos), 10.0);
    glutSwapBuffers();
}

void Resize(int iWidth, int iHeight)
{
    glViewport(0, 0, (GLsizei)iWidth, (GLsizei)iHeight);
    glMatrixMode(GL_PROJECTION);
    glLoadIdentity();
    glOrtho(-50.0, 50.0, -50.0, 50.0, -1.0, 1.0);
    glMatrixMode(GL_MODELVIEW);
    glLoadIdentity();
}

void Animation()
{
    fPos += fStep;
    if (fPos > 30.0)
        fStep = -0.1f;
    if (fPos < -30.0)
        fStep = 0.1f;
    glutPostRedisplay();
}

void KeyPress(unsigned char uKey, int x, int y)
{
     if (uKey == 'q')
        glClearColor(0.0, 0.0, 0.0, 0.0);
    else if (uKey == 'w')
        glClearColor(0.0, 1.0, 1.0, 0.0);
    else if (uKey == 'e')
        glClearColor(1.0, 1.0, 0.0, 0.0);
     if (uKey == 'a')
        glutIdleFunc(Animation);
    else if (uKey == 'z')
        glutIdleFunc(NULL);
    glutPostRedisplay();
}

int main(int argc, char** argv)
{
    glutInit(&argc, argv);
    glutInitDisplayMode(GLUT_DOUBLE|GLUT_RGB|GLUT_DEPTH);
    glutInitWindowSize(350, 350);
    glutInitWindowPosition(100, 100);
    glutCreateWindow("OpenGL - Prima Esperienza");
    Init();
    glutDisplayFunc(Draw);
    glutReshapeFunc(Resize);
    glutKeyboardFunc(KeyPress);
    glutMainLoop();
}

In questo semplice esempio viene aperta una finestra e disegnati due triangoli verdi con un quadrato centrale rosso, con i tasti “q”, “w” ed “e” si cambia il colore di sfondo, mentre con i tasti “a” e “z” rispettivamente si inizia e ferma il movimento del quadrato tra i due triangoli.
Nella funzione main abbiamo la creazione della finestra con doppio buffer, la gestione dei colori RGB e il depth-buffer. Il doppio buffer serve ad un’applicazione grafica per una migliore gestione del disegno: si disegna sul buffer in memoria e poi quando pronto si sostituisce ( swap )  al visibile e via di questo ciclo.
Gli eventi gestibili tramite GLUT sono numerosi e vengono gestiti attraverso alcune funzioni che accettano come argomento funzioni callback:

  • glutKeyboardFunc – Specifica quale funzione gestirà l’input da tastiera, la funzione dovrà avere come parametri un unsigned char che conterrà il tasto premuto e due int che restituiranno le coordinate del mouse alla pressione del tasto.
  • glutMouseFunc – Funzione che gestisce la pressione del mouse e dovrà avere tre parametri di tipo int, che indicheranno lo stato dei tasti del mouse tramite le costanti GLUT_LEFT_BUTTON, GLUT_RIGHT_BUTTON e le coordinate al momento del click.
  • glutReshapeFunc – Specifica la funzione che verrà eseguita tutte le volte che la finestra verrà ridimensionata, con due parametri int a indicare le nuove dimensioni.
  • glutDisplayFunc – Specifica la funzione che servirà per il tracciamento della finestra, qui infatti va inserito il codice per il disegno.
  • glutIdleFunc – Specifica la funzione che andrà in esecuzione in assenza di eventi da gestire, il suo uso principale è nelle animazioni.

Per un buon disegno è prima necessario cancellare il contenuto del buffer nel quale andremo a disegnare: questo avviene con la funzione glClear che azzera il depth-buffer e riempie il buffer di disegno con il colore che è stato specificato in precedenza con il comando glClearColor. Il colore che viene utilizzato per il disegno è specificato tramite il comando glColor3f. Al termine del disegno nel buffer si alterna con il video tramite la funzione glutSwapBuffers.
L’animazione è ottenuta semplicemente inserendo una funzione in idle e poi congelarla inserendo un valore nullo. Il programma presentato può sembrare scarno, ma farà da base per i prossimi esempi che faremo in quanto contiene tutti gli elementi più comuni di OpenGL. Per ora basta avere una visione d’insieme e generale, nel prosecuzione del corso analizzeremo i vari aspetti delle librerie parlando delle primitive grafiche.

<< Lezione PrecedenteLezione Successiva >>

Di Giampaolo Rossi

Sviluppatore software da oltre 16 anni.

2 commenti

  1. bel programmino semplice semplice ma che introduce subito all’uso delle opengl . Hai tuttavia commesso un’errore di sintassi… ” glutInit(&argc, argv); ” giusto è “glutInit(&argc, argv);”

    1. Non era un errore. Si trattava dell’editor di WordPress che fa questo in automatico passando dal sorgente dell’articolo all’anteprima, comunque ho sistemato.

I commenti sono chiusi.