In diesem Beitrag werden wir die Phase der Arbeit mit Eckpunkten betrachten. Das heißt, wir müssen wieder die Lehrbücher über Mathematik besorgen und uns an lineare Algebra, Matrizen und Trigonometrie erinnern. Hurra!
Wir werden herausfinden, wie 3D-Modelle transformiert und Lichtquellen berücksichtigt werden. Wir werden auch den Unterschied zwischen Scheitelpunkt- und geometrischen Shadern im Detail erklären und Sie werden herausfinden, in welchem Stadium sich die Tessellation befindet. Zum besseren Verständnis verwenden wir Diagramme und Codebeispiele, die zeigen, wie das Spiel Berechnungen durchführt und Werte verarbeitet.
Der Screenshot am Anfang des Beitrags zeigt das Spiel GTA V im Drahtmodell-Anzeigemodus. Vergleichen Sie es mit dem viel weniger komplexen Half-Life 2-Drahtmodell. Die Bilder wurden von thalixte mit
ReShade erstellt .
Was ist der Punkt?
In der Welt der Mathematik ist ein Punkt einfach ein Ort im geometrischen Raum. Es gibt nichts Kleineres als einen Punkt, er hat keine Größe, sodass Punkte verwendet werden können, um die genaue Position von Anfang und Ende von Objekten wie Liniensegmenten, Ebenen und Volumina anzugeben.
Für 3D-Grafiken sind solche Informationen von entscheidender Bedeutung. Das Erscheinungsbild hängt davon ab, da alle Objekte als Sätze von Liniensegmenten, Ebenen usw. angezeigt werden. Das Bild unten zeigt einen Screenshot von Bethesda 2015
Fallout 4 :
Es ist möglicherweise nicht leicht für Sie zu erkennen, dass dies nur eine große Menge von Punkten und Linien ist. Wir zeigen Ihnen daher, wie dieselbe Szene im Drahtgittermodus aussieht. In diesem Modus überspringt die 3D-Rendering-Engine Texturen und Effekte, die im Pixelstadium ausgeführt werden, und zeichnet nur mehrfarbige Linien, die die Punkte verbinden.
Jetzt sieht alles ganz anders aus, aber wir sehen, wie alle Linien kombiniert werden, um verschiedene Objekte, Umgebungen und Hintergründe zu bilden. Einige bestehen nur aus Dutzenden von Linien, zum Beispiel Steinen im Vordergrund, während andere so viele Linien enthalten, dass sie solide aussehen.
Jeder Punkt am Anfang und Ende jeder Linie wird verarbeitet, indem eine ganze Reihe von Berechnungen durchgeführt werden. Einige Berechnungen sind sehr einfach und schnell, andere sind viel komplizierter. Durch die Verarbeitung von Punkten in Gruppen, insbesondere in Form von Dreiecken, können Sie eine erhebliche Produktivitätssteigerung erzielen. Schauen wir uns diese also genauer an.
Was wird für ein Dreieck benötigt?
Das
Namensdreieck macht deutlich, dass die Figur drei innere Ecken hat; Dazu benötigt sie drei Eckpunkte und drei Segmente, die sie verbinden. Es ist richtig, einen Eckpunkt einen
Scheitelpunkt (Scheitelpunkt) (im Plural - Scheitelpunkte) zu nennen; Jeder Scheitelpunkt wird durch einen Punkt definiert. Da wir uns in einer dreidimensionalen geometrischen Welt befinden, wird das
kartesische Koordinatensystem für Punkte verwendet. Normalerweise werden die Koordinaten in Form von drei Werten geschrieben, z. B. (1, 8, -3) oder generisch (
x, y, z ).
Als nächstes können wir zwei weitere Eckpunkte hinzufügen, um ein Dreieck zu bilden:
Beachten Sie, dass die angezeigten Linien optional sind. Wir können die Punkte festlegen und dem System mitteilen, dass diese drei Eckpunkte ein Dreieck bilden. Alle Scheitelpunktdaten werden in einem zusammenhängenden Speicherblock gespeichert, der als
Scheitelpunktpuffer bezeichnet wird . Informationen über die Figur, die sie bilden, werden entweder direkt im Rendering-Programm codiert oder in einem anderen Speicherblock gespeichert, der als
Indexpuffer bezeichnet wird .
Wenn die Informationen in einem Rendering-Programm codiert sind, werden die verschiedenen Formen, die durch Scheitelpunkte gebildet werden können, als
Grundelemente bezeichnet . Direct3D schlägt vor, eine Liste für sie, Streifen und Lüfter in Form von Punkten, Linien und Dreiecken zu verwenden. Bei korrekter Verwendung verwenden Dreiecksstreifen Scheitelpunkte für mehr als ein Dreieck, was die Produktivität verbessert. Im folgenden Beispiel sehen wir, dass zum Erstellen von zwei miteinander verbundenen Dreiecken nur vier Scheitelpunkte benötigt werden. Wenn sie getrennt sind, benötigen wir sechs Scheitelpunkte.
Von links nach rechts: Liste der Punkte, Liste der Linien und DreiecksstreifenWenn wir beispielsweise in einem Spiel-NPC-Modell einen größeren Satz von Scheitelpunkten verarbeiten müssen, ist es besser, ein Objekt zu verwenden, das als
Netz bezeichnet wird , einen weiteren Speicherblock, der jedoch aus mehreren Puffern (Scheitelpunkte, Indizes usw.) und Modelltexturressourcen besteht . In der
Online-Dokumentation von Microsoft wird kurz erläutert, wie diese Puffer verwendet werden.
Konzentrieren wir uns zunächst darauf, was mit diesen Scheitelpunkten in einem 3D-Spiel passiert, wenn Sie jeden neuen Frame rendern. Kurz gesagt, sie führen eine von zwei Operationen aus:
- Der Scheitelpunkt bewegt sich an eine neue Position.
- Die Scheitelpunktfarbe ändert sich
Bereit für Mathe? Exzellent, weil wir es brauchen.
Vektor erscheint auf der Bühne.
Stellen Sie sich vor, Sie haben ein Dreieck auf dem Bildschirm und drücken eine Taste, um es nach links zu verschieben. Natürlich erwarten wir, dass sich die Zahlen (
x, y, z ) jedes Scheitelpunkts entsprechend ändern. Das ist, was passiert, aber eine ziemlich unerwartete
Art, Änderungen umzusetzen. Anstatt einfach die Koordinaten zu ändern, verwendet die überwiegende Mehrheit der 3D-Grafik-Rendering-Systeme ein spezielles mathematisches Werkzeug: Wir meinen
Vektoren .
Ein Vektor kann als Pfeil dargestellt werden, der auf einen bestimmten Punkt im Raum zeigt und die gewünschte Länge hat. Scheitelpunkte werden normalerweise mithilfe von Vektoren festgelegt, die auf kartesischen Koordinaten basieren:
Beachten Sie, dass der blaue Pfeil an einer Stelle (in diesem Fall am
Ursprungspunkt ) beginnt und sich nach oben erstreckt. Um den Vektor festzulegen, haben wir einen
Datensatz in einer Spalte verwendet , aber es ist durchaus möglich, einen
Datensatz in einer Zeile zu verwenden . Möglicherweise haben Sie bemerkt, dass es einen anderen vierten Wert gibt, der üblicherweise als
w-Komponente bezeichnet wird . Es wird verwendet, um zu zeigen, wofür der Vektor steht: Punktposition (
Positionsvektor ) oder allgemeine Richtung (
Richtungsvektor ). Im Fall eines Richtungsvektors sieht es folgendermaßen aus:
Dieser Vektor zeigt in die gleiche Richtung und hat die gleiche Länge wie der vorherige Positionsvektor, dh die Werte (
x, y, z ) sind gleich. Die
w- Komponente ist jedoch nicht 1, sondern Null. Wir werden die Verwendung von Richtungsvektoren später erklären, aber denken Sie vorerst daran, dass alle Eckpunkte in der 3D-Szene auf diese Weise beschrieben werden. Warum? Weil es in diesem Format viel einfacher ist, sie zu verschieben.
Mathe, Mathe und wieder Mathe
Denken Sie daran, dass wir ein einfaches Dreieck haben und es nach links verschieben möchten. Jeder Scheitelpunkt wird durch einen Positionsvektor beschrieben, daher muss die „Bewegungsmathematik“ (
Transformationen genannt ) mit diesen Vektoren arbeiten. Ein neues Werkzeug erscheint:
Matrizen (
Matrix im Singular). Dies ist ein Array von Werten, die in einem Format ähnlich einer Excel-Tabelle mit Zeilen und Spalten geschrieben sind.
Für jeden Transformationstyp gibt es eine entsprechende Matrix, und für eine Transformation reicht es aus, die Transformationsmatrix und den Positionsvektor einfach zu multiplizieren. Wir werden nicht näher darauf eingehen, wie und warum dies geschieht, sondern nur sehen, wie es aussieht.
Das Verschieben eines Scheitelpunkts im 3D-Raum wird als
Übersetzung bezeichnet und erfordert die folgende Berechnung:
Werte
x 0 usw. die ursprünglichen Koordinaten des Vektors darstellen;
Delta -
x - Werte geben den Betrag an, um den der Scheitelpunkt verschoben werden muss. Die Multiplikation der Matrix und des Vektors führt dazu, dass sie einfach zusammengefasst werden (beachten Sie, dass die
w- Komponente unverändert bleibt, so dass die fertige Antwort wie zuvor der Positionsvektor bleibt).
Zusätzlich zum Verschieben müssen wir möglicherweise auch das Dreieck drehen oder seinen Maßstab ändern - für diese Operationen gibt es auch Transformationen.
Diese Transformation dreht den Scheitelpunkt um die z-Achse in der XY-EbeneUnd dies wird verwendet, wenn Sie den Maßstab der Figur ändern müssenWir können das WebGL-basierte Grafiktool von
Real-Time Rendering verwenden , um diese Berechnungen für die gesamte Abbildung zu visualisieren. Beginnen wir mit der Box in der Standardposition:
In diesem Online-Tool ist der Modellpunkt der Positionsvektor, die Weltmatrix die Transformationsmatrix und der Weltraumpunkt der Positionsvektor für den transformierten Scheitelpunkt.
Wenden wir verschiedene Transformationen auf die Box an:
Im obigen Bild wurde die Figur
um 5 Einheiten entlang jeder Achse
verschoben . Diese Werte sind in der letzten Spalte der mittleren großen Matrix zu sehen. Der ursprüngliche Positionsvektor (4, 5, 3, 1) bleibt unverändert, aber der transformierte Scheitelpunkt wird jetzt auf (9, 10, 8, 1) verschoben.
Bei dieser Transformation wurde alles um den Faktor 2 skaliert: Jetzt sind die Seiten der Box doppelt so lang geworden. Schauen Sie sich zum Schluss das Rotationsbeispiel an:
Das Parallelepiped wurde um einen Winkel von 45 ° gedreht, aber der
Sinus und der
Cosinus dieses Winkels werden in der Matrix verwendet. Nach Überprüfung auf einem wissenschaftlichen Taschenrechner können wir sehen, dass
sin (45 °) = 0,7071 ... ist, was auf den angezeigten Wert von 0,71 gerundet ist. Wir erhalten die gleiche Antwort für den
Kosinuswert .
Matrizen und Vektoren sind optional; Eine beliebte Alternative für sie, insbesondere bei komplexen Kurven, ist die Verwendung komplexer Zahlen und
Quaternionen . Diese Berechnungen unterscheiden sich stark von Vektoren, daher werden wir sie nicht berücksichtigen und weiterhin mit Transformationen arbeiten.
Vertex Shader Power
In diesem Stadium müssen wir verstehen, dass all dies von Leuten gemacht wird, die den Rendering-Code programmieren. Wenn ein Spieleentwickler eine Drittanbieter-Engine verwendet (z. B. Unity oder Unreal), wurde dies alles bereits für ihn erledigt. Aber wenn jemand seinen Motor von Grund auf neu herstellt, muss er alle diese Berechnungen mit Eckpunkten durchführen.
Aber wie sieht das alles in Bezug auf Code aus?
Um dies zu verstehen, werden wir Beispiele von der erstaunlichen
Braynzar Soft- Website verwenden. Wenn Sie selbst mit der 3D-Programmierung beginnen möchten, ist dies der richtige Ort, um die Grundlagen sowie komplexere Dinge zu lernen ...
Dies ist ein Beispiel für eine All-in-One-Transformation. Es erstellt die entsprechenden Transformationsmatrizen basierend auf der Tastatureingabe und wendet sie dann in einer Operation auf den ursprünglichen Positionsvektor an. Beachten Sie, dass dies immer in der angegebenen Reihenfolge (Skalierung - Rotation - Übertragung) erfolgt, da das Ergebnis auf jede andere Weise vollständig ruiniert wird.
Solche Codeblöcke werden als
Vertex-Shader bezeichnet . Ihre Komplexität und Größe können sehr unterschiedlich sein. Das obige Beispiel ist einfach, es ist
nur ein Vertex-Shader, der nicht die volle Programmierbarkeit von Shadern nutzt. Eine komplexere Folge von Shadern könnte Objekte im 3D-Raum transformieren, ihr Erscheinungsbild aus Sicht der Szenenkamera verarbeiten und dann Daten in die nächste Stufe des Renderprozesses übertragen. In Anbetracht der Reihenfolge der Scheitelpunktverarbeitung werden wir andere Beispiele untersuchen.
Natürlich können sie für viel mehr verwendet werden. Vergessen Sie also beim Spielen eines 3D-Spiels nicht, dass alle Bewegungen, die Sie sehen, von einer GPU ausgeführt werden, die Vertex-Shader-Befehle ausführt.
Dies war jedoch nicht immer der Fall. Wenn Sie bis Mitte der neunziger Jahre zurückgehen, dann hatten die Grafikkarten dieser Ära nicht die Fähigkeit, Scheitelpunkte und Grundelemente unabhängig voneinander zu verarbeiten, sondern nur der Zentralprozessor.
Einer der ersten Prozessoren mit einer eigenen Hardwarebeschleunigung für diesen Prozess war
Nvidia GeForce, die im Jahr 2000 veröffentlicht wurde. Diese Funktionalität wurde als
Hardware-Transformation und Beleuchtung (kurz Hardware-TnL) bezeichnet. Die Prozesse, mit denen diese Ausrüstung umgehen konnte, waren in Bezug auf die Teams sehr begrenzt, aber mit der Veröffentlichung neuer Chips änderte sich die Situation schnell. Heutzutage gibt es keine separate Ausrüstung für die Verarbeitung von Scheitelpunkten, und ein Gerät erledigt alles auf einmal: Punkte, Grundelemente, Pixel, Texturen usw.
Übrigens zur
Beleuchtung : Es ist erwähnenswert, dass wir dank des Lichts alles sehen. Lassen Sie uns also sehen, wie es im Scheitelpunktstadium verarbeitet werden kann. Dazu müssen wir das nutzen, worüber wir zuvor gesprochen haben.
Licht, Kamera, Motor!
Stellen Sie sich dieses Bild vor: Der Spieler steht in einem dunklen Raum, der von einer Lichtquelle rechts beleuchtet wird. In der Mitte des Raumes steht ein riesiger Wasserkocher. Möglicherweise benötigen Sie dabei Hilfe. Verwenden Sie also die
Echtzeit-Rendering- Website und sehen Sie, wie sie aussieht:
Vergessen Sie nicht, dass dieses Objekt eine Reihe von flachen Dreiecken ist, die miteinander verbunden sind. Das heißt, die Ebene jedes Dreiecks wird in eine bestimmte Richtung gerichtet. Einige von ihnen sind auf die Kamera gerichtet, andere - andere sind verzerrt. Licht von der Quelle fällt auf jede Ebene und wird von ihr in einem bestimmten Winkel reflektiert.
Je nachdem, wo das Licht reflektiert wird, können sich Farbe und Helligkeit der Ebene ändern. Damit die Farbe des Objekts richtig aussieht, muss dies alles berechnet und berücksichtigt werden.
Zunächst müssen wir herausfinden, wohin jede Ebene gerichtet ist, und dazu benötigen wir
den Normalenvektor der Ebene. Dies ist ein weiterer Pfeil, aber im Gegensatz zum Positionsvektor ist seine Größe nicht wichtig (tatsächlich nimmt die Größe der Normalenvektoren nach der Berechnung immer ab, so dass sie eine Länge von 1 haben), und er ist immer
senkrecht (im rechten Winkel) zur Ebene gerichtet.
Die Normale zur Ebene jedes Dreiecks wird berechnet, indem das Vektorprodukt zweier Richtungsvektoren (über
p und
q gezeigt ) bestimmt wird, die die Seiten des Dreiecks bilden. Tatsächlich ist es besser, sie für jeden Scheitelpunkt und nicht für ein Dreieck zu berechnen, aber da es immer mehr von ersteren als von letzteren gibt, ist es schneller, die Normalen für die Dreiecke zu berechnen.
Nachdem Sie die Normalen an der Oberfläche erhalten haben, können Sie beginnen, die Lichtquelle und die Kamera zu betrachten. Beim 3D-Rendering können Lichtquellen unterschiedlichen Typs sein. In diesem Artikel werden jedoch nur
Richtungsquellen betrachtet , z. B. Scheinwerfer. Wie die Ebene des Dreiecks zeigen der Scheinwerfer und die Kamera in eine bestimmte Richtung, ungefähr so:
Der Lichtquellenvektor und der Normalenvektor können verwendet werden, um den Winkel zu berechnen, unter dem Licht auf die Oberfläche fällt (unter Verwendung der Beziehung zwischen dem Skalarprodukt der Vektoren und dem Produkt ihrer Größe). Die Eckpunkte des Dreiecks enthalten zusätzliche Informationen zu Farbe und Material. Material beschreibt, was mit Licht passiert, wenn es auf die Oberfläche trifft.
Eine glatte Metalloberfläche reflektiert fast das gesamte einfallende Licht in dem Winkel, in dem es fällt, und ändert kaum die Farbe des Objekts. Raues mattes Material streut das Licht weniger vorhersehbar und ändert die Farbe geringfügig. Um dies zu berücksichtigen, müssen Sie den Scheitelpunkten zusätzliche Werte hinzufügen:
- Original Grundfarbe
- Umgebungsmaterialattribut - Ein Wert, der bestimmt, wie viel Hintergrundbeleuchtung einen Scheitelpunkt absorbieren und reflektieren kann
- Das Attribut des diffusen Materials ist ein anderer Wert, aber diesmal wird die „Rauheit“ des Scheitelpunkts bestimmt, was wiederum die Absorptions- und Reflexionsmenge des gestreuten Lichts beeinflusst
- Spiegelmaterialattribute - Zwei Werte, die den Scheitelpunktglanz angeben
Verschiedene Beleuchtungsmodelle verwenden unterschiedliche mathematische Formeln, um alle diese Attribute zu gruppieren. Das Ergebnis der Berechnung ist der ausgehende Beleuchtungsvektor. In Kombination mit dem Kameravektor können Sie das Gesamterscheinungsbild des Dreiecks bestimmen.
Eine gerichtete Lichtquelle beleuchtet viele verschiedene Nvidia-DemosWir haben viele detaillierte Details aus gutem Grund weggelassen: Öffnen Sie ein 3D-Rendering-Tutorial, und Sie werden sehen, dass ganze Kapitel diesem Prozess gewidmet sind. In modernen Spielen wird der Großteil aller Berechnungen von Licht- und Materialeffekten jedoch in der Pixelverarbeitungsphase durchgeführt, sodass wir im nächsten Artikel darauf zurückkommen werden.
Beispielcode B. Anguelov zeigt, wie das Phong-Lichtreflexionsmodell im Vertex-Shader verarbeitet werden kann.Alles, was wir oben untersucht haben, wird von Vertex-Shadern ausgeführt, und es scheint, dass für sie nichts unmöglich ist. das ist leider nicht so. Scheitelpunkt-Shader können keine neuen Scheitelpunkte erstellen, und jeder Shader muss jeden einzelnen Scheitelpunkt verarbeiten. Es wäre praktisch, wenn Sie den Code verwenden könnten, um neue Dreiecke zwischen den bereits vorhandenen zu erstellen (um die visuelle Qualität zu verbessern) und einen Shader zu haben, der das gesamte Grundelement verarbeitet (um die Verarbeitung zu beschleunigen). In modernen GPUs können wir
das schaffen !
Bitte, Sir, ich möchte mehr (Dreiecke)
Moderne Grafikchips sind extrem leistungsfähig und können jede Sekunde Millionen von Matrixvektorberechnungen durchführen. Sie können leicht mit einem riesigen Haufen von Gipfeln gleichzeitig fertig werden. Auf der anderen Seite ist das Erstellen sehr detaillierter Modelle für das Rendern ein sehr langer Prozess. Wenn sich das Modell in einiger Entfernung von der Szene befindet, werden alle diese Details verschwendet.
Das heißt, wir müssen dem Prozessor irgendwie befehlen, ein großes Grundelement, beispielsweise ein flaches Dreieck, in eine Reihe kleinerer Dreiecke zu teilen, die sich innerhalb des ursprünglichen Dreiecks befinden. Ein solcher Prozess wird als
Tesselation bezeichnet, und Grafikchips haben bereits gelernt, ihn sehr gut auszuführen. Im Laufe der Jahre der Entwicklung hat der Grad der Kontrolle, den Programmierer über diesen Prozess haben, zugenommen.
Um dies in Aktion zu betrachten, verwenden wir das
Heaven-Benchmark-Tool der Unigine-Engine , da wir damit unterschiedliche Tessellationswerte auf die im Test verwendeten Modelle anwenden können.
. , — , . : Unigine , .
, . , , , ( wireframe):
, — ! , .
Direct3D (
(sub-division) ), .
(hull shader) — ,
(geometry patch) . , , .
- .
(domain shader) , . , , .
? :
, , . , — , , .
wireframe , , , . , .
, Direct3D; -,
RasterTek .
, …
(.
): , , , , , . , Unigine , .
«» !
, , ? , . , , , , , , .
, —
. , . .
UL Benchmark's 3DMark Vantage —Direct3D, API, . (
), . Microsoft
Direct3D , :
(stream output) , , ( ), , .
, , .
— , , . , - .
. ., (GPU) API — , .
3D- ; , . 3D- — , , .