Erstellen Sie eine 3D-Grafik-Engine Rastern von Dreiecken und Quads

Willkommen zum fünften Teil unserer Let's Build einer 3D Graphics Engine-Serie! Dieses Mal werden wir zwei neue Klassen für das Rasterisieren erstellen: eine für Dreiecke und eine für grundlegende Vierecke. Dann werden wir Stücke aus diesen beiden Klassen nehmen und eine abschließende, allmächtige Polygonklasse zusammenstellen.

Spitze: Dies ist ein Teil einer Serie. Wenn Sie also das Beste aus dieser Serie herausholen möchten, sollten Sie die anderen Tutorials lesen, die zu diesem Tutorial führen.


Rekapitulieren

Wir haben schon einiges in unseren Motor eingebaut! Folgendes haben wir:

  • Punkt- und Vektorklassen (die Bausteine ​​unserer Engine).
  • Transformationsfunktionen für unsere Punkte.
  • Eine Kameraklasse (legt unser Ansichtsfenster fest und entfernt Punkte außerhalb des Bildschirms).
  • Zwei Klassen zum Rastern (Liniensegmente und Kreise).

Hier ist eine Kurzübersicht für alle Klassen, die wir erstellt haben:

 Punktklasse Variablen: Zahlentupel [3]; // (x, y, z) Operatoren: Punkt AddVectorToPoint (Vektor); Point SubtractVectorFromPoint (Vektor); Vektor SubtractPointFromPoint (Punkt); Null SetPointToPoint (Punkt); Funktionen: drawPoint; // Zeichne einen Punkt an seinem Positionstupel Vektorklasse Variablen: Anzahl Tupel [3]; // (x, y, z) Operatoren: Vector AddVectorToVector (Vector); Vector SubtractVectorFromVector (Vector); Vektor RotateXY (Grad); VektordrehzahlYZ (Grad); VektordrehzahlXZ (Grad); Vektorskala (s0, s1, s2); // erhält ein 3-Tupel mit Skalierung, gibt den skalierten Vektor zurück Camera Class Vars: int minX, maxX; int minY, maxY; int minZ, maxZ; Array objectsInWorld; // ein Array aller vorhandenen Objekte Functions: null drawScene (); // zeichnet alle benötigten Objekte auf den Bildschirm LineSegment Class Variablen: int startX, startY; // der Startpunkt unseres Liniensegments int endX, endY; // der Endpunkt unseres Liniensegments Function: array returnPointsInSegment; // alle Punkte, die auf diesem Liniensegment liegen

Wir werden uns stark auf das verlassen Liniensegment Klasse, um unsere zu erstellen Dreieck und Quad Klassen, also stellen Sie sicher, dass Sie sich damit vertraut machen, bevor Sie fortfahren.


Rasterdreiecke

Zusammensetzen a Dreieck Klasse für den Motor ist ziemlich einfach, vor allem seit dem Liniensegment Klasse ist, wo all unsere Rasterung tatsächlich stattfinden wird. Diese Klasse ermöglicht das Setzen von drei Punkten und das Zeichnen eines Liniensegments, um das fertige Dreieck zu erhalten.  

Eine grundlegende Gliederung der Klasse könnte folgendermaßen aussehen:

 Triangle Class Variablen: // Koordinaten für die drei Punkte unserer Dreiecke int Point1X, Point1Y; int Punkt2X, Punkt2Y; int Punkt3X, Punkt3Y; Funktion: Array returnPointsInTriangle; // alle Punkte innerhalb des Umkreises des Dreiecks

Aus Gründen der Standards gehen wir davon aus, dass die drei Punkte, die innerhalb unseres Dreiecks angegeben sind, im Uhrzeigersinn sind.  

Mit unserem Liniensegment Klasse, dann können wir unsere einrichten returnPointsInTriangle () Funktion wie folgt:

 function returnPointsInTriangle () array PointsToReturn; // Erstellen Sie ein temporäres Array für die Punkte des Dreiecks. // Erstellen Sie drei Liniensegmente und speichern Sie deren Punkte im Array PointsToReturn.push (neues LineSegment (this.Point1X, this.Point1Y, this.Point2X, this.Point2Y)); PointsToReturn.push (neues LineSegment (this.Point2X, this.Point2Y, this.Point3X, this.Point3Y)); PointsToReturn.push (neues LineSegment (this.Point3X, this.Point3Y, this.Point1X, this.Point1Y)); return (PointsToReturn); 

Nicht so schlimm, richtig? Da haben wir schon viel Arbeit in unserem Liniensegment In der Klasse müssen wir sie nur zusammenfädeln, um komplexere Formen zu erstellen. Dies macht es einfach, immer kompliziertere Polygone auf dem Bildschirm zu erstellen, indem einfach weitere hinzugefügt werden Liniensegmente (und mehr Punkte innerhalb der Klasse selbst speichern).

Als Nächstes wollen wir uns ansehen, wie wir diesem System durch das Erstellen einer quadratischen Klasse mehr Punkte hinzufügen können.


Squared entfernt werden

Wenn Sie eine Klasse für den Umgang mit Vierecken zusammenstellen, müssen Sie nur ein paar zusätzliche Dinge hinzufügen Dreieck Klasse. Mit einem weiteren Satz von Punkten würde unsere vierseitige Klasse so aussehen:

 Quad Class Variablen: int Punkt1X, Punkt1Y; // koordiniert für die vier Punkte unseres vierseitigen int Point2X, Point2Y; int Punkt3X, Punkt3Y; int Point4X, Point4Y; Funktion: Array returnPointsInQuad; // alle Punkte innerhalb des Vierecks zurückgeben

Dann fügen wir einfach das zusätzliche Liniensegment zum hinzu returnPointsInQuad Funktion wie folgt:

 function returnPointsInQuad () array PointsToReturn; // Erstellen Sie ein temporäres Array, um die Punkte des Quad zu speichern. // Erstellen Sie vier Liniensegmente und speichern Sie ihre Punkte im Array PointsToReturn.push (neues LineSegment (this.Point1X, this.Point1Y, this.Point2X, this.Point2Y)); PointsToReturn.push (neues LineSegment (this.Point2X, this.Point2Y, this.Point3X, this.Point3Y)); PointsToReturn.push (neues LineSegment (this.Point3X, this.Point3Y, this.Point4X, this.Point4Y)); PointsToReturn.push (neues LineSegment (this.Point4X, this.Point4Y, this.Point1X, this.Point1Y)); return (PointsToReturn); 

Der Aufbau neuer Klassen ist zwar recht einfach, aber es ist viel einfacher, all unsere Polygone in einer Klasse zu kapseln. Durch die Verwendung der Magie von Schleifen und Arrays können wir eine Polygonklasse zusammenstellen, die fast jede gewünschte Form haben kann!


Wo haben alle Polys-Gon?

Um eine ständig wachsende Polygonklasse zu erstellen, müssen wir zwei Dinge tun. Die erste besteht darin, alle unsere Punkte in ein Array zu verschieben, was uns eine Klassengliederung ähnlich der folgenden ähnelt:

 Polygon-Klasse Variablen: Array-Punkte; // enthält alle Punkte des Polygons in einem Array Funktion: array returnPointsInPolygon; // ein Array mit allen Punkten des Polygons

Die zweite besteht darin, eine Schleife zu verwenden, um eine unbenannte Anzahl von Liniensegmenten in unserem durchlaufen zu können returnPointsInPolygon () Funktion, die ungefähr so ​​aussehen könnte:

 Funktion returnPointsInPolygon array PointsToReturn; // ein temporäres Array zum Halten der Punkte des Polygons // Schleife durch alle Punkte im Polygon, wobei jeweils ein Koordinatenpaar (um einen Schritt von zwei) für (int x = 0; x) verschoben wird < 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; 

Mit dieser Klasse, die zu unserer Engine hinzugefügt wurde, können wir jetzt alles von einem Dreieck bis hin zu 39-seitigen Abscheulichkeiten mit derselben Codezeile erstellen.


Polygon-Schöpfer

Um mit unserer neuen Polygonklasse zu spielen, erstellen wir ein Programm, das den Umfang seiner Reichweite zeigt. Unser Programm ermöglicht es dem Benutzer, Seiten per Tastendruck zum angezeigten Polygon hinzuzufügen oder daraus zu entfernen. Natürlich müssen wir Grenzen für die Anzahl der Seiten festlegen, die unser Polygon haben kann, da weniger als drei Seiten es nicht mehr zu einem Polygon machen. Wir müssen die Obergrenzen unseres Polygons nicht wirklich im Auge behalten, da sie gut skalieren sollten. Wir werden Polygone jedoch auf maximal zehn Seiten beschränken, da wir die neuen Punkte aus dem Code heraus setzen werden.

Unsere Programmspezifikationen können in folgende kleinere Teile unterteilt werden:

  • Zeichnen Sie zunächst ein Polygon auf dem Bildschirm.
  • Wenn Sie die Taste 'a' drücken, verringern Sie die Anzahl der Seiten des Polygons um 1.
  • Wenn Sie die Taste 's' drücken, erhöhen Sie die Anzahl der Seiten des Polygons um 1.
  • Verhindern Sie, dass die Anzahl der Seiten des Polygons unter 3 fällt.
  • Verhindern Sie, dass die Anzahl der Seiten des Polygons über 10 steigt.

Schauen wir uns an, wie unser Code aussehen könnte:

 main // Setup für Ihre bevorzugte Grafik-API hier // Setup für die Tastatureingabe (möglicherweise nicht erforderlich) hier var camera = new Camera (); // eine Instanz unserer Kameraklasse erstellen camera.objectsInWorld []; // das Objektarray der Kamera initialisieren // den Ansichtsraum der Kamera einrichten camera.minX = 0; camera.maxX = screenWidth; camera.minY = 0; camera.maxY = screenHeight; camera.minZ = 0; camera.maxZ = 100; // ein Array von Punkten für jede Polygongröße erstellen var threeSides = new Array (100,100,100,50,50,50); var fourSides = neues Array (Punkte hier); var fiveSides = new Array (Punkte hier); var sixSides = new Array (Punkte hier); var sevenSides = new Array (Punkte hier); var eightSides = neues Array (Punkte hier); var nineSides = new Array (Punkte hier); var tenSides = new Array (Punkte hier); // Speichern Sie alle Arrays in einem anderen Array, um den Zugriff zu erleichtern. var sidesArray = new Array (threeSides, fourSides, fiveSides, sixSides, sevenSides, achtSides, nineSides, tenSides); // Verfolge, wie viele Punkte das Polygon aktuell hat var polygonPoints = 3; // das anfängliche Polygon erstellen, das angezeigt werden soll var polygon = new Polygon (SeitenArray [0] [0], SeitenArray [0] [1], SeitenArray [0] [2], SeitenArray [0] [3], SeitenArray [0] ] [4], sideArray [0] [5],); // Zeichne das ursprüngliche Polygon auf dem Bildschirm camera.drawScene (); // während der Benutzer die Escape-Taste nicht gedrückt hat (Taste! = esc) if (Taste gedrückt == 'a') // Wenn das Polygon nicht unter 3 fallen darf, wenn (polygonPoints! = 3) // Anzahl der Punkte reduzieren polygonPoints--; // das Polygon so ändern, dass die korrekte Anzahl von Punkten angezeigt wird // Szene neu zeichnen camera.drawScene ();  else if (Taste gedrückt == 's') // wenn das Polygon nicht über 10 hinausgehen darf if (polygonPoints! = 10) // Anzahl der Punkte erhöhen polygonPoints ++; // das Polygon so ändern, dass die korrekte Anzahl von Punkten angezeigt wird // Szene neu zeichnen camera.drawScene (); 

Mit unserem kleinen Programm können Sie jetzt ein Polygon auf dem Bildschirm anpassen! Schauen Sie sich die Demo an. Wenn Sie dieses Programm ein wenig aufpeppen möchten, sollten Sie den Polygon-Änderungsabschnitt in eine Form eines Algorithmus stellen, um die Skalierung für Sie einfacher zu gestalten. Ich bin nicht sicher, ob es bereits eines gibt, aber wenn dies der Fall ist, könnten Sie leicht ein unendlich skalierendes Polygon an den Händen haben!


Fazit

Wir haben jetzt eine beträchtliche Menge an Rastern in unserer Engine eingebaut, so dass wir fast jede Form erstellen können, die wir benötigen (auch wenn diese nur durch Kombination möglich ist). Beim nächsten Mal werden wir uns vom Zeichnen von Formen entfernen und mehr über ihre Eigenschaften sprechen. Wenn Sie daran interessiert sind, etwas Farbe auf Ihren Bildschirm zu bringen, lesen Sie den nächsten Teil!