Primo progetto di Grafica Interattiva A.A. 2003-4

Grafica bidimensionale

Vedere anche il testo del progetto.

Questo documento e' in evoluzione, raccogliero' qui le risposte alle questioni che solleverete, se saranno di interesse generale.
Aggiornamenti: 16/1/04, 13/1/04, 2/1/04

Suggerimenti

Divisione in due aree, toolbar

La divisione della finestra in due aree (grafica e toolbar) e i "bottoni" della toolbar si realizzano come spiegato nel laboratorio guidato, seconda esercitazione.

Struttura dati per un poligono

Definire una classe "poligono" che contiene (tra le varie cose):

Nota: supponendo che di un poligono vada disegnato tutto, bisogna disegnare prima l'interno, poi il contorno, infine i vertici, quindi le tre funzioni di disegno saranno chiamate in quest'ordine.

E' permesso supporre che un poligono non abbia piu' di 20 vertici e memorizzarli in un array statico.

Struttura per l'insieme dei poligoni e gestione del sopra/sotto

Tenere i poligoni in una lista linkata. Vengono disegnati nell'ordine in cui sono memorizzati (il primo e' sotto tutti, l'ultimo e' sopra tutti). Per portare "sopra" ("sotto") un poligono lo si sposta alla fine (all'inizio) della lista.
Nota: non usare un array perche' per portare sopra / sotto un poligono bisognerebbe spostarli tutti.

Interno del poligono

[ultimo aggiornamento: 16/1/04]

Se il poligono non e' convesso, talvolta il disegno del suo interno appare sbagliato. Non vi preoccupate, va bene cosi'.
GL_POLYGON funziona bene solo per poligoni semplici e convessi. Altrimenti, OpenGL non garantisce che sia disegnato giusto. Sara' cura dell'utente introdurre poligoni semplici e convessi o, in caso contrario, accettare che possano essere "disegnati male".

Traduzione delle coordinate cliccate

[ultimo aggiornamento: 16/1/04]

Questo suggerimento riguarda la questione della modifica interattiva di un poligono che e' stato trasformato (traslato, ruotato e/o scalato).

Per tradurre da coordinate sulla finestra (pixel) a coordinate di modellazione si usa glUnproject. Tra gli argomenti a questa funzione c'e' la matrice modelview salvata (con glGet) nel mentre che si disegna.
Bisogna distinguere due casi:

  1. quando stiamo inserendo i vertici di un nuovo poligono
  2. quando stiamo immettendo un nuovo vertice che divide un lato di un poligono esistente

Nel primo caso le coordinate di modellazione che interessano sono quelle generali della scena.
La modelview che si deve passare a glUnproject e' quella generale della scena, ottenuta ponendo glGet prima del disegno dei poligoni con le loro trasformazioni.
Nel secondo caso le coordinate di modellazione che interessano sono quelle particolari del poligono che sto modificando, il quale puo' essere stato scalato, ruotato e/o traslato prima di essere disegnato.
La modelview che si deve passare a glUnproject e' quella particolare del poligono, ottenuta ponendo glGet dopo le sue particolari trasformazioni.
In pratica dovete salvare, oltre alla modelview generale della scena, tutte le modelview dei vari poligoni. Dal meccanismo della selection possiamo sapere a quale poligono appartiene il lato su cui l'utente ha cliccato e quindi quale modelview dobbiamo andare a pescare.

Il baricentro

[ultimo aggiornamento: 13/1/04]

Il baricentro e' usato come punto di riferimento per scalare e ruotare un poligono. Di norma si calcola facendo la media delle coordinate x ed y dei vertici. Questo pero' implica che ad ogni modifica della forma del poligono (es. spostamento di un vertice) il baricentro cambi. Quindi, se il poligono viene modificato quando e' sotto rotazione o scalatura, la modifica provoca un cambiamento della sua posizione!
Per evitare questo problema stabiliamo che il baricentro del poligono viene calcolato una sola volta alla creazione del poligono (quando il poligono viene chiuso dopo aver immesso i suoi vertici) e poi rimane sempre quello, cioe' non viene mai ricalcolato neanche se cambiano i vertici del poligono.
Per questo si rende necessario memorizzare il baricentro nella struttura dati che tiene il poligono.

Per la selezione

Notiamo che in modalita' modifica bisogna poter selezionare un vertice o un lato anche in casi in cui del poligono viene tracciato solo l'interno. Cioe' occorre poter selezionare anche cose non tracciate.

Questo si ottiene tracciando in selection mode sempre tutto cio' interessa selezionare, mentre in rendering mode viene tracciato solo quello che e' richiesto in base ai flag.

In genere in selection mode e' meglio tracciare solo quello che interessa selezionare (e' inutile disegnare altro).

Inoltre per poter selezionare individualmente i vertici e i lati occorre tracciarli come primitive individuali (un glBegin(GL_POINTS) ... glEnd() per ogni vertice, idem per i lati con GL_LINES).

Per costruire i nomi delle primitive si puo' comunque sfruttare il numero d'ordine in cui sono disegnati i poligoni, nonostante che i poligoni non siano tenuti in un array. Infatti, l'ordine di memorizzazione in lista non cambia durante il disegno.
Supponendo al piu' 20 vertici (e lati) per poligono, si possono dare

Notare che in modalita' normale interessa selezionare i poligoni "in blocco": in quel caso si usano i nomi 0, 20, 40... che si attribuiscono a tutto cio' che del poligono viene disegnato (interno, lati o vertici, non e' necessario distinguere).

Invece in modalita' modifica interessa selezionare i vertici e i lati ma non i poligoni: quindi usiamo i nomi N+1, N+3, N+5... (vertici) e N, N+2, N+4... (lati) dove N e' il nome del poligono.

Poligoni che "si perdono"

[ultimo aggiornamento: 13/1/04]

Se di un poligono l'utente decide di non disegnare ne' interno ne' lati ne' vertici, allora il poligono diventa completamente invisibile; l'utente perde qualunque modo di selezionarlo per farne tornare visibile qualcosa. Va bene cosi': peggio per l'utente!
Potete scegliere se tenere comunque in memoria questi poligoni "persi" oppure cancellarli, ciascuna delle due scelte e' accettabile.

Sfondo, assi e griglia

[ultimo aggiornamento: 2/1/04]

Per colore di sfondo si intende il colore che OpenGL usa per pulire lo schermo prima di disegnare (con glClear); esiste una istruzione apposita per impostarlo (glClearColor, ved. anche il manuale).

Disegnare la griglia in colore tenue, simile a quello di sfondo, per non disturbare troppo. Disegnarla prima dei poligoni, in modo che rimanga sotto.
Dimensionare la quadrettatura in modo tale che risulti ben leggibile sia in condizioni normali (senza zoom), sia dopo due aver ingrandito o rimpicciolito un paio di volte.

Anche per gli assi usare un colore poco appariscente, ma ben distinguibile dalla griglia.