Laten we een 3D-grafische engine bouwen rasters en quads rasteren

Welkom bij het vijfde deel van onze serie Let's Build a 3D Graphics Engine! Deze keer zullen we twee nieuwe klassen bouwen voor rasteren: één voor driehoeken en één voor standaard vierhoeken. Dan gaan we stukken uit die twee klassen nemen en een laatste, almachtige veelhoekklasse samenstellen.

Tip: Dit maakt deel uit van een serie, dus als je er het meeste uit wilt halen, zorg er dan voor dat je de andere tutorials leest die hiertoe leiden.


Samenvatting

We hebben tot nu toe nogal wat in onze motor ingebouwd! Dit is wat we hebben:

  • Punt- en vectorklassen (de bouwstenen van onze motor).
  • Transformatiefuncties voor onze punten.
  • Een cameraklasse (stelt ons kijkvenster in en ruimt punten buiten het scherm in).
  • Twee klassen voor rasteren (lijnsegmenten en cirkels).

Hier is een korte naslag voor alle klassen die we hebben gebouwd:

 Puntklasse variabelen: num tuple [3]; // (x, y, z) Operators: Point AddVectorToPoint (Vector); Point SubtractVectorFromPoint (Vector); Vector SubtractPointFromPoint (punt); Null SetPointToPoint (punt); Functies: drawPoint; // teken een punt op de positie tuple Vector Class Variables: num tuple [3]; // (x, y, z) Operators: Vector AddVectorToVector (Vector); Vector SubtractVectorFromVector (Vector); Vector RotateXY (graden); Vector RotateYZ (graden); Vector RotateXZ (graden); Vectorschaal (s0, s1, s2); // ontvangt een schaling 3-tuple, retourneert de geschaalde vector Cameraklasse Vars: int minX, maxX; intIJp, maxY; int minZ, maxZ; array objectsInWorld; // een array van alle bestaande objecten Functies: null drawScene (); // tekent alle benodigde objecten op het scherm LineSegment Class Variables: int startX, startY; // het startpunt van ons lijnsegment int endX, endY; // het eindpunt van ons lijnsegment Functie: array returnPointsInSegment; // alle punten liggend op dit lijnsegment

We gaan zwaar op de Lijnstuk klasse om onze te maken Driehoek en Quad lessen, dus zorg ervoor dat je jezelf hiermee leert kennen voordat je verder gaat.


Driehoeken rasteren

Samenstellen van een Driehoek klasse voor de motor is vrij eenvoudig, vooral sinds de Lijnstuk klas is waar al onze rastering daadwerkelijk zal plaatsvinden. In deze klasse kunnen drie punten worden ingesteld en wordt er een lijnsegment tussen getekend om de voltooide driehoek te maken.  

Een eenvoudige schets van de klas zou er als volgt uit kunnen zien:

 Triangle Class Variables: // coordinates for the three points of our triangles int Point1X, Point1Y; int Point2X, Point2Y; int Point3X, Point3Y; Functie: array returnPointsInTriangle; // alle punten binnen de perimeter van de driehoek

Omwille van de normen gaan we ervan uit dat de drie punten die in onze driehoek worden aangegeven, met de wijzers van de klok mee zijn.  

Gebruik maken van onze Lijnstuk klas, dan kunnen we onze returnPointsInTriangle () functioneer als volgt:

 function returnPointsInTriangle () array PointsToReturn; // maak een tijdelijke array om de punten van de driehoek vast te houden // Maak drie lijnsegmenten en sla hun punten op in de array PointsToReturn.push (nieuwe LineSegment (this.Point1X, this.Point1Y, this.Point2X, this.Point2Y)); PointsToReturn.push (nieuwe LineSegment (this.Point2X, this.Point2Y, this.Point3X, this.Point3Y)); PointsToReturn.push (nieuwe LineSegment (this.Point3X, this.Point3Y, this.Point1X, this.Point1Y)); terugkeer (PointsToReturn); 

Niet slecht, toch? Omdat we al veel werk hebben gedaan binnen onze Lijnstuk klasse, we hoeven alleen maar door te gaan met rijgen om samen meer complexe vormen te maken. Dit maakt het eenvoudig om steeds meer gecompliceerde polygonen op het scherm te maken, simpelweg door er meer toe te voegen Lijnsegmenten (en meer punten op te slaan in de klas zelf).

Laten we vervolgens eens kijken hoe we meer punten aan dit systeem kunnen toevoegen door een vierkante klasse te maken.


Squared Away worden

Het samenstellen van een klas om quadrilaterals te behandelen, houdt alleen in dat we een paar extra dingen aan ons toevoegen Driehoek klasse. Met een andere reeks punten zou onze vierhoekklasse er als volgt uitzien:

 Quad Class Variabelen: int Point1X, Point1Y; // coördinaten voor de vier punten van onze quadrilaterale int Point2X, Point2Y; int Point3X, Point3Y; int Point4X, Point4Y; Functie: array returnPointsInQuad; // keer alle punten terug binnen de vierhoek

Vervolgens voegen we gewoon het extra lijnsegment toe aan de returnPointsInQuad functie, zoals zo:

 function returnPointsInQuad () array PointsToReturn; // maak een tijdelijke array om de punten van de quad vast te houden // Maak vier lijnsegmenten en sla hun punten op in de array PointsToReturn.push (nieuwe LineSegment (this.Point1X, this.Point1Y, this.Point2X, this.Point2Y)); PointsToReturn.push (nieuwe LineSegment (this.Point2X, this.Point2Y, this.Point3X, this.Point3Y)); PointsToReturn.push (nieuwe LineSegment (this.Point3X, this.Point3Y, this.Point4X, this.Point4Y)); PointsToReturn.push (nieuwe LineSegment (this.Point4X, this.Point4Y, this.Point1X, this.Point1Y)); terugkeer (PointsToReturn); 

Hoewel het bouwen van nieuwe klassen als deze vrij eenvoudig is, is er een veel eenvoudigere manier om al onze polygonen in één klasse in te kapselen. Door de magie van loops en arrays te gebruiken, kunnen we een polygoonklasse samenstellen die bijna elke gewenste maat kan maken!


Waar hebben alle Polys-Gon?

Om een ​​steeds groter wordende polygoonklasse te maken, moeten we twee dingen doen. De eerste is om al onze punten in een array te verplaatsen, wat ons een klassenoverzicht geeft dat lijkt op iets als dit:

 Polygoonklasse variabelen: matrixpunten; // bevat alle polygoonpunten in een array. Functie: array returnPointsInPolygon; // een array met alle punten van de polygoon

De tweede is om een ​​lus te gebruiken om een ​​onbenoemd aantal lijnsegmenten door te laten in onze returnPointsInPolygon () functie, die er ongeveer zo zou kunnen uitzien:

 function returnPointsInPolygon array PointsToReturn; // een tijdelijke array om de punten van de polygoon vast te houden // doorloop alle punten in de polygoon door telkens een coördinaatpaar te verplaatsen (met een stap van twee) voor (int x = 0; x < this.Points.length; x+=2)  if(this is not the last point)  //create a line segment between this point and the next one in the array PointsToReturn.push(new LineSegment(this.Points[x], this.Points[x+1], this.Points[x+2], this.Points[x+3]));  else if(this is the last point)  //create a line segment between this point and the first point in the array PointsToReturn.push(new LineSegment(this.Points[x-2], this.Points[x-1], this.Points[0], this.Points[1]));   //return the array of points return PointsToReturn; 

Met deze klasse toegevoegd aan onze engine, kunnen we nu alles maken, van een driehoek tot een 39 -zijdige gruwel met dezelfde regel code.


Polygoon Creator

Om te spelen met onze nieuwe polygoonklasse, laten we een programma maken dat de reikwijdte van het bereik aangeeft. Ons programma stelt de gebruiker in staat om zijden toe te voegen aan of te verwijderen van de weergegeven veelhoek met behulp van toetsaanslagen. Natuurlijk zullen we grenzen moeten stellen aan het aantal zijden dat onze polygoon kan hebben, omdat minder dan drie zijden het niet langer tot een polygoon maken. We hoeven niet echt de bovengrenzen van onze polygoon in de gaten te houden, omdat ze mooi moeten schalen. We gaan echter veelhoeken beperken tot maximaal tien zijden, omdat we de nieuwe punten van binnen de code bepalen.

Onze programmaspecificaties zijn onder te verdelen in deze kleinere delen:

  • Teken aanvankelijk een polygoon naar het scherm.
  • Wanneer u op de toets 'a' drukt, verlaagt u het aantal zijden van de polygoon met 1.
  • Wanneer u op de 's'-toets drukt, verhoogt u het aantal zijden van de polygoon met 1.
  • Voorkom dat het aantal zijden van de polygoon onder de 3 valt.
  • Voorkom dat het aantal zijden van de polygoon groter wordt dan 10.

Laten we eens kijken naar hoe onze code eruit zou kunnen zien:

 main // setup voor je favoriete grafische API hier // setup voor toetsenbordinvoer (is mogelijk niet nodig) var camera = new Camera (); // maak een instantie van onze cameraklasse camera.objectenInWorld []; // initialiseer de objectarray van de camera // stel de camerabeeldruimtecamera in.minX = 0; camera.maxX = schermbreedte; camera.minY = 0; camera.maxY = schermhoogte; camera.minZ = 0; camera.maxZ = 100; // maak een array van punten voor elke polygoongrootte var threeSides = new Array (100,100,100,50,50,50); var fourSides = new Array (punten hier); var fiveSides = new Array (punten hier); var sixSides = new Array (punten hier); var sevenSides = new Array (punten hier); var eightSides = new Array (punten hier); var nineSides = new Array (punten hier); var tenSides = new Array (punten hier); // sla alle arrays in een andere array op voor eenvoudiger toegang var sidesArray = nieuwe Array (threeSides, fourSides, fiveSides, sixSides, sevenSides, eightSides, nineSides, tenSides); // bijhouden hoeveel punten de polygoon momenteel heeft var polygonPoints = 3; // maak de eerste polygoon die moet worden weergegeven var polygon = new Polygon (sidesArray [0] [0], sidesArray [0] [1], sidesArray [0] [2], sidesArray [0] [3], sidesArray [0 ] [4], sidesArray [0] [5],); // teken de eerste polygoon naar het scherm camera.drawScene (); // terwijl de gebruiker de escape-toets niet heeft ingedrukt terwijl (toets! = esc) if (toets ingedrukt == 'a') // als de polygoon niet het risico loopt onder 3 te dalen als (polygonPoints! = 3) // verminder het aantal punten polygonPoints--; // verander de polygoon om het juiste aantal punten te krijgen // herschrijf de scene camera.drawScene ();  else if (key pressed == 's') // als de polygoon niet het risico loopt om boven de 10 te komen als (polygonPoints! = 10) // het aantal punten verhogen polygonPoints ++; // verander de polygoon om het juiste aantal punten te krijgen // herschrijf de scene camera.drawScene (); 

Ons kleine programma zou je nu een veelhoek op het scherm moeten laten aanpassen! Bekijk de demo. Als je dit programma een beetje wilt verbeteren, kun je proberen de polygoon-wijzigingssectie in een of andere vorm van een algoritme te plaatsen om het schalen gemakkelijker voor jezelf te maken. Ik weet niet zeker of er al een bestaat, maar als dat zo is, kun je gemakkelijk een oneindig schalende polygoon op je handen hebben!


Conclusie

We hebben nu een vrij uitgebreide hoeveelheid rasterbewerking ingebouwd in onze engine, waardoor we bijna elke vorm kunnen maken die we nodig hebben (hoewel sommige alleen door combinatie). De volgende keer gaan we af van het tekenen van vormen en praten we meer over hun eigenschappen. Als je geïnteresseerd bent in wat kleur op je scherm, bekijk dan het volgende deel!