Costruiamo un motore grafico 3D punti, vettori e concetti di base

I motori di gioco 3D che stanno dietro ai più grandi giochi di oggi sono incredibili lavori di matematica e programmazione, e molti sviluppatori di giochi ritengono che comprenderli nella loro interezza è un compito difficile. Se manchi di esperienza (o di una laurea, come me), questo compito diventa ancora più arduo. In questa serie, ho l'obiettivo di guidarti attraverso le basi dei sistemi grafici nei motori 3D.

Più specificamente, in questo tutorial parleremo di punti e vettori e di tutto il divertimento che ne deriva. Se hai una conoscenza di base di algebra (variabili e matematica variabile) e Computer Science (le basi di qualsiasi linguaggio di programmazione orientato agli oggetti), dovresti essere in grado di farlo attraverso la maggior parte di questi tutorial, ma se hai problemi con uno qualsiasi dei concetti, si prega di fare domande! Alcuni di questi argomenti possono essere terribilmente difficili.

Puoi inoltre ottenere ulteriore assistenza su Envato Studio, dove puoi trovare numerosi fantastici servizi di progettazione e modellazione 3D a prezzi accessibili. 

Servizi di progettazione e modellazione 3D su Envato Studio

Nozioni di base sui sistemi di coordinate

Iniziamo dalle basi. La grafica tridimensionale richiede il concetto di uno spazio tridimensionale. Il più ampiamente usato di questi spazi è chiamato lo spazio cartesiano, che ci dà il vantaggio delle coordinate cartesiane (le notazioni di base \ ((x, y) \) e i grafici a griglia 2D che vengono insegnati nella maggior parte delle scuole superiori).


Nella foto: la rovina dell'esistenza di molti liceali.

Lo spazio cartesiano tridimensionale ci fornisce un asse x, yez (che descrive la posizione in base al posizionamento orizzontale, al posizionamento verticale e alla profondità rispettivamente). Le coordinate per qualsiasi punto all'interno di questo spazio sono mostrate come a tuple (in questo caso una tupla da 3, poiché ci sono tre assi). Su un piano bidimensionale, una tupla può essere rappresentata come \ ((x, y) \), e nel piano tridimensionale, è raffigurata come \ ((x, y, z) \). L'uso di questa 3-tupla è che mostra la posizione di un punto rispetto all'origine dello spazio (che di solito è indicato come \ ((0,0,0) \)).

Mancia: Tupla: una lista (o sequenza) ordinata di elementi in informatica o in matematica. Quindi, \ ((K, y, l, e) \) sarebbe una 4-tupla, mostrando una sequenza di caratteri che compongono il mio nome.

All'interno di questo spazio, definiremo un punto come una rappresentazione di una tupla di 3 elementi. Questo può anche essere mostrato come:

\ [P = (x, y, z) \]

Oltre a questa definizione di un punto, dobbiamo definirne le parti.

Ciascuno degli elementi all'interno di questa tupla 3 è a scalare (numero) che definisce una posizione lungo a vettore di base. Ogni vettore di base deve avere una lunghezza unitaria (ovvero una lunghezza esattamente 1), quindi 3-tuple come \ ((1,1,1) \) e \ ((2,2,2) \) non potrebbero essere vettori di base perché sono troppo lunghi.

Definiamo tre vettori di base per il nostro spazio:

\ [\ Begin allineati
X & = (1,0,0) \\
Y & = (0,1,0) \\
Z & = (0,0,1)
\ End allineata \]


Fonte: http://www.thefullwiki.org/Arithmetics/Cartesian_Coordinate.

Il sistema di coordinate

Parliamo ora della definizione matematica del nostro sistema di coordinate, di come influisce sul nostro sistema grafico e dei calcoli che possiamo fare.

Rappresentare i punti

Il punto di origine del nostro sistema di coordinate può essere rappresentato come il punto \ (O \), che rappresenta la 3-tupla (0,0,0). Ciò significa che la rappresentazione matematica del nostro sistema di coordinate può essere rappresentata come:

\ [\ O; X, Y, Z \ \]

Con questa affermazione, puoi dire che \ ((x, y, z) \) rappresenta la posizione di un punto in relazione all'origine. Questa definizione significa anche che qualsiasi punto \ (P \), \ ((a, b, c) \), può essere rappresentato come:

\ [P = O + aX + bY + cZ \]

Da qui in poi, farò riferimento agli scalari in lettere minuscole e ai vettori in maiuscolo, quindi \ (a \), \ (b \) e \ (c \) sono scalari e \ (X \), \ ( Y \) e \ (Z \) sono vettori. (Sono in realtà i vettori di base che abbiamo definito in precedenza.)

Ciò significa che un punto la cui tupla è (2,3,4) potrebbe essere rappresentato come:

\ [\ Begin allineati
(2,3,4) & = (2,0,0) + (0,3,0) + (0,0,4) \\
& = (0,0,0) + (2,0,0) + (0,3,0) + (0,0,4) \\
& = (0,0,0) + 2 (1,0,0) + 3 (0,1,0) + 4 (0,0,1) \\
& = O + 2X + 3Y + 4Z \\
\ End allineata \]

Quindi, abbiamo preso questo concetto astratto di "un punto nello spazio 3D" e lo abbiamo definito come quattro oggetti separati sommati. Questo tipo di definizione è molto importante ogni volta che vogliamo mettere qualsiasi concetto in codice.

Mutualmente perpendicolare

Il sistema di coordinate che useremo ha anche la preziosa proprietà di essere reciprocamente perpendicolare. Ciò significa che c'è un angolo di 90 gradi tra ciascuno degli assi in cui si incontrano sui rispettivi piani.


Il nostro sistema di coordinate sarà anche definito come "destrorso":

Fonte: http://viz.aset.psu.edu/gho/sem_notes/3d_fundamentals/html/3d_coordinates.html.

In termini matematici, ciò significa che:

\ [X = Y \ volte Z \]

... dove \ (\ times \) rappresenta l'operatore del prodotto incrociato.

Nel caso in cui non si sia sicuri di quale sia un prodotto incrociato, può essere definito dalla seguente equazione (supponendo che vi siano state fornite due 3-tuple):

\ [(a, b, c) \ times (d, e, f) = (bf - ce, cd - af, ae - bd) \]

Queste affermazioni potrebbero sembrare noiose, ma in seguito ci consentiranno di eseguire una varietà di calcoli e trasformazioni molto più facilmente. Fortunatamente, non devi memorizzare tutte queste equazioni quando costruisci un motore di gioco: puoi semplicemente costruire da queste affermazioni e poi costruire anche sistemi meno complicati. Bene, finché non devi modificare qualcosa di fondamentale nel tuo motore e devi rinfrescarti di nuovo su tutto ciò!


Punti e vettori

Con tutte le basi del nostro sistema di coordinate bloccato, è tempo di parlare di punti e vettori e, ancora più importante, di come interagiscono tra loro. La prima cosa da notare è che punti e vettori sono cose nettamente differenti: un punto è una posizione fisica all'interno del tuo spazio; un vettore è lo spazio tra due punti.


Per assicurarmi che i due non si confondano, scriverò dei punti in corsivo maiuscolo, come \ (P \), e i vettori in grassetto capitale, come \ (\ mathbf V \).

Ci sono due assiomi principali di cui ci occuperemo quando si usano punti e vettori, e sono:

  • Assioma 1: la differenza tra due punti è un vettore, quindi \ (\ mathbf V = P - Q \)
  • Assioma 2: la somma di un punto e un vettore è un punto, quindi \ (Q = P + \ mathbf V \)
Mancia: Un assioma è un punto di ragionamento, spesso visto come abbastanza evidente da essere accettato senza discussione.

Costruire il motore

Con questi assiomi affermati, ora disponiamo di informazioni sufficienti per creare le classi elementari che sono al centro di qualsiasi motore di gioco 3D: il Punto classe e il Vettore classe. Se avessimo intenzione di costruire il nostro motore utilizzando queste informazioni, ci sarebbero alcuni altri passaggi importanti da prendere quando si creano queste classi (principalmente per quanto riguarda l'ottimizzazione o la gestione di API già esistenti), ma lasceremo queste cose per per semplicità.

Gli esempi di classe seguenti saranno tutti in pseudocodice in modo da poter seguire il linguaggio di programmazione scelto. Ecco i profili delle nostre due classi:

Point Class Variables: num tuple [3]; // (x, y, z) Operatori: Punto AddVectorToPoint (Vettore); Point SubtractVectorFromPoint (Vector); Vector SubtractPointFromPoint (Point); Funzione: // più avanti chiamerà una funzione da un'API di grafica, ma per ora // dovrebbe semplicemente stampare le coordinate dei punti sul drawPoint dello schermo; 
Vector Class Variables: num tuple [3]; // (x, y, z) Operatori: Vector AddVectorToVector (Vector); Vector SubtractVectorFromVector (Vector); 

Come esercizio, prova a inserire ognuna delle funzioni di questa classe con un codice funzionante (basato su ciò che abbiamo passato finora). Una volta che hai finito tutto, mettilo alla prova facendo questo esempio di programma:

main var point1 = new Point (1,2,1); var point2 = new Point (0,4,4); var vector1 = new Vector (2,0,0); var vector2; point1.drawPoint (); // dovrebbe mostrare (1,2,1) point2.drawPoint (); // dovrebbe visualizzare (0,4,4) vector2 = point1.subtractPointFromPoint (point2); vector1 = vector1.addVectorToVector (vector2); point1.addVectorToPoint (vector1); point1.drawPoint (); // dovrebbe visualizzare (4,0, -2) point2.subtractVectorFromPoint (vector2); point2.drawPoint (); // dovrebbe mostrare (-1,6,7)

Conclusione

Hai fatto fino alla fine! Può sembrare un'enorme quantità di matematica fare solo due lezioni - e lo è sicuramente. Nella maggior parte dei casi non dovrai mai lavorare su un gioco a questo livello, ma avere una conoscenza approfondita del funzionamento del tuo motore di gioco è comunque utile (se non altro per l'auto-soddisfazione).

Se pensavi che fosse divertente, assicurati di dare un'occhiata al mio prossimo tutorial sulle basi del sistema grafico: le trasformazioni!

Ovviamente, una volta creato il motore grafico, è necessario aggiungere alcuni contenuti, quindi sentiti libero di dare un'occhiata all'ampia selezione di risorse di gioco e modelli 3D sul mercato Envato.