OpenGL – Animazione

Prima di cominciare a spiegare il piccolo codice di esempio è importante fare qualche piccola premessa. La fluidità dell’animazione dipende dai frame per secondo (fps). I frame per secondo massimi dipendono dal refresh dello schermo. Gli schermi moderni vanno all’incirca a 60Hz, e quindi che in un secondo lo schermo proietta 60 immagini. Questo significa che ogni secondo possiamo rappresentare al massimo 60 immagini differenti e, quindi, possiamo avere al massimo 60fps.

Andare a 60fps, inoltre, significa che in un sessantesimo di secondo il nostro pc deve calcolare tutti i vertici dell’immagine successiva, inviarli alla scheda video e renderizzarli. Nel caso in cui l’elaborazione necessita più di un sessantesimo di secondo dobbiamo inserirci nell’intervallo successivo, ovvero due sessantesimi di secondo. In questo caso la nostra animazione crolla a 30fps (60/2). Se nemmeno due sessantesimi di secondo sono sufficienti allora passiamo a tre sessantesimi facendo abbassare i nostri fps a 20 (60/3) e così via.

Data la presenza di questi intervalli fissi il tempo di calcolo che “avanza” alla funzione Display viene occupato dalla funzione Idle. Questa è la funzione che viene eseguita quando nessun’altra funzione deve essere eseguita.

Il secondo punto è la presenza del doppio buffer. Usando un solo buffer infatti c’è il rischio che i vertici da visualizzare vengano modificati ancor prima di essere completamente renderizzati sullo schermo. Questo rischia di creare un fastidioso “effetto-fantasma” causato dalla coesistenza sullo schermo di due frame incompleti. Per ovviare a questo tutte le schede video moderne implementano il doppio buffer: secondo questo sistema un buffer viene utilizzato per la visualizzazione mentre il secondo viene utilizzato dal programma per immagazzinare i vertici del prossimo frame. Quando arriva il momento della visualizzazione questi due buffer vengono scambiati. In questo modo è garantito che vengano visualizzati solo frame completi.

from OpenGL.GLUT import *
from OpenGL.GL import *

spin = 0

def init():
    glClearColor(0,0,0,0)
    glShadeModel(GL_FLAT)

def display():
    glClear(GL_COLOR_BUFFER_BIT)
    glPushMatrix()
    glRotatef(spin, 0, 0, 1)
    glColor3f(1, 1, 1)
    glRectf(-25, -25, 25, 25)
    glPopMatrix()
    glutSwapBuffers()

def reshape(w, h):
    glViewport(0, 0, w, h)
    glMatrixMode(GL_PROJECTION)
    glLoadIdentity()
    glOrtho(-50, 50, -50, 50, -1, 1)
    glMatrixMode(GL_MODELVIEW)
    glLoadIdentity()

def spinDisplay():
    global spin
    spin += 0.5
    if spin > 360 :
        spin = spin - 360
    glutPostRedisplay()

def mouse(button, state, x, y) :
    if button == GLUT_LEFT_BUTTON :
        if state == GLUT_DOWN :
            glutIdleFunc(spinDisplay)
    elif button == GLUT_MIDDLE_BUTTON:
        if state == GLUT_DOWN :
            glutIdleFunc(None)

if __name__ == '__main__':
    glutInit()
    glutInitDisplayMode(GLUT_DOUBLE | GLUT_RGB)
    glutInitWindowSize(250, 250)
    glutInitWindowPosition(100, 100)
    glutCreateWindow("Quadrato Rotante")
    init()
    glutMouseFunc(mouse)
    glutDisplayFunc(display)
    glutReshapeFunc(reshape)
    glutMainLoop()

Questo programma fa due cose in più rispetto al precedente: fa ruotare il quadrato e permette di attivare/disattivare la rotazione con la pressione di due tasti del mouse (il centrale stoppa mentre il sinistro avvia).

Molte funzioni sono le stesse dell’ultima volta quindi non mi ripeterò. Vediamo le novità.

Innanzitutto potete notare che utilizzo GLUT_DOUBLE in DisplayMode. Questo serve ad attivare il doppio buffer.

Poi c’è la funzione glutMouseFunc() che serve ad impostare la funzione che servirà a gestire l’input del mouse. In questo caso ho usato una fantasiosa funzione mouse. Tale funzione prende quattro parametri:

  • button: indica quale bottone è stato premuto.
  • state: indica lo stato (premuto, alzato, click, etc…) vedremo più avanti queste cose in dettaglio.
  • x e y: sono, ovviamente, la posizione del puntatore.

Nella funzione mouse faccio una sola cosa: verifico quale tasto è stato premuto e a seconda del tasto modifico la funzione di Idle. Perché è la funzione IDLE che modifica i frame. La funzione display li mostra, la funzione IDLE li modifica (modificando i parametri utilizzati da display). Questo è il punto fondamentale.

Come potete vedere sposto la funzione di idle con il comando glutIdleFunc. La imposto a None (o NULL in C) per fermare il quadrato e alla funzione spinDisplay per ruotarlo. Quest’ultima funzione non fa altro che incrementare una variabile spin che rappresenta i gradi di rotazione.

La funzione display è del tutto simile a quella dell’esempio precedente. Viene aggiunta però la funzione glRotate la quale non fa altro che ruotare di spin gradi tutti i vertici che verranno inseriti fra glPushMatrix e glPopMatrix.

Un altra cosa accessoria è la funzione glutReshapeFunc che imposta la funzione da chiamare nel momento in cui la finestra viene ridimensionata. In questo caso la funzione evita solamente che vengano alterate le proporzioni.

EDIT: È disponibile la versione in C del codice di questa puntata. Lo trovate questo indirizzo

8 comments on “OpenGL – Animazione

  1. dovresti cambiare la visualizzazione del codice. l’indentazione viene azzerata e così il programma non funziona.

  2. È rimasto un codice html al posto di un >.

    Riga 30, all’interno della funzione spinDisplay.

  3. Grazie anche per questa puntata, seguo con interesse 🙂
    Se a qualcuno può tornare utile ho postato il codice tradotto in C sul mio sito: stylecode.altervista.org/opengl2.c