So funktioniert das Rendern von 3D-Spielen: Texturierung und Texturfilterung

Bild

Im dritten Artikel zum Rendern in 3D-Spielen werden wir herausfinden, was mit der 3D-Welt passiert, nachdem die Vertex-Verarbeitung verarbeitet und die Szene gerastert wurde. Die Texturierung ist eine der wichtigsten Stufen des Renderns, obwohl nur die Farben eines zweidimensionalen Gitters aus mehrfarbigen Blöcken berechnet und geändert werden.

Die meisten visuellen Effekte in modernen Spielen beschränken sich auf den bewussten Einsatz von Texturen - ohne sie würden Spiele langweilig und leblos erscheinen. Also mal sehen, wie das alles funktioniert!

Teil 1: Vertex-Verarbeitung

Teil 2: Rasterisierung und Raytracing

Beginnen wir mit einem einfachen


Sie können alle dreidimensionalen Bestseller-Spiele verwenden, die im letzten Jahr veröffentlicht wurden, und mit Zuversicht sagen, dass sie alle etwas gemeinsam haben: Sie verwenden Textur-Maps (oder nur Texturen ). Dies ist ein so gebräuchlicher Begriff, dass die meisten Menschen beim Nachdenken über Texturen dasselbe Bild präsentieren: ein einfaches flaches Quadrat oder Rechteck, das ein Bild einer Oberfläche (Gras, Stein, Metall, Stoff, Gesicht usw.) enthält.

Bei Verwendung und Kombination komplexer Berechnungen können solche einfachen Bilder in einer 3D-Szene jedoch erstaunlich realistische Bilder erzeugen. Um zu verstehen, wie dies möglich ist, schalten wir sie vollständig aus und sehen, wie die Objekte der 3D-Welt ohne Texturen aussehen.

Wie wir aus früheren Artikeln gesehen haben, besteht die 3D-Welt aus Eckpunkten - einfachen Formen, die sich bewegen und dann kolorieren. Sie werden dann verwendet, um Grundelemente zu erstellen, die wiederum zu einem zweidimensionalen Pixelraster komprimiert werden. Da wir keine Texturen verwenden, müssen wir diese Pixel einfärben.

Eine der Methoden, die angewendet werden kann, heißt flache Schattierung : Die Farbe des ersten Scheitelpunkts des Grundelements wird übernommen, und diese Farbe wird dann auf alle Pixel angewendet, die von der Figur im Raster abgedeckt werden. Es sieht ungefähr so ​​aus:


Offensichtlich sieht der Wasserkocher unrealistisch aus, nicht zuletzt wegen unregelmäßiger Oberflächenfarben. Farben springen von einer Ebene zur anderen, es gibt keine glatten Übergänge. Eine Lösung für das Problem könnte die Verwendung der Gouraud-Schattierung sein .

In diesem Prozess werden die Farben der Eckpunkte genommen, wonach die Farbänderung entlang der Oberfläche des Dreiecks berechnet wird. Hierzu wird eine lineare Interpolation verwendet . Es klingt kompliziert, aber in Wirklichkeit bedeutet dies, dass wenn beispielsweise eine Seite des Grundelements eine Farbe von 0,2 Rot und die andere eine Farbe von 0,8 Rot hat, die Mitte der Figur eine Farbe in der Mitte zwischen 0,2 und 0,8 (d. H. 0,5) hat.

Dieser Prozess ist einfach genug, und dies ist sein Hauptvorteil, weil Einfachheit Geschwindigkeit bedeutet. Viele ältere 3D-Spiele verwendeten diese Technik, da die Fähigkeiten der Computerausrüstung eingeschränkt waren.


Barrett und Cloud in all der Größe der Gouraud-Schattierung (Final Fantasy VII, 1997)

Aber selbst eine solche Lösung hat Probleme - wenn das Licht genau in die Mitte des Dreiecks fällt, können seine Ecken (und Eckpunkte) diese Eigenschaft möglicherweise nicht vermitteln. Dies bedeutet, dass die durch Licht erzeugte Blendung vollständig verloren gehen kann.

Obwohl Gourauds flache Schattierung und Schattierung ihren rechtmäßigen Platz in den Rendering-Werkzeugen eingenommen haben, sind die oben gezeigten Beispiele klare Kandidaten für eine Texturverbesserung. Und um gut zu verstehen, was passiert, wenn die Textur der Oberfläche überlagert wird, werden wir in die Vergangenheit reisen ... bereits 1996.

Spiel- und GPU-Geschichte in Kürze


Vor ungefähr 23 Jahren veröffentlichte id Software Quake und es wurde ein wichtiger Meilenstein. Obwohl dies nicht das erste Spiel war, das 3D-Polygone und -Texturen zum Rendern von Umgebungen verwendete, war es definitiv eines der ersten, das sie effektiv nutzte.

Aber sie hat noch etwas anderes gemacht - sie hat gezeigt, was mit OpenGL gemacht werden kann (diese Grafik-API befand sich damals im ersten Versionszustand) und auch der ersten Generation von Grafikkarten wie Rendition Verite und 3Dfx Voodoo wirklich geholfen .


Lichtspitzen und einfache Texturen. Sauber 1996, sauberes Beben.

Für moderne Verhältnisse war Voodoo extrem einfach: keine Unterstützung für 2D-Grafiken, keine Scheitelpunktverarbeitung, nur die einfachste Pixelverarbeitung. Sie war jedoch wunderschön:


Bild: VGA Museum

Sie hatte einen ganzen Chip (TMU), um ein Pixel aus der Textur zu erhalten, und einen weiteren Chip (FBI), um es später mit einem Rasterpixel zu mischen. Die Karte könnte einige zusätzliche Prozesse ausführen, zum Beispiel die Implementierung von Nebel- oder Transparenzeffekten, aber dies beendete im Wesentlichen ihre Fähigkeiten.

Wenn wir uns die Architektur ansehen, die der Struktur und dem Betrieb der Grafikkarte zugrunde liegt, werden wir sehen, wie diese Prozesse funktionieren.


3Dfx-Spezifikation. Quelle: Falconfly Central

Der FBI-Chip erhielt zwei Farbwerte und mischte sie; Einer von ihnen könnte ein Wert aus einer Textur sein. Der Mischvorgang ist mathematisch recht einfach, variiert jedoch geringfügig, je nachdem, was gemischt wird und welche API zum Ausführen der Anweisungen verwendet wird.

Wenn Sie sich ansehen, was Direct3D uns in Bezug auf Funktionen und Mischvorgänge bietet , werden Sie feststellen, dass jedes Pixel zuerst mit einer Zahl von 0,0 bis 1,0 multipliziert wird. Dies bestimmt, wie stark die Farbe des Pixels das Endergebnis beeinflusst. Dann werden zwei geänderte Pixelfarben addiert, subtrahiert oder multipliziert; In einigen Funktionen wird eine logische Operation ausgeführt, bei der beispielsweise immer das hellste Pixel ausgewählt wird.


Bild: Tech-Blog der Initiative nehmen

Das obige Bild zeigt, wie dies in der Praxis funktioniert. Beachten Sie, dass der Pixel- Alpha- Wert als Koeffizient für das linke Pixel verwendet wird. Diese Zahl gibt den Grad der Transparenz des Pixels an.

In anderen Phasen wird der Nebelwert angewendet (er wird aus der vom Programmierer erstellten Tabelle entnommen und anschließend werden dieselben Mischungsberechnungen durchgeführt). Durchführung von Überprüfungen und Änderungen der Sichtbarkeit und Transparenz; Am Ende wird die Pixelfarbe in den Speicher der Grafikkarte geschrieben.

Warum brauchen Sie diesen Ausflug in die Geschichte? Nun, trotz der relativen Einfachheit des Designs (insbesondere im Vergleich zu modernen Monstern) beschreibt dieser Prozess die Grundprinzipien der Texturierung: Wir nehmen die Werte der Farben und mischen sie so, dass die Modelle und Umgebungen in einer bestimmten Situation so aussehen, wie sie sollten.

Moderne Spiele machen dasselbe, der einzige Unterschied ist die Anzahl der verwendeten Texturen und die Komplexität der Mischungsberechnungen. Zusammen simulieren sie die visuellen Effekte von Filmen oder die Interaktion von Licht mit verschiedenen Materialien und Oberflächen.

Texturierungsgrundlagen


Für uns ist eine Textur ein flaches 2D-Bild, das den Polygonen überlagert ist, aus denen die 3D-Struktur im Rahmen besteht. Für einen Computer ist dies jedoch nur ein kleiner Speicherblock in Form eines 2D-Arrays. Jedes Element des Arrays bezeichnet den Farbwert eines der Pixel im Texturbild (üblicherweise als Texel - Texturpixel bezeichnet).

Jeder Scheitelpunkt des Polygons hat einen Satz von zwei Koordinaten (normalerweise als u, v bezeichnet ), die dem Computer mitteilen, welches Pixel der Textur ihm zugeordnet ist. Der Scheitelpunkt selbst hat einen Satz von drei Koordinaten ( x, y, z ), und das Verknüpfen von Texeln mit den Scheitelpunkten wird als Texturabbildung bezeichnet .

Um zu sehen, wie dies geschieht, wenden wir uns dem Tool zu, das wir bereits mehrmals in dieser Artikelserie verwendet haben - Real Time Rendering WebGL . Im Moment verwerfen wir auch die z- Koordinate der Eckpunkte und betrachten alles auf einer flachen Ebene.


Von links nach rechts: die u, v- Koordinaten der Textur, die direkt mit den x, y- Koordinaten der Eckscheitelpunkte verknüpft sind . Im zweiten Bild werden die y- Koordinaten an den oberen Eckpunkten erhöht , aber da die Textur immer noch an ihnen befestigt ist, wird sie vertikal gestreckt. Die Textur wurde bereits im rechten Bild geändert: Die u- Werte haben zugenommen, aber infolgedessen wurde die Textur komprimiert und dann wiederholt.

Dies geschah, weil trotz der Tatsache, dass die Textur aufgrund des erhöhten Wertes von u tatsächlich höher geworden ist , sie immer noch in das Grundelement passen sollte - tatsächlich wiederholte sich die Textur teilweise. Dies ist eine Möglichkeit, den in 3D-Spielen häufig vorkommenden Effekt zu implementieren: Wiederholen von Texturen. Beispiele für diesen Effekt sind Szenen mit steinigen oder grasbewachsenen Landschaften sowie mit Backsteinmauern.

Ändern wir nun die Szene, sodass mehr Grundelemente vorhanden sind, und geben die Tiefe der Szene erneut zurück. Die klassische Landschaftsansicht wird unten gezeigt, aber jetzt wird die Box-Textur kopiert und für alle Grundelemente wiederholt.


Die Box-Textur im ursprünglichen GIF-Format hat eine Größe von 66 KB und eine Auflösung von 256 x 256 Pixel. Die anfängliche Auflösung des Teils des Rahmens, der von den Box-Texturen abgedeckt wird, beträgt 1900 x 680, dh aus Sicht des Pixel-Bereichs sollte ein solcher Bereich nur 20 Box-Texturen anzeigen.

Es ist jedoch offensichtlich, dass wir viel mehr als zwanzig Kästchen sehen. Dies bedeutet, dass die Textur des Kästchens in der Ferne viel kleiner als 256 x 256 Pixel sein sollte. In der Tat haben sie einen Prozess namens "Texturminimierung" durchlaufen (ja, ein solches Wort existiert auf Englisch!). Wiederholen wir dies jetzt, aber diesmal bringen Sie die Kamera näher an eine der Schubladen.


Vergessen Sie nicht, dass die Textur nur 256 x 256 Pixel groß ist, aber hier sehen wir eine Textur, die größer als die Hälfte des Bildes ist und eine Breite von 1900 Pixel hat. Diese Textur wurde einer "Texturvergrößerung" unterzogen .

Diese beiden Texturprozesse treten in 3D-Spielen ständig auf, denn wenn sich die Kamera in der Szene bewegt, nähern sich die Modelle oder bewegen sich weg, und alle auf die Grundelemente angewendeten Texturen müssen zusammen mit den Polygonen skaliert werden. Aus mathematischer Sicht ist dies ein kleines Problem. Selbst die einfachsten integrierten Grafikchips können einen solchen Job problemlos ausführen. Das Verkleinern und Vergrößern von Texturen ist jedoch eine neue Herausforderung, die auf irgendeine Weise angegangen werden muss.

Mini-Kopien von Texturen erscheinen in der Szene


Das erste Problem, das für Texturen gelöst werden muss, ist die Entfernung. Wenn wir zum ersten Bild mit einer Landschaft aus Kästchen zurückkehren, haben die Kästchen in der Nähe des Horizonts tatsächlich nur eine Größe von wenigen Pixeln. Daher ist der Versuch, ein Bild mit 256 x 256 Pixel auf so kleinem Raum zu komprimieren, aus zwei Gründen sinnlos.

Erstens nimmt die kleinere Textur weniger Speicherplatz auf der Grafikkarte ein, was praktisch ist, da Sie versuchen können, sie in einen kleineren Cache einzupassen. Dies bedeutet, dass es weniger wahrscheinlich ist, dass es aus dem Cache gelöscht wird, dh, die wiederholte Verwendung dieser Textur führt zu einer höheren Leistung, da sich die Daten im engen Speicher befinden. Aus dem zweiten Grund werden wir bald zurückkehren, da dies mit demselben Problem verbunden ist, das bei Texturen in der Nähe der Kamera auftritt.

Die Standardlösung für das Problem der Notwendigkeit, große Texturen in kleine Grundelemente zu komprimieren, ist die Verwendung von Mip-Texturen (Mipmaps) . Dies sind verkleinerte Versionen der ursprünglichen Textur. Sie können von der Engine selbst (mithilfe der entsprechenden API-Befehle) generiert oder von Spieledesignern vorab erstellt werden. Jede nachfolgende Ebene der Mip-Textur hat eine halbe Größe im Vergleich zur vorherigen.

Das heißt, für die Box-Textur betragen die Abmessungen: 256 x 256 → 128 x 128 → 64 x 64 → 32 x 32 → 16 x 16 → 8 x 8 → 4 x 4 → 2 x 2 → 1 x 1.


Alle Mip-Texturen sind zusammen gepackt, sodass die Textur denselben Dateinamen hat, jedoch größer wird. Die Textur ist so gepackt, dass die u, v- Koordinaten nicht nur bestimmen, welches Texel dem Pixel im Rahmen überlagert ist, sondern auch mit welcher Mip-Textur. Dann schreiben die Programmierer einen Renderer, der auf dem Wert der Pixeltiefe des Rahmens basiert und bestimmt, welche Mip-Textur verwendet werden soll. Wenn der Wert beispielsweise sehr hoch ist, ist das Pixel weit entfernt, was bedeutet, dass Sie eine kleine Mip-Textur verwenden können.

Aufmerksame Leser konnten das Fehlen von Mip-Texturen bemerken - sie müssen dafür bezahlen, indem sie die Größe der Texturen erhöhen. Die ursprüngliche Textur der Box war 256 x 256 Pixel, aber wie Sie im obigen Bild sehen können, hat die Textur mit Mip-Texturen jetzt eine Größe von 384 x 256. Ja, sie hat viel leeren Raum, aber egal wie wir kleinere Texturen im Allgemeinen verpacken Die Größe der Textur auf einer Seite erhöht sich um mindestens 50%.

Dies gilt jedoch nur für zuvor erstellte Mip-Texturen. Wenn die Spiel-Engine so programmiert ist, dass sie korrekt generiert wird, beträgt die Erhöhung nicht mehr als 33% der ursprünglichen Texturgröße. Aufgrund einer geringfügigen Erhöhung des Speicherplatzes zum Speichern von Mip-Texturen erhalten wir daher einen Gewinn an Leistung und visueller Qualität.

Unten finden Sie einen Vergleich von Bildern mit deaktivierten / aktivierten Mip-Texturen:


Auf der linken Seite des Bildes wurden die Texturen der Boxen "wie sie sind" verwendet, was zum Auftreten von Granularität und dem sogenannten Moiré in der Ferne führte. Rechts ermöglichte die Verwendung von Mip-Texturen glattere Übergänge, und am Horizont wird die Textur der Box in eine einheitliche Farbe verwischt.

Wer möchte jedoch, dass verschwommene Texturen die Hintergründe seines Lieblingsspiels verderben?

Bilinear, trilinear, anisotrop - das alles ist für mich ein chinesischer Buchstabe


Das Auswählen eines Pixels aus einer Textur, um es einem Pixel in einem Frame zu überlagern, wird als Abtasttexturen bezeichnet . In einer idealen Welt würde es eine Textur geben, die ideal zu dem Grundelement passt, für das es entworfen wurde, unabhängig von Größe, Position, Richtung usw. Mit anderen Worten, das Abtasten der Textur wäre eine einfache Eins-zu-Eins-Texel-Pixelabbildung.

Da dies jedoch nicht der Fall ist, müssen beim Abtasten von Texturen mehrere Faktoren berücksichtigt werden:

  • Wurde die Textur verkleinert oder vergrößert?
  • Ist die Textur eine Quell- oder Mip-Textur?
  • In welchem ​​Winkel wird die Textur angezeigt?

Lassen Sie uns sie der Reihe nach analysieren. Der erste Faktor ist ziemlich offensichtlich: Wenn die Textur erhöht wurde, gibt es im Grundelement mehr Texel, die das Pixel im Grundelement bedecken, als erforderlich; Beim Verringern ist das Gegenteil der Fall - jedes Texel sollte jetzt mehrere Pixel abdecken. Und das ist ein Problem.

Der zweite Faktor verursacht keine Probleme, da Mip-Texturen verwendet werden, um das Problem der Abtastung der Texturen weit entfernter Grundelemente zu umgehen. Die einzige Aufgabe besteht darin, die Texturen in einem Winkel anzuzeigen. Und ja, das ist auch ein Problem. Warum? Weil alle Texturen Bilder sind, die für die Anzeige „streng vor“ generiert wurden. In mathematischer Sprache entspricht die normale Oberflächentextur dem Nennwert der Oberfläche, auf dem die Textur aktuell angezeigt wird.

Wenn daher zu wenige oder zu viele Texel vorhanden sind oder sich in einem Winkel befinden, ist ein zusätzlicher Prozess erforderlich, der als "Texturfilterung" bezeichnet wird . Wenn dieser Prozess nicht verwendet wird, erhalten wir Folgendes:


Hier haben wir die Textur der Box durch eine Textur mit dem Buchstaben R ersetzt, um deutlicher zu zeigen, in welches Chaos das Bild gerät, ohne Texturen zu filtern!

Grafik-APIs wie Direct3D, OpenGL und Vulkan bieten dieselben Filtertypen, verwenden jedoch unterschiedliche Namen. Tatsächlich laufen sie alle auf Folgendes hinaus:

  • Near Point Sampling
  • Lineare Texturfilterung
  • Anisotrope Texturfilterung

Tatsächlich ist das Abtasten der nächsten Punktabtastung kein Filter, da damit nur das nächste Texel des erforderlichen Texturpixels abgetastet wird (z. B. aus dem Speicher kopiert) und dann mit der ursprünglichen Farbe des Pixels gemischt wird.

Hier hilft uns die lineare Filterung. Die erforderlichen Texelkoordinaten u, v werden an die Abtastausrüstung übertragen, aber anstatt das diesen Koordinaten am nächsten liegende Texel zu nehmen, nimmt der Abtastgerät vier Texel. Hierbei handelt es sich um Texel, die sich oberhalb, unterhalb, links und rechts des Texels befinden, das durch Abtasten der nächstgelegenen Punkte ausgewählt wird.

Diese vier Texel werden dann unter Verwendung einer Formel mit Gewichten gemischt. In Vulkan sieht die Formel beispielsweise folgendermaßen aus:


T bezeichnet die Texelfarbe, wobei f das Ergebnis der Filtration ist und 1-4 die Farbe von vier abgetasteten Texeln ist. Alpha- und Beta- Werte werden abhängig davon genommen, wie weit der Punkt mit den Koordinaten u, v von der Mitte der Textur entfernt ist.

Zum Glück für diejenigen, die mit 3D-Grafiken zu tun haben, geschieht dies automatisch im Grafikchip. Genau das hat der TMU-Chip der 3dfx Voodoo-Karte getan: Er hat vier Texel abgetastet und sie dann zusammengemischt. In Direct3D hat dieser Prozess einen seltsamen Namen für die bilineare Filterung.Aber seit den Tagen von Quake und dem TMU-Chip haben Grafikkarten bereits gelernt, wie man eine bilineare Filterung in nur einem Taktzyklus durchführt (natürlich, wenn sich die Textur bereits im nächsten Speicher befindet).

Die lineare Filterung kann zusammen mit Mip-Texturen verwendet werden. Wenn Sie die Filterung komplizieren möchten, können Sie vier Texel aus der Textur und vier weitere aus der nächsten Ebene der Mip-Textur entnehmen und alle mischen. Und wie heißt es in Direct3D? Trilineare Filterung. Woher kamen die „drei“ in diesem Prozess ? Wir wissen es also nicht ...

Die letzte erwähnenswerte Filtermethode ist anisotrop . Tatsächlich ist es eine Verbesserung des Prozesses, der durch bilineare oder trilineare Filterung durchgeführt wird. Zunächst wird berechnetder Grad der Anisotropie der primitiven Oberfläche (und dies ist ein überraschend komplexer Prozess ) - dieser Wert erhöht die Änderung des Seitenverhältnisses des primitiven aufgrund seiner Orientierung:


Die obige Abbildung zeigt dasselbe quadratische Grundelement mit gleichen Seitenlängen. aber allmählich dreht es sich in ein Rechteck, und seine Breite ändert sich mehr als seine Höhe. Daher hat das Grundelement rechts einen höheren Anisotropiegrad als links (und im Fall eines Quadrats ist der Grad Null).

In vielen modernen 3D-Spielen können Sie die anisotrope Filterung aktivieren und dann ihre Stufe ändern (von 1x auf 16x). Aber was ändert sich wirklich? Dieser Parameter steuert die maximale Anzahl zusätzlicher Texel-Samples, die in jedem anfänglichen linearen Sample entnommen werden. Angenommen, eine anisotrope bilineare Filterung von 8x ist im Spiel aktiviert. Dies bedeutet, dass anstelle von vier Texelwerten 32 Werte erhalten werden.

Der Unterschied bei der Verwendung der anisotropen Filterung ist deutlich zu erkennen:


Gehen Sie einfach zum obigen Bild und vergleichen Sie die Abtastung der nächstgelegenen Punkte mit einer maximal 16-fachen anisotropen trilinearen Filterung. Erstaunlich glatt!

Für diese glatte Schönheit von Texturen müssen Sie jedoch mit Leistung bezahlen: Bei maximalen Einstellungen erhält die anisotrope trilineare Filterung 128 Abtastwerte aus der Textur für jedes Pixel des Renderings. Selbst mit den besten modernen GPUs kann dies nicht in einem Taktzyklus erreicht werden.

Wenn Sie zum Beispiel AMD Radeon RX 5700 XT nehmenDann kann jeder der Texturierungsblöcke im Prozessor bis zu 32 Texeladressen in einem Taktzyklus verwenden und dann im nächsten Taktzyklus 32 Texelwerte aus dem Speicher laden (von denen jeder eine Größe von 32 Bit hat) und dann vier davon in einem weiteren mischen Takt. Das heißt, um 128 Texel-Samples zu einem zu mischen, sind mindestens 16 Taktzyklen erforderlich.


GPU AMD RDNA Radeon RX 5700 mit 7-Nanometer-Prozesstechnologie

Wenn die Taktrate des 5700 XT 1605 MHz beträgt, dauern 16 Zyklen nur 10 Nanosekunden . Das Ausführen dieser Zyklen für jedes Pixel in einem 4K-Frame mit nur einer Textureinheit dauert nur 70 Millisekunden. Großartig, es sieht so aus, als wäre Leistung keine große Sache!

Bereits 1996 kamen 3Dfx Voodoo und ähnliche Karten schnell mit Texturen zurecht. Sie konnten höchstens 1 Texel mit bilinearer Filterung pro Zyklus ausgeben, und mit einer TMU-Chipfrequenz von 50 MHz konnten 50 Millionen Texel pro Sekunde verarbeitet werden. Ein Spiel mit 800 x 600 und 30 fps benötigt nur 14 Millionen Texel mit bilinearer Filterung pro Sekunde.

Dies gilt jedoch nur unter der Annahme, dass sich alle Texturen im nächsten Speicher befinden und nur ein Texel jedem Pixel entspricht. Vor zwanzig Jahren war die Idee, mehrere Texturen auf ein Primitiv zu legen, völlig fremd, aber heute ist es ein Standard. Mal sehen, warum sich das alles ändert.

Beleuchtung hinzufügen


Um zu verstehen, warum Texturierung so wichtig geworden ist, schauen Sie sich diese Szene aus Quake an:


Dies ist ein dunkles Bild, weil Dunkelheit die Atmosphäre des Spiels war, aber wir sehen, dass die Dunkelheit nicht überall gleich ist - einige Fragmente von Wänden und Böden sind heller als andere, was in diesen Bereichen ein Gefühl von Helligkeit erzeugt.

Die Grundelemente, aus denen die Wände und der Boden bestehen, werden mit denselben Texturen überlagert. Es gibt jedoch eine andere Textur, die als „Lichtkarte“ bezeichnet wird und mit den Werten der Texel gemischt wird, bevor sie auf die Rahmenpixel angewendet werden. In Bebenzeiten wurden Beleuchtungskarten im Voraus berechnet und von der Spiel-Engine erstellt. Sie wurden verwendet, um statische und dynamische Beleuchtungsstärken zu erzeugen.

Der Vorteil ihrer Verwendung besteht darin, dass komplexe Beleuchtungsberechnungen eher mit Texturen als mit Scheitelpunkten durchgeführt wurden, was das Erscheinungsbild der Szene auf Kosten niedriger Geschwindigkeitskosten erheblich verbesserte. Offensichtlich ist das Bild nicht perfekt: Auf dem Boden fällt auf, dass die Grenze zwischen den beleuchteten Bereichen und den Schatten sehr scharf ist.

In vielerlei Hinsicht ist eine Lightmap nur eine andere Textur (vergessen Sie nicht, dass es sich bei allen um reguläre 2D-Datensätze handelt). Daher ist diese Szene eines der ersten Beispiele für die Verwendung von Multitexturing. Wie der Name schon sagt, ist dies ein Prozess, bei dem zwei oder mehr Texturen einem Grundelement überlagert werden. Die Verwendung von Beleuchtungskarten in Quake ist zu einer Möglichkeit geworden, die Einschränkungen der Gouraud-Schattierung zu überwinden. Mit der Erweiterung des Funktionsumfangs von Grafikkarten wurden jedoch auch die Möglichkeiten zur Anwendung von Multitexturing erweitert.

3Dfx Voodoo war, wie viele andere Karten dieser Zeit, in der Anzahl der Operationen begrenzt, die es in einem einzigen Rendering- Durchgang ausführen konnte . Tatsächlich ist ein Durchlauf ein vollständiger Renderzyklus: von der Verarbeitung von Scheitelpunkten bis zur Rasterung des Frames, dem anschließenden Ändern der Pixel und dem Schreiben in den fertigen Frame-Puffer. Vor zwanzig Jahren verwendeten Spiele fast immer One-Pass-Rendering.


Nvidia GeForce 2 Ultra, gegen Ende 2000. Bild: Wikimedia

Dies geschah, weil die zweite Vertex-Verarbeitung nur zum Anwenden zusätzlicher Texturen in Bezug auf die Leistung zu kostspielig war. Nach Voodoo mussten wir einige Jahre warten, bis die Grafikkarten ATI Radeon und Nvidia GeForce 2 erschienen, die in einem Durchgang multitexturiert werden konnten.

Diese GPUs hatten mehrere Textureinheiten im Pixelverarbeitungsbereich ( dh in der Pipeline ), so dass das Erhalten eines Texels mit bilinearer Filterung aus zwei getrennten Texturen die einfachste Aufgabe wurde. Dies erhöhte die Beliebtheit von Beleuchtungskarten weiter und ermöglichte es den Spielen, sie vollständig dynamisch zu gestalten und die Beleuchtungswerte abhängig von den Bedingungen der Spielumgebung zu ändern.

Mit ein paar Texturen könnte jedoch noch viel mehr getan werden. Lassen Sie uns also ihre Fähigkeiten untersuchen.

Das Ändern der Höhe ist normal


In dieser Artikelserie über 3D-Rendering haben wir nicht darüber gesprochen, wie sich die Rolle der GPU auf den gesamten Prozess auswirkt (wir werden darüber sprechen, aber nicht jetzt!). Wenn Sie jedoch zu Teil 1 zurückkehren und den gesamten komplexen Prozess der Verarbeitung von Scheitelpunkten lesen, denken Sie möglicherweise, dass dies der schwierigste Teil aller Arbeiten ist, die die GPU ausführen muss.

Lange Zeit war es so, und Spielprogrammierer haben alles getan, um diese Last zu reduzieren. Sie mussten alle möglichen Tricks anwenden, um die gleiche Bildqualität wie bei der Verwendung mehrerer Scheitelpunkte sicherzustellen, diese jedoch nicht verarbeiten.

Die meisten dieser Tricks verwendeten Texturen, die als Höhenkarten und normale Karten bezeichnet werden.. Diese beiden Konzepte sind durch die Tatsache verbunden, dass das letztere aus dem ersteren erstellt werden kann. Betrachten wir jedoch zunächst nur eine Technik namens „Bump Mapping“ .


Bilder, die in einem Demo-Rendering von Emil Persson erstellt wurden . Die geprägte Texturierung ist deaktiviert / aktiviert. Bei der geprägten Texturierung

wird ein 2D-Array verwendet, das als „Höhenkarte“ bezeichnet wird und wie eine seltsame Version der ursprünglichen Textur aussieht. Das obige Bild zeigt beispielsweise eine realistische Ziegelstruktur, die auf zwei ebenen Flächen liegt. Die Textur und ihre Höhenkarte sehen folgendermaßen aus:


Die Farben der Höhenkarte geben die Normalen der Oberfläche der Steine ​​an (wir haben in Teil 1 einer Artikelserie über die Normalen gesprochen ). Wenn der Rendervorgang das Stadium des Aufbringens der Ziegelstruktur auf die Oberfläche erreicht, wird eine Reihe von Berechnungen durchgeführt, um die Farbe der Ziegelstruktur basierend auf ihren Normalen zu ändern.

Infolgedessen sehen die Steine ​​selbst dreidimensionaler aus, obwohl sie weiterhin vollständig flach bleiben. Wenn Sie genau hinschauen, insbesondere an den Rändern der Steine, können Sie die Einschränkungen dieser Technik erkennen: Die Textur sieht leicht verzerrt aus. Dies ist jedoch ein schneller Trick, mit dem Sie mehr Oberflächendetails hinzufügen können. Daher ist die geprägte Texturierung sehr beliebt.

Eine normale Karte ähnelt einer Höhenkarte, nur die Texturfarben sind die Normalen selbst. Mit anderen Worten, Berechnungen zum Konvertieren der Höhenkarte in Normal sind nicht erforderlich. Sie können eine Frage stellen: Wie können Farben einen Vektor im Raum beschreiben? Die Antwort ist einfach: Jedes Texel hat eine Menge von r-, g-, b- Werten (rot, grün, blau) und diese Werte entsprechen direkt den x-, y- und z- Werten des Normalenvektors.


Das linke Diagramm zeigt die Richtungsänderung der Normalen auf einer unebenen Oberfläche. Um dieselben Normalen mit einer flachen Textur (mittlerer Umriss) zu beschreiben, weisen wir ihnen Farben zu. In diesem Fall haben wir die Werte r, g, b (0,255,0) für den Vektor verwendet, der gerade nach oben gerichtet ist, und dann den Wert von Rot für die Neigung nach links und Blau für die Neigung nach rechts erhöht.

Beachten Sie, dass diese Farbe nicht mit dem Originalpixel gemischt wird. Sie teilt dem Prozessor lediglich mit, in welche Richtung die Normalen zeigt, damit die Winkel zwischen Kamera, Lichtquellen und strukturierter Oberfläche korrekt berechnet werden können.

Die Vorteile von geprägten Texturen und normalen Karten liegen voll auf der Hand, wenn dynamische Beleuchtung in der Szene verwendet wird und wenn der Renderprozess den Effekt der Beleuchtungsänderung Pixel für Pixel berechnet und nicht für jeden Scheitelpunkt. Heutzutage verwenden moderne Spiele eine Reihe von Texturen, um die Qualität dieses Tricks zu verbessern.


Bild: Ryan Benno von Twitter

Überraschenderweise ist diese realistisch aussehende Wand nur eine flache Oberfläche. Die Details von Ziegeln und Mauerzement werden nicht aus Millionen von Polygonen hergestellt. Stattdessen reichen nur fünf Texturen und der durchdachte Einsatz von Berechnungen aus.

Eine Höhenkarte wurde verwendet, um Schattenwurf mit Ziegeln zu erzeugen, und eine normale Karte wurde verwendet, um alle geringfügigen Oberflächenänderungen zu simulieren. Die Rauheitstextur wurde verwendet, um die Art und Weise zu ändern, in der Licht von verschiedenen Elementen der Wand reflektiert wird (zum Beispiel reflektiert glatter Ziegel das Licht gleichmäßiger als rauer Zement).

Die letzte Karte, die im AO-Bild benannt ist, erzeugt einen Teil des Prozesses, der als Umgebungsokklusion bezeichnet wird: Wir werden diese Technik in den folgenden Artikeln genauer untersuchen, aber nehmen wir zunächst an, dass sie dazu beiträgt, den Realismus von Schatten zu erhöhen.

Texture Mapping ist ein kritischer Prozess.


Texturierung ist bei der Entwicklung von Spielen unbedingt erforderlich. Nehmen wir zum Beispiel das Spiel Kingdom Come: Deliverance aus dem Jahr 2019 , ein Rollenspiel aus der ersten Person, das im 15. Jahrhundert in Böhmen spielt. Designer wollten die realistischste Welt dieser Zeit schaffen. Und um den Spieler in das Leben vor Hunderten von Jahren einzutauchen, ist es am besten, eine historisch korrekte Landschaft, Gebäude, Kleidung, Frisuren, Alltagsgegenstände und vieles mehr zu implementieren.

Jede Textur in diesem Bild aus dem Spiel wurde manuell von Künstlern erstellt und auch dank einer von Programmierern gesteuerten Rendering-Engine. Einige von ihnen sind klein, mit einfachen Details und werden daher leicht gefiltert oder mit anderen Texturen (z. B. Hühnerflügeln) verarbeitet.


Andere haben eine hohe Auflösung und viele kleine Details; Sie werden anisotrop gefiltert und mit normalen Karten und anderen Texturen gemischt. Schauen Sie sich einfach das Gesicht der Person im Vordergrund an. Der Unterschied in den Texturierungsanforderungen jedes Szenenobjekts wird von Programmierern berücksichtigt.

All dies geschieht heute in vielen Spielen, weil die Spieler immer mehr Details und Realismus erwarten. Texturen werden größer und immer mehr von ihnen überlagern die Oberfläche, aber der Prozess des Abtastens von Texeln und des Überlagerns von Pixeln bleibt im Wesentlichen der gleiche wie in den Tagen von Quake. Die besten Technologien sterben nie, egal wie alt sie sind!

All Articles