Questa è la penultima lezione del primo grande capitolo di OpenGL: il disegno di poligoni. Oggi parleremo dei “pattern” e di come istruire il motore grafico affinché non utilizzi un colore uniforme per disegnare righe e campiture ma colori soltanto i pixel che decidiamo noi. L’esempio più banale consiste nel voler disegnare una riga tratteggiata o di voler realizzare campiture in half-tone come quella nell’immagine dell’articolo.

Prima di entrare nel dettaglio facciamo un attimo il punto sulla struttura di OpenGL. OpenGL è una macchina a stati. Gli stati attivi influenzano il comportamento di OpenGL in modo sostanziale. Per attivare uno stato si utilizza il comando:

glEnable(state)

e si disabilita con

glDisable(state)

Dove state è l’identificativo di uno dei possibili stati di OpenGL. Non elencherò adesso tutti gli stati possibili di OpenGL perché sono tantissimi ma ve li citerò nel momento del bisogno. Un avvertimento: non tenete tutti gli stati abilitati se non ne avete bisogno perché questo danneggia pesantemente le prestazioni. Se non usate la nebbia (GL_FOG) è inutile che la attivate rendendo più pesante il processo di rendering.

STIPPLE NELLE LINEE

Cominciamo con le linee. Abbiamo visto come tracciare una linea (ad esempio tramite la modalità GL_LINE_STRIP) e come modificare il colore di tale linea (tramita glColor() e le sue varianti). Vediamo ora come effettuare il tratteggio.

La prima cosa da fare è abilitare lo stato GL_LINE_STIPPLE nella macchina tramite il comando enable. Dopodiché possiamo utilizzare il pratico comando:

glLineStipple(coefficente, pattern)

Questo comando imposta semplicemente lo stipple di una linea usando il tratteggio indicato in pattern. Ma come definiamo questo pattern? Tramite un numero esadecimale a 16bit. Qui bisogna fare un po’ di attenzione ma esiste un metodo infallibile per ricavare il numero corrispondente al pattern dei vostri sogni.

  1. Per prima cosa disegnate il pattern su un foglio quadrettato utilizzando solamente 16 quadretti.
  2. Sotto questo schema disegnate un 1 in corrispondenza dei quadratini anneriti e uno 0 in corrispondenza dei quadratini vuoti.  Ad esempio se voglio fare un pattern tratteggiato con 4pixel disegnati e 4 no avrò: 1111000011110000.
  3. Ribaltate il numero binario che avete trovato. Io ad esempio ottengo 0000111100001111.
  4. Raggruppate le cifre a gruppi di 4 e convertite il numero in esadecimale. Io ad esempio ottengo 0F0F.

Se vi domandate perché vada ribaltato vi basti sapere che dipende solamente dal modo con cui vengono letti i numeri nei calcolatori.
Il parametro coefficente è un semplice moltiplicatore. Se lo impostate ad 1 allora avrete identicamente il pattern che avete progettato, se lo impostate a 2 questo pattern verrò raddoppiato (ad esempio, nel mio caso, invece di 4pixel si e 4 no avrò 8pixel si e 8 no), con 3 triplicato e così via.

Ho questo esempio pronto:

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

def drawLine(x1,y1,x2,y2) :
    glBegin(GL_LINES)
    glVertex2f(x1,y1)
    glVertex2f(x2,y2)
    glEnd()

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

def display() :
    glClear(GL_COLOR_BUFFER_BIT)
    glColor3f(1,1,1)

    glEnable(GL_LINE_STIPPLE)

    #Prima Riga
    glLineStipple(1, 0x0101)
    drawLine(50, 125, 150, 125)
    glLineStipple(1, 0x00FF)
    drawLine(150, 125, 250, 125)
    glLineStipple(1, 0x1C47)
    drawLine(250, 125, 350, 125)

    #Seconda Riga
    glLineWidth(5)
    glLineStipple(1, 0x0101)
    drawLine(50, 100, 150, 100)
    glLineStipple(1, 0x00FF)
    drawLine(150, 100, 250, 100)
    glLineStipple(1, 0x1C47)
    drawLine(250, 100, 350, 100)
    glLineWidth(1)

    #Terza Riga
    glLineStipple(1, 0x1C47)
    glBegin(GL_LINE_STRIP)
    for i in range(7) :
        glVertex2f(50 + (i * 50), 75)
    glEnd()

    #Quarta Riga
    for i in range(6) :
        drawLine(50 + (i * 50), 50, 50 + (i+1) * 50, 50)

    #Quinta Riga
    glLineStipple(5, 0x1C47)
    drawLine(50, 25, 350, 25)

    glDisable(GL_LINE_STIPPLE)
    glFlush()

def reshape(w,h) :
    glViewport(0, 0, w, h)
    glMatrixMode(GL_PROJECTION)
    glLoadIdentity()
    gluOrtho2D(0, w, 0, h)

if __name__=='__main__' :
    glutInit()
    glutInitDisplayMode(GLUT_SINGLE | GLUT_RGB)
    glutInitWindowSize(400, 150)
    glutInitWindowPosition(100, 100)
    glutCreateWindow("Righe")
    init()
    glutDisplayFunc(display)
    glutReshapeFunc(reshape)
    glutMainLoop()

Uso tutti comandi già visti (tranne glLineWidth() ma credo che in questo caso il significato sia piuttosto intuitivo). La funzione drawLine() è una funzione personale che serve a snellire il codice. Potete usarla oppure usare direttamente ogni volta lo schema begin-vertex-end.

STIPPLE NEI POLIGONI

Ora invece vediamo come possiamo fare qualcosa di analogo con le campiture dei poligoni. Il meccanismo è analogo a quello delle linee. Per prima cosa si abilità lo stato GL_POLYGON_STIPPLE. Poi si imposta il pattern con:

glPolygonStipple(pattern)

Questa volta però disegnare il pattern è più complesso. Bisogna infatti utilizzare un array di 128 numeri esadecimali a 8bit al fine di formare una bitmap di 32×32 bit. Disegnare trame complesse è quindi molto più complesso del disegnare pattern per le righe. Proprio a causa di questa complessità e per il fatto che lo stipple di poligoni non è importante come lo stipple di linee, tralascerò per il momento il modo con cui vengono costruite queste bitmap. Ne farò forse un appendice.

Per il momento vi lascio questo codice di esempio:

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

halftone = [ 0xAA, 0xAA, 0xAA, 0xAA, 0x55, 0x55, 0x55, 0x55,
        0xAA, 0xAA, 0xAA, 0xAA, 0x55, 0x55, 0x55, 0x55,
        0xAA, 0xAA, 0xAA, 0xAA, 0x55, 0x55, 0x55, 0x55,
        0xAA, 0xAA, 0xAA, 0xAA, 0x55, 0x55, 0x55, 0x55,
        0xAA, 0xAA, 0xAA, 0xAA, 0x55, 0x55, 0x55, 0x55,
        0xAA, 0xAA, 0xAA, 0xAA, 0x55, 0x55, 0x55, 0x55,
        0xAA, 0xAA, 0xAA, 0xAA, 0x55, 0x55, 0x55, 0x55,
        0xAA, 0xAA, 0xAA, 0xAA, 0x55, 0x55, 0x55, 0x55,
        0xAA, 0xAA, 0xAA, 0xAA, 0x55, 0x55, 0x55, 0x55,
        0xAA, 0xAA, 0xAA, 0xAA, 0x55, 0x55, 0x55, 0x55,
        0xAA, 0xAA, 0xAA, 0xAA, 0x55, 0x55, 0x55, 0x55,
        0xAA, 0xAA, 0xAA, 0xAA, 0x55, 0x55, 0x55, 0x55,
        0xAA, 0xAA, 0xAA, 0xAA, 0x55, 0x55, 0x55, 0x55,
        0xAA, 0xAA, 0xAA, 0xAA, 0x55, 0x55, 0x55, 0x55,
        0xAA, 0xAA, 0xAA, 0xAA, 0x55, 0x55, 0x55, 0x55,
        0xAA, 0xAA, 0xAA, 0xAA, 0x55, 0x55, 0x55, 0x55 ]

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

def reshape(w,h) :
    glViewport(0, 0, w, h)
    glMatrixMode(GL_PROJECTION)
    glLoadIdentity()
    gluOrtho2D(0, w, 0, h)

def display() :
    glClear(GL_COLOR_BUFFER_BIT)
    glColor3f(1,1,1)
    #Disegna un quadrato bianco
    glRectf(25, 25, 125, 125)
    #Disegna un quadrato stipple in halftone
    glEnable(GL_POLYGON_STIPPLE)
    glPolygonStipple(halftone)
    glRectf(125, 25, 225, 125)
    glDisable(GL_POLYGON_STIPPLE)
    glFlush()

if __name__ == '__main__' :
    glutInit()
    glutInitDisplayMode(GLUT_SINGLE | GLUT_RGB)
    glutInitWindowSize(250, 150)
    glutCreateWindow("HalfTone")
    init()
    glutDisplayFunc(display)
    glutReshapeFunc(reshape)
    glutMainLoop()

Per questa volta è tutto. La prossima volta vedremo alcuni modi per evitare di inserire singolarmente tutti i vertici di una figura ed i rispettivi colori. Sostituendo quindi 20 istruzioni con una sola.

 

Nelle precedenti lezioni abbiamo visto come si riesca a disegnare qualunque poligono semplicemente inviando a OpenGL le coordinate dei suoi vertici. Per fare questo abbiamo anche visto che dobbiamo inserire il comando glVertex() all’interno di un blocco di istruzioni che comincia con:

glBegin(modes)

e termina con

glEnd()

Questa volta vediamo, anche grazie ad un piccolo programma di esempio come si comporta la renderizzazione al variare del parametro modes. Ogni modalità ha i suoi vantaggi e le sue modalità di utilizzo, ma andiamo a vedere queste modalità nel dettaglio:

  • GL_POINTS. Questa modalità interpreta i vertici come singoli punti.
  • GL_LINES. Questa modalità interpreta i vertici come segmenti. In pratica collega due vertici con una linea a coppie di due. Ad esempio dati 4 vertici v1, v2, v3 e v4 OpenGL traccerà una linea da v1 a v2 e da v3 a v4.
  • GL_LINE_STRIP. Questa modalità corrisponde ad una linea spezzata. In pratica OpenGL collegherà tutti i punti con una linea. v1 a v2, v2 a v3, v3 a v4 e così via.
  • GL_LINE_LOOP. Come sopra ma, in più, unisce anche l’ultimo vertice al primo.
  • GL_TRIANGLES. Questa modalità prende i vertici a gruppi di tre e forma dei triangoli.
  • GL_TRIANGLE_STRIP. Questa è forse la modalità più utilizzata. In pratica forma dei triangoli utilizzando come vertici l’ultimo vertice inserito più due vertici precedenti. Facciamo un esempio. Prendiamo 6 vertici. Inseriamo i primi tre formando il triangolo v1-v2-v3. Quando inseriremo il quarto vertice OpenGL creerà il triangolo v2-v3-v4. Poi v3-v4-v5 e così via fino all’ultimo triangolo. La modalità precedente, invece avrebbe disegnato solamente due triangoli: v1-v2-v3 e v4-v5-v6.
  • GL_TRIANGLE_FAN. Questa modalità è simile alla precedente ma ha una differenza fondamentale: il primo vertice inserito farà sempre parte dei triangoli. Così, supponendo di avere sempre i 6 vertici di prima, OpenGL disegnerà il triangolo v1-v2-v3, poi v1-v3-v4, poi v1-v4-v5 e così via.
  • GL_QUADS. Questa modalità è simile alla modalità GL_TRIANGLES. Ogni 4 vertici passati OpenGL disegna un quadrato.
  • GL_QUAD_STRIP. Questa modalità è analoga a GL_TRIANGLE_STRIP. Solamente con i quadrati al posto dei triangoli.
  • GL_POLYGON. Questa modalità interpreta ogni vertice come vertice di un poligono.

C’è però una cosa da tenere a mente: OpenGL non renderizza poligoni concavi. Gli unici poligoni che si possono renderizzare sono i poligoni convessi. Se volete disegnare poligoni non convessi dovete necessariamente suddividere il poligono da disegnare in un insieme di poligoni convessi (è sempre possibile). Solitamente vengono usati i triangoli poiché un triangolo è sempre convesso (questa proprietà non vale per i quadrilateri).

Un altra osservazione riguarda le facce. Un poligono bidimensionale in uno spazio tridimensionale ha due facce che chiameremo “davanti” e “dietro”. OpenGL decide quale faccia è “davanti” e quale è “dietro” semplicemente interpretando i vertici: viene considerata “davanti” la faccia dalla quale si vedono i vertici in senso anti-orario. E viceversa. L’ordine dei vertici è ovviamente l’ordine con i quali vengono inseriti: se inseriamo i vertici v1, v2 e v3 la faccia davanti sarà quella in cui posso vedere i vertici v1-v2-v3 ordinati in senso anti-orario.

Basta un piccolo sforzo di immaginazione, non è un concetto difficile. :)

Ora inseriamo un piccolo codice di esempio. In questo codice ad ogni click del mouse vengono disegnati sempre gli stessi punti (e sempre nello stesso ordine) ma con modalità diverse. Ad ogni click viene cambiata modalità. Una cosa istruttiva che potete fare è di disegnarvi i 9 punti che traccia il programma su un foglio di carta e di provare a prevedere cosa uscirà. Ovviamente alcune modalità con quei punti non si comportano molto bene (come GL_TRIANGLE_FAN e GL_POLYGON in quanto si verrebbero a formare poligoni concavi). Non ho però spostato i punti per far quadrare tutto, ho preferito lasciare i punti sempre fissi e far vedere come varia il risultato al variare delle modalità.

modes = [GL_POINTS, GL_LINES, GL_LINE_STRIP,
        GL_LINE_LOOP, GL_TRIANGLES, GL_TRIANGLE_STRIP,
        GL_TRIANGLE_FAN, GL_QUADS, GL_QUAD_STRIP, GL_POLYGON]
       
index = 0

def init() :
    glClearColor(0,0,0,0)
    glMatrixMode(GL_PROJECTION)
    glLoadIdentity()
    glOrtho(0,1,0,1,-1,1)
   
def mouse(button, state, x, y) :
    global index
    if button == GLUT_LEFT_BUTTON :
        if state == GLUT_DOWN :
            index += 1
    if index >= len(modes) :
        index -= len(modes)
    glutPostRedisplay()
   
def display() :
    glClear(GL_COLOR_BUFFER_BIT)
    glColor3f(1,1,1)
    glBegin(modes[index])
    glVertex2f(0.25, 0.25)
    glVertex2f(0.10, 0.50)
    glVertex2f(0.25, 0.85)
    glVertex2f(0.50, 0.50)
    glVertex2f(0.65, 0.85)
    glVertex2f(0.90, 0.85)
    glVertex2f(0.75, 0.50)
    glVertex2f(0.60, 0.15)
    glVertex2f(0.90, 0.15)
    glEnd()
    glFlush()
   
if __name__ == '__main__' :
    glutInit()
    glutInitDisplayMode(GLUT_SINGLE | GLUT_RGB)
    glutInitWindowSize(250, 250)
    glutInitWindowPosition(100, 100)
    glutCreateWindow("Esempi Modalita'")
    init()
    glutDisplayFunc(display)
    glutMouseFunc(mouse)
    glutMainLoop()

Ho utilizzato solamente comandi già visti quindi non sto a rispiegarvi il codice. Il codice in questo caso non è nemmeno la cosa più importante. La cosa cruciale è guardare i vertici e vedere come vengono disegnati al variare della modalità.

Per questa volta è tutto. La prossima volta vedremo come modificare il disegno dei vertici ad esempio inserendo campiture nei poligoni o pattern nelle righe. Per fare, ad esempio, righe tratteggiate, spesse, fine, etc…

 

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

 

Stavo ripassando gran parte delle API delle OpenGL. Stavo facendo piccoli schemi e riassunti ed allora ho pensato: perché non condividere un po’ di questo lavoro? Così ci trascrivo qualche piccolo cenno di OpenGL senza nessuna intenzione di portare alla luce chissà quale serie di tutorial. Se poi esce qualcosa di appetibile meglio così.

Innanzitutto devo fare due appunti: il primo è che, per mia semplicità, userò il Python come linguaggio per il codice, tuttavia le API sono identiche sia in pyOpenGL che nell’OpenGL standard quindi anche se programmate in C potete facilmente convertire il tutto nel linguaggio a voi più familiare. Secondo, le libreria OpenGL prese da sole sono un po’ complicate, infatti di solito ci si appoggia alle librerie collegate GLUT. Queste librerie si incaricano di fare tutto il lavoro “esterno” alla visualizzazione grafica come gestione degli input e integrazione nel sistema a finestre. Usare GLUT è proprio l’approccio che userò anche io.

Iniziamo mostrando un piccolo programma che disegna un quadrato bianco su uno sfondo nero.

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

def init():
glClearColor(0,0,0,0)
glMatrixMode(GL_PROJECTION)
glLoadIdentity()
glOrtho(0,1,0,1,-1,1)

def display():
glClear(GL_COLOR_BUFFER_BIT)
glColor3f(1,1,1)
glBegin(GL_POLYGON)
glVertex3f(0.25, 0.25, 0)
glVertex3f(0.75, 0.25, 0)
glVertex3f(0.75, 0.75, 0)
glVertex3f(0.25, 0.75, 0)
glEnd()
glFlush()

if __name__ == '__main__' :
glutInit()
glutInitDisplayMode(GLUT_SINGLE | GLUT_RGB)
glutInitWindowSize(250, 250)
glutInitWindowPosition(100, 100)
glutCreateWindow("Hello World")
init()
glutDisplayFunc(display)
glutMainLoop()

Partiamo quindi a spiegare il codice cominciando da l main. La prima funzione che incontriamo è glutInit(). Questa funzione si incarica di inizializzare GLUT. La versione canonica di questa funzione prende per argomento gli argomenti del main (argc e argv per chi conosce il C).

La seconda funzione è glutInitDisplayMode(). Questa funzione prende per parametri delle opzioni di visualizzazione. Nel nostro caso GLUT_SINGLE e GLUT_RGB i quali impostano la visualizzazione a singolo buffer (capiremo la differenza con il doppio buffer la prossima volta) e la visualizzazione RGB (ovvero con i colori tradizionalmente usati nei pc).

Gli altri tre comandi invece creano la finestra impostandone dimensione, posizione e titolo.

A questo punto entriamo in init(). In questa funzione vengono preimpostate alcune variabili di OpenGL. Non entrerò nel dettaglio ora, vi basti sapere che glClearColor() è la funzione per il colore di “sfondo” ovvero per quello usato durante la cancellazione. Questa funzione prende 4 parametri (rosso, verde, blu e trasparenza).

Un altra funzione importantissima è glutDisplayFunc() questa è la funzione che indica al motore grafico quale funzione chiamare nel momento in cui c’è bisogno di disegnare sullo schermo. In questo esempio passiamo semplicemente la funzione display la quale non fa altro che disegnare un quadrato bianco.

Come? Semplice. Per disegnare qualcosa bisogna passare al sistema le coordinate dei vertici secondo un algoritmo del tipo:

  • Si imposta il colore.
  • Si avverte il sistema che stiamo inserendo i vertici con glBegin().
  • Si passano le coordinate dei vertici con glVertex3f()
  • Si avverte il sistema che abbiamo terminato con glEnd()

Il parametro di glBegin è molto importante ma capiremo meglio il suo significato successivamente.

La funzione glFlush() è inutile per molte applicazioni. Ma voi mettetela. Così sarete sicuri che il vostro codice funzioni, ad esempio, in applicazioni di rete.

Alla fine, per chiudere in bellezza si lancia glutMainLoop() per avviare il programma.

Questo è solo un piccolo esempio. Disegnare un quadrato immobile non è ne bello ne utile. Ma questo esempio, nella sua semplicità, racchiude l’essenza di ogni programma OpenGL. La prossima volta vedremo come far ruotare questo dannato quadrato.

© 2008-2012 SlashCode Suffusion theme by Sayontan Sinha