Fondamenti di Grafica 3D
Iniziamo con la parte relativa alla proiezione: l'idea base è di un mio amico (Giorgio Fornara). Il diagramma allegato all'articolo aiuterà nella comprensione (dategli un'occhiata). L'idea è molto semplice (ma ingegnosa): quando si disegna un oggetto tridimensionale su un foglio di carta si è già fatta la proiezione che stiamo cercando, perché il foglio è 2-dimensionale!
Inizio con la descrizione del diagramma: i tre assi blu sono quelli del nostro spazio tridimensionale, i due assi neri sono quelli dello schermo 2-dimensionale (per essere precisi bisognerebbe cambiare segno all'asse Y in quanto tale asse sullo schermo punta verso il basso). Le linee rosse formano il nostro oggetto (per chiarezza non ho disegnato le linee nascoste) e le linee verdi sono le coordinate 2-dimensionali del punto P che stiamo cercando. Nel programma i due angoli alpha e beta sono entrambi uguali a 30 gradi, ma non devono necessariamente essere tali.
D'ora in poi indicherò le coordinate dello schermo con le lettere maiuscole X e Y, e le coordinate dello spazio tridimensionale con lettere minuscole x, y e z; allora la coordinata Y di P verrà scritta P_Y, e la coordinata y di P sarà rappresentata da P_y, e così via... Adesso il lavoro è facile: P_Y è semplicemente uguale a P_z meno il segmento dato da P_x * Sin(beta) (quello delimitato dalle linee blu tratteggiate) meno l'altro piccolo segmento dato da P_y * Sin(alpha). Analogamente per l'altra coordinata: P_X è uguale a P_x * Cos(beta) meno P_y * Cos(alpha). Quindi abbiamo le seguenti relazioni:
P_X = P_x * Cos(beta) - P_y * Cos(alpha) P_Y = P_z - P_x * Sin(beta) - P_y * Sin(alpha)
Per ottenere le formule usate nel programma occorre sottrarre queste quantità dalle coordinate del centro dello schermo.
A proposito, il disegno degli spigoli nascosti con linee tratteggiate è dovuto ad un (subdolo) trucco. Fra l'altro, il trucco funziona solo se si ha un solo vertice nascosto alla volta: si calcola quale vertice ha il valore più negativo per la somma delle sue tre coordinate P_x + P_y + P_z e si disegna tratteggiata ogni linea che si diparte da tale vertice. Sto ancora pensando a come generalizzare tale idea per permette configurazioni in cui più vertici sono nascosti contemporaneamente (se avete suggerimenti io non ho E-Mail, ma potete scrivere a Fabio Soft presso fsoft@intercom.it)
Veniamo ora alla routine che effettua le rotazioni. Le formule usate qui sono solo il prodotto della matrice di rotazione attorno all'asse z per la matrice di rotazione attorno all'asse x. In particolare: la rotazione attorno all'asse z è rappresentata in algebra lineare dalla matrice
| Cos(theta) Sin(theta) 0 | | | | -Sin(theta) Cos(theta) 0 | | | | 0 0 1 |
dove theta è l'angolo che rappresenta l'entità della rotazione; la rotazione attorno all'asse x è rappresentata dalla matrice
| 1 0 0 | | | | 0 Cos(phi) Sin(phi) | | | | 0 -Sin(phi) Cos(phi) |
dove phi è l'angolo che rappresenta l'entità della rotazione. Ora si effettua il prodotto (righe per colonne, al solito) delle due matrici e si ottiene:
| Cos(theta) Sin(theta)Cos(phi) Sin(theta)Sin(Phi) | | | R = | -Sin(theta) Cos(theta)Cos(phi) Cos(theta)Sin(phi) | | | | 0 -Sin(phi) Cos(phi) |
Se indico le nuove coordinate (quelle ruotate) con (x', y', z') e quelle vecchie con (x, y, z) abbiamo
| x' | | x | | | | | | y' | = R | y | | | | | | z' | | z |
cioè
x' = x*Cos(theta) + y*Sin(theta)Cos(phi) + z*Sin(theta)Sin(Phi) y' = - x*Sin(theta) + y*Cos(theta)Cos(phi) + z*Cos(theta)Sin(phi) z' = - y*Sin(phi) + z*Cos(phi)
e queste sono le formule che appaiono nel programma.
Io ho scelto di ruotare il mio cubo attorno agli assi x e z, ma si possono effettuare rotazioni attorno a qualunque asse si voglia, a patto di moltiplicare le matrici giuste e, poi, di collegare gli angoli al movimento del mouse.
Il resto del programma è dedicato ad aprire la finestra, leggere l'input, scrivere l'output: potete trovare i commenti a proposito di queste operazioni direttamente nel programma.
Scritto da: Andrea Galimberti e-mail: fsoft@intercom.it Via E.Villoresi Turbigo (MI) ITALY tel: (ITA) - (0)331 - 871009