Laten we een 3D-grafische engine bouwen punten, vectoren en basisbegrippen

De 3D-game-engines achter de grootste games van vandaag zijn verbluffende werken van wiskunde en programmeren en veel game-ontwikkelaars merken dat het een moeilijke taak is om ze in hun geheel te begrijpen. Als je geen ervaring hebt (of een universitaire opleiding, zoals ikzelf), wordt deze taak nog moeilijker. In deze serie probeer ik je door de basis van grafische systemen in 3D-engines te loodsen.

Meer specifiek, in deze tutorial zullen we punten en vectoren bespreken, en al het plezier dat ermee gepaard gaat. Als je een elementaire kennis hebt van algebra (variabelen en variabele wiskunde) en Computerwetenschap (de basis van elke objectgerichte programmeertaal), zou je de meeste van deze handleidingen moeten kunnen doorlopen, maar als je problemen hebt met een van de concepten, stel vragen! Sommige van deze onderwerpen kunnen vreselijk moeilijk zijn.

U kunt ook extra hulp krijgen bij Envato Studio, waar u tal van fantastische 3D-ontwerp- en modelleringsdiensten kunt vinden voor betaalbare prijzen. 

3D-ontwerp- en modelleringsdiensten op Envato Studio

Basisprincipes van Coordinate Systems

Laten we beginnen bij de basis. Driedimensionale grafische afbeeldingen vereisen het concept van een driedimensionale ruimte. De meest gebruikte ruimte is de Cartesiaanse ruimte, die ons het voordeel biedt van Cartesiaanse coördinaten (de basis \ ((x, y) \) notaties en 2D op roosterafstand geplaatste grafieken die op de meeste middelbare scholen worden onderwezen).


Afgebeeld: de vloek van het bestaan ​​van veel middelbare scholieren.

De driedimensionale cartesiaanse ruimte geeft ons een x-, y- en z-as (waarbij de positie wordt beschreven op basis van respectievelijk horizontale plaatsing, verticale plaatsing en diepte). De coördinaten voor elk punt binnen deze ruimte worden weergegeven als een tuple (in dit geval een 3-tuple, omdat er drie assen zijn). Op een 2-dimensionaal vlak kan een tuple worden afgebeeld als \ ((x, y) \), en in een driedimensionaal vlak wordt het afgebeeld als \ ((x, y, z) \). Het gebruik van dit 3-tupel is dat het de locatie van een punt toont ten opzichte van de oorsprong van de ruimte (die zelf typisch wordt weergegeven als \ ((0,0,0) \)).

Tip: Tuple: een geordende lijst (of reeks) van elementen in de informatica of wiskunde. Dus, \ ((K, y, l, e) \) zou een 4-tuple zijn, die een reeks tekens toont die mijn naam vormen.

Binnen deze ruimte gaan we een punt definiëren als een representatie van een 3-tupel. Dit kan ook worden weergegeven als:

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

Naast deze definitie van een punt, moeten we de delen ervan definiëren.

Elk van de elementen binnen dit 3-tupel is een scalaire (nummer) dat een positie langs a definieert basis vector. Elke basisvector moet een eenheidslengte hebben (dat wil zeggen een lengte van exact 1), dus 3-tupels zoals \ ((1,1,1) \) en \ ((2,2,2) \) konden niet zijn basisvectoren omdat ze te lang zijn.

We definiëren drie basisvectoren voor onze ruimte:

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


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

Het coördinatenstelsel

Laten we het nu hebben over de wiskundige definitie van ons coördinatensysteem, hoe dit ons grafische systeem beïnvloedt en de berekeningen die we kunnen maken.

Punten vertegenwoordigen

De oorsprong punt van ons coördinatensysteem kan worden afgebeeld als het punt \ (O \), dat het 3-tuple (0,0,0) vertegenwoordigt. Dit betekent dat de wiskundige weergave van ons coördinatensysteem kan worden afgebeeld als:

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

Door deze verklaring kun je zeggen dat \ ((x, y, z) \) staat voor de positie van een punt ten opzichte van de oorsprong. Deze definitie betekent ook dat elk punt \ (P \), \ ((a, b, c) \) kan worden weergegeven als:

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

Vanaf hier zal ik verwijzen naar scalaires in kleine letters en vectoren in hoofdletters - dus \ (a \), \ (b \) en \ (c \) zijn scalaire waarden en \ (X \), \ ( Y \) en \ (Z \) zijn vectoren. (Ze zijn eigenlijk de basisvectoren die we eerder hebben gedefinieerd.)

Dit betekent dat een punt waarvan het tuple (2,3,4) is, kan worden weergegeven als:

\ [\ Begin gericht
(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 gericht \]

Dus we hebben dit abstracte concept van "een punt in de 3D-ruimte" genomen en het gedefinieerd als vier afzonderlijke objecten bij elkaar opgeteld. Dit soort definitie is erg belangrijk wanneer we een concept in code willen omzetten.

Wederzijds loodrecht

Het coördinatensysteem dat we gaan gebruiken heeft ook de waardevolle eigenschap van het zijn onderling loodrecht. Dit betekent dat er een hoek van 90 graden is tussen elk van de assen waar ze elkaar ontmoeten op hun respectievelijke vlakken.


Ons coördinatensysteem zal ook worden gedefinieerd als "rechtshandig":

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

In wiskundige termen betekent dit dat:

\ [X = Y \ maal Z \]

... waarbij \ (\ times \) de operator voor meerdere producten is.

Als u niet zeker weet wat een crossproduct is, kan dit worden gedefinieerd door de volgende vergelijking (ervan uitgaande dat u twee 3-tuples krijgt):

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

Deze uitspraken kunnen vervelend lijken, maar later zullen ze ons in staat stellen om een ​​veelvoud aan verschillende berekeningen en transformaties veel gemakkelijker te doen. Gelukkig hoef je niet al deze vergelijkingen te onthouden bij het bouwen van een game-engine - je kunt eenvoudigweg bouwen op basis van deze uitspraken en vervolgens nog minder ingewikkelde systemen bouwen. Welnu, totdat je iets fundamenteels in je engine moet bewerken en jezelf hier opnieuw op moet verversen!


Punten en vectoren

Met alle basisbeginselen van ons coördinatensysteem op slot, is het tijd om te praten over punten en vectoren en, nog belangrijker, hoe ze met elkaar omgaan. Het eerste ding om op te merken is dat punten en vectoren duidelijk verschillende dingen zijn: een punt is een fysieke locatie in je ruimte; een vector is de ruimte tussen twee punten.


Om ervoor te zorgen dat de twee niet in de war raken, schrijf ik punten in cursief cursief, als \ (P \), en vectoren in vetgedrukte hoofdletters, als \ (\ mathbf V \).

Er zijn twee hoofd axioma's waarmee we te maken krijgen bij het gebruik van punten en vectoren, en ze zijn:

  • Axioma 1: Het verschil van twee punten is een vector, dus \ (\ mathbf V = P - Q \)
  • Axioma 2: de som van een punt en een vector is een punt, dus \ (Q = P + \ mathbf V \)
Tip: Een axioma is een redenering, vaak gezien als evident genoeg om zonder argument geaccepteerd te worden.

De motor bouwen

Met deze axioma's vermeld, hebben we nu genoeg informatie om de bouwsteenklassen te maken die de kern vormen van elke 3D-game-engine: de Punt klasse en de Vector klasse. Als we onze eigen engine zouden gaan bouwen met behulp van deze informatie, zouden er enkele andere belangrijke stappen zijn om deze klassen te maken (meestal met optimalisatie of omgaan met reeds bestaande API's), maar we laten deze voor omwille van de eenvoud.

De onderstaande klassenvoorbeelden gaan allemaal in pseudocode zodat u kunt volgen met uw programmeertaal naar keuze. Hier zijn de contouren van onze twee klassen:

Puntklasse variabelen: num tuple [3]; // (x, y, z) Operators: Point AddVectorToPoint (Vector); Point SubtractVectorFromPoint (Vector); Vector SubtractPointFromPoint (punt); Functie: // later zal dit een functie van een grafische API noemen, maar voor nu // zou dit gewoon de puntencoördinaten naar het scherm drawPoint moeten afdrukken; 
Vectorklasse variabelen: num tuple [3]; // (x, y, z) Operators: Vector AddVectorToVector (Vector); Vector SubtractVectorFromVector (Vector); 

Probeer als oefening alle functies van deze klasse in te vullen met werkcode (op basis van wat we tot nu toe hebben besproken). Als je dit allemaal hebt voltooid, kun je het op de proef stellen door dit voorbeeldprogramma te maken:

hoofd var point1 = new Point (1,2,1); var point2 = nieuw punt (0,4,4); var vector1 = new Vector (2,0,0); var vector2; point1.drawPoint (); // moet weergeven (1,2,1) point2.drawPoint (); // zou moeten weergeven (0,4,4) vector2 = point1.subtractPointFromPoint (punt2); vector1 = vector1.addVectorToVector (vector2); point1.addVectorToPoint (vector1); point1.drawPoint (); // moet weergeven (4,0, -2) point2.subtractVectorFromPoint (vector2); point2.drawPoint (); // zou moeten weergeven (-1,6,7)

Conclusie

Je bent klaar met het einde! Het lijkt misschien heel veel wiskunde om maar twee klassen te maken - en dat is het zeker. In de meeste gevallen zul je nooit aan een game op dit niveau hoeven te werken, maar een grondige kennis van de werking van je game-engine is toch nuttig (al was het maar voor de zelftevredenheid).

Als je dacht dat dit leuk was, bekijk dan mijn volgende tutorial over de basisprincipes van het grafische systeem: transformaties!

Als je eenmaal de grafische engine hebt gemaakt, moet je natuurlijk wat inhoud toevoegen, dus bekijk de uitgebreide selectie game-items en 3D-modellen op Envato Market..