La oss bygge en 3D Graphics Engine Rasterizing Triangles og Quads

Velkommen til den femte delen av vår La oss bygge en 3D Graphics Engine-serie! Denne gangen vil vi bygge to nye klasser for rasterisering: en for trekanter og en for grunnleggende firkanter. Deretter skal vi ta stykker fra de to klassene og sette sammen en siste, allmektig polygonklasse.

Tips: Dette er en del av en serie, så hvis du vil få mest mulig ut av det, sørg for at du leser de andre opplæringene som fører opp til denne.


oppsummering

Vi har bygget ganske mye inn i vår motor så langt! Her er hva vi har:

  • Punkt og vektorglasser (byggeblokkene til motoren vår).
  • Transformasjonsfunksjoner for våre poeng.
  • En kameraklasse (setter vår visningsport, og culls peker utenfor skjermen).
  • To klasser for rasterisering (linjesegmenter og sirkler).

Her er en rask referanse for alle klassene vi har bygget:

 Point Class Variables: num tuple [3]; // (x, y, z) Operatører: Point AddVectorToPoint (Vector); Punkt SubtraherVectorFromPoint (Vector); Vector SubtractPointFromPoint (punkt); Null SetPointToPoint (punkt); Funksjoner: drawPoint; // tegne et punkt i sin posisjon tuple Vector Class Variables: num tuple [3]; // (x, y, z) Operatører: Vector AddVectorToVector (Vector); Vector SubtractVectorFromVector (Vector); Vector RotateXY (grader); Vector RotateYZ (grader); Vector RotateXZ (grader); Vector Scale (s0, s1, s2); // mottar en skalering 3-tuple, returnerer den skalerte vektoren Kamera klasse Vars: int minX, maxX; int minY, maxY; int minZ, maxZ; array objectsInWorld; // et utvalg av alle eksisterende objekter Funksjoner: null drawScene (); // trekker alle nødvendige objekter til skjermen LineSegment Class Variables: int startX, startY; // utgangspunktet for vårt linjesegment int endX, endY; // sluttpunktet til vårt linjesegment Funksjon: array returnPointsInSegment; // alle poeng som ligger på dette linjesegmentet

Vi kommer til å stole tungt på Linjestykke klasse for å skape vår Triangel og Quad klasser, så sørg for å bli kjent med det før du går videre.


Rasterizing Triangles

Å sette sammen en Triangel Klassen for motoren er ganske enkel, spesielt siden Linjestykke klassen er der all vår rasterisering faktisk kommer til å foregå. Denne klassen tillater tre poeng å settes, og vil tegne et linjesegment mellom dem for å lage den ferdige trekanten.  

En grunnleggende oversikt over klassen kan se slik ut:

 Triangle Class Variables: // koordinerer de tre punktene i våre trekanter int Point1X, Point1Y; int punkt2x, punkt2y; int punkt3x, punkt3y; Funksjon: array returnPointsInTriangle; // alle punkter innenfor trekantenes omkrets

For normernes skyld skal vi anta at de tre punktene deklarert i vår trekant er i et urvisende mønster.  

Bruk vår Linjestykke klasse, da kan vi sette opp vår returnPointsInTriangle () fungere som dette:

 funksjon returnPointsInTriangle () array PointsToReturn; // lage et midlertidig array for å holde trekantens poeng // Opprett tre linjesegmenter og lagre poengene i arrayet PointsToReturn.push (nytt LineSegment (this.Point1X, this.Point1Y, this.Point2X, this.Point2Y)); PointsToReturn.push (new LineSegment (this.Point2X, this.Point2Y, this.Point3X, this.Point3Y)); PointsToReturn.push (nytt LineSegment (this.Point3X, this.Point3Y, this.Point1X, this.Point1Y)); returnere (PointsToReturn); 

Ikke så ille, ikke sant? Siden vi allerede har mye arbeid som gjøres innenfor vår Linjestykke klasse, må vi bare fortsette å strengge dem sammen for å skape mer komplekse former. Dette gjør det enkelt å lage stadig mer kompliserte polygoner på skjermen, ganske enkelt ved å legge til på mer LineSegments (og lagre flere poeng i klassen selv).

Deretter kan vi se hvordan vi kan legge til flere poeng til dette systemet ved å lage en firkantet klasse.


Bli kvadret bort

Å sette sammen en klasse for å håndtere firehjulinger bare innebærer å legge til noen ekstra ting til vår Triangel klasse. Med et annet sett med poeng vil vår firkantede klasse se slik ut:

 Quad Class Variables: int Point1X, Point1Y; // koordinater for de fire punktene i vår firkantet int Point2X, Point2Y; int punkt3x, punkt3y; int Point4X, Point4Y; Funksjon: array returnPointsInQuad; // returnere alle poeng i firkanten

Deretter legger vi bare til i ekstra linjesegmentet til returnPointsInQuad fungere som:

 funksjon returnPointsInQuad () array PointsToReturn; // Opprett et midlertidig array for å holde quads poeng // Opprett fire linjesegmenter og lagre poengene i arrayet PointsToReturn.push (nytt LineSegment (this.Point1X, this.Point1Y, this.Point2X, this.Point2Y)); PointsToReturn.push (new LineSegment (this.Point2X, this.Point2Y, this.Point3X, this.Point3Y)); PointsToReturn.push (nytt LineSegment (this.Point3X, this.Point3Y, this.Point4X, this.Point4Y)); PointsToReturn.push (nytt LineSegment (this.Point4X, this.Point4Y, this.Point1X, this.Point1Y)); returnere (PointsToReturn); 

Mens å bygge nye klasser som dette er ganske rett frem, er det en mye enklere måte å inkapslere alle våre polygoner i en klasse. Ved å bruke det magiske av løkker og arrays, kan vi sette sammen en polygonklasse som kan gjøre nesten hvilken som helst form som du kan ønske deg!


Hvor har alle Polys-Gon?

For å skape en stadig voksende polygonklasse må vi gjøre to ting. Den første er å flytte alle våre poeng inn i en matrise, noe som vil gi oss en klassebilde som ligner på noe slikt:

 Polygon Class Variables: array Points; // holder alle polygonens punkter i en matrise Funksjon: array returnPointsInPolygon; // et array som holder alle polygonens punkter

Den andre er å bruke en sløyfe for å tillate at et navngitt antall linjesegmenter blir krysset i vår returnPointsInPolygon () funksjon, som kan se noe slikt ut:

 funksjon returnPointsInPolygon array PointsToReturn; // en midlertidig rekkefølge for å holde polygonens punkter // loop gjennom alle punkter i polygonen, flytte ett koordinatpar om gangen (med et trinn på to) for (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; 

Med denne klassen lagt til vår motor, kan vi nå lage noe fra en trekant til en 39-sidig avsky med samme linje med kode.


Polygon Creator

For å spille med vår nye polygonklasse, la oss lage et program som viser omfanget av rekkevidden. Vårt program skal tillate brukeren å legge til eller fjerne sider fra det viste polygonet ved hjelp av tastetrykk. Selvfølgelig må vi sette grenser for antall sider som polygon kan ha, siden å ha mindre enn tre sider, vil ikke lenger gjøre det til en polygon. Vi trenger ikke å holde øye med polygonens øvre grenser fordi de skal skalere pent. Vi kommer imidlertid til å begrense polygoner til å ha ti sider på maksimum siden vi vil sette inn sine nye poeng fra koden.

Våre programspesifikasjoner kan brytes ned i disse mindre delene:

  • Tegn først en polygon på skjermen.
  • Når "a" -tasten trykkes, senker du antall sider på polygonen med 1.
  • Når 's' tasten trykkes, øker du antall sider på polygonen med 1.
  • Forhindre at polygonets antall sider faller under 3.
  • Forhindre at polygonets antall sider øker over 10.

La oss se på hvordan vår kode kan se ut:

 main // setup for din favoritt grafikk-API her // oppsett for tastaturinngang (kanskje ikke nødvendig) her var kamera = nytt kamera (); // lage en forekomst av kameraklassen camera.objectsInWorld []; // initialiser kameraets objekt array // sett opp kameraets visning space camera.minX = 0; camera.maxX = screenWidth; kamera.minY = 0; camera.maxY = screenHeight; camera.minZ = 0; camera.maxZ = 100; // lage en rekke poeng for hver polygonstørrelse var threeSides = new Array (100,100,100,50,50,50); var fourSides = new Array (poeng inn her); var fiveSides = new Array (poeng inn her); var sixSides = new Array (poeng inn her); var sevenSides = new Array (poeng inn her); var eightSides = new Array (poeng inn her); var nineSides = new Array (poeng her); var tenSides = nytt Array (poeng her); // lagre alle arrays i en annen array for enklere tilgang var sidesArray = new Array (threeSides, fourSides, fiveSides, sixSides, sevenSides, eightSides, nineSides, tenSides); // holde oversikt over hvor mange poeng polygonen har for tiden var polygonPoints = 3; // lage den første polygonen som skal vises var polygon = ny Polygon (sidesArray [0] [0], sidesArray [0] [1], sidesArray [0] [2], sidesArray [0] [3], sidesArray [0 ] [4], sidesArray [0] [5],); // tegne den første polygonen til skjermkameraet .drawScene (); // mens brukeren ikke har trykket på flyktasten mens (nøkkel! = esc) hvis (tastetrykket == 'a') // hvis polygonen ikke er i fare for å falle under 3 hvis (polygonPoints! = 3) // redusere antall poeng polygonPoints--; // endre polygonen for å få riktig antall poeng // redrav scenekameraet.drawScene ();  ellers hvis (tastetrykket == 's') // hvis polygonen ikke er i fare for å gå over 10 hvis (polygonPoints! = 10) // øker antall poeng polygonPoints ++; // endre polygonen for å få riktig antall poeng // redrav scenekameraet.drawScene (); 

Vårt lille program skal gi deg mulighet til å justere en polygon på skjermen nå! Sjekk ut demoen. Hvis du vil bøte opp dette programmet litt, vil du kanskje prøve å sette polygon-endringsdelen i en form for en algoritme for å gjøre skaleringen lettere på deg selv. Jeg er usikker på om en allerede eksisterer, men hvis det gjør det, kan du lett ha en uendelig skaleringspolygon på hendene!


Konklusjon

Vi har ganske omfattende rasterisering innebygd i vår motor nå, og lar oss lage nesten hvilken som helst form som vi kanskje trenger (men noen bare gjennom kombinasjon). Neste gang vil vi bevege oss vekk fra tegningsformer og snakke mer om deres egenskaper. Hvis du er interessert i å få litt farge på skjermen, så husk å sjekke ut neste del!