OpenGl – Approfondiamo le Modalità

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…

9 comments on “OpenGl – Approfondiamo le Modalità

  1. Interessante!
    Ma è normale che ogni tanto nella finestra sembrano vedersi dei refresh?

    Anche questo l’ho tradotto (ma non capisco il modes = …. all’inizio a cosa serve).
    Il file è qui: http://stylecode.altervista.org/opengl3.c

    p.s.: I sorgenti in C li puoi postare direttamente sul tuo sito se ti fa comodo 😉

    • Il modes=… ora te lo spiego. In pratica creo un array con tutte le modalità, poi faccio scorrere un indice che pesca a rotazione le modalità dall’array. Te non lo hai usato… ora non so se funziona lo stesso ma sicuramente non è il modo migliore per farlo. Tu passi a glBegin() un parametro che va da 0 a 9… questo funziona solo se GL_POINTS è uguale a 0, GL_LINES è uguale a 1 e così via.

      Non so se è così, potrebbe anche essere, ma se non usi l’array non è sicuro che a te esca la stessa cosa che esce a me e, inoltre, il risultato potrebbe variare da versione in versione. Metti caso che gli sviluppatori decidano di cambiare il valore della macro GL_POINTS da 0 a 987. Se usi l’array come ho fatto io sei sicuro che avrai sempre GL_POINTS, come hai fatto tu potresti avere qualunque cosa.

      Capito? Se non è chiaro cerco di farti un esempio migliore.

      Forse è per questo che ti sfarfalla.

      • Uhm… non mi è chiara una cosa:
        glBegin, da quello che vedo, prende in ingresso un intero.
        Quindi l’array modes è un array di integer?

      • Edit: penso di aver capito… credevo che i valori di modes fossero stringhe 😛
        Invece sono costanti definite dalle opengl, giusto?

        Comunque index l’ho cambiato perché è una parola riservata, e num_modes sostituisce il len().

        I refresh invece li vedo quando clicco troppo velocemente 😀

        • Esatto. Tutte le cose in maiuscolo non sono stringhe ma costanti definite nella libreria. Altrimenti avrebbero avuto le virgolette 😉

          Si ho capito perché hai cambiato quelle cose. 😀 Conosco il C piuttosto bene 😀

          Riguardo ai refresh… ho scritto quel codice sdraiato sul letto prima di uscire. È già tanto che se clicchi funziona XD Non l’ho testato per le “alte velocità”. Comunque credo che se sostituisci GLUT_SINGLE con GLUT_DOUBLE magari non ti sfarfalla. Ho usato single perché non è un esempio progettato per cliccatori folli. 😀

          • Ci avevo provato con GLUT_DOUBLE! Solo che in questo modo non funziona proprio 🙁

          • Hai messo anche glutSwapBuffer() come ultima istruzione della funzione display? Altrimenti viene sempre disegnato il buffer non visualizzato.