Warum verwenden wir nicht die gesamte Farbtiefe für normale Karten?


7

Alle normalen Karten, die ich gesehen habe, sind rosa oder bläulich. Es scheint, dass nur ein kleiner Farbbereich verwendet wird. Warum verschenken Spieleentwickler so viel Präzision?

Antworten:


11

Die Farben in einer normalen Karte repräsentieren die Normalen an jedem Punkt. Wenn ein normal ist (x, y, z), wird der entsprechende Bildpunkt in der normalen Karte haben jeweils x, yund zaus dem Bereich zugeordnet , (-1,1)um (0,255)auf die roten, grünen zu erhalten und Blau - Komponenten sind.

Jetzt wird die z-Achse typischerweise als Richtung von der Oberfläche weg verwendet. Eine perfekt ebene Fläche, so Normalen am (0, 0, 1)ganzen Körper , hat xund ybeide abgebildet 128und zabgebildet 255. Das heißt, die resultierende Farbe ist (128, 128, 255)das Himmelblau, das Sie häufig in normalen Karten sehen.

Die Unebenheiten in einer Oberfläche weichen von dieser Normalität ab, entfernen ein wenig von der blauen Komponente und geben sie an die roten und / oder grünen Komponenten weiter (abhängig davon, in welche Richtung die Unebenheit zeigt). Im Allgemeinen sind die Unebenheiten in Oberflächen nicht besonders übertrieben, sodass die normale Karte größtenteils blau bleibt. Sie sehen Magentas und Cyan für die Unebenheiten entlang der x- und y-Achse.

Wenn Sie die normale Karte für eine Oberfläche mit starken Unebenheiten gefunden haben, z. B. eine normale Ziegelkarte , werden Sie feststellen, dass die Kanten sehr rot und grün sind.


Der Hauptgrund dafür, dass die verfügbare Farbtiefe nicht für jeden Kanal verwendet wird, ist, dass die Normalen normalisiert gespeichert werden. Würde es nicht zu einer besseren Präzision führen, stattdessen nicht normalisierte Normalen zu verwenden?
Danijar

Dann hätten Sie zu wenig Präzision für tatsächliche Daten. Alles, was uns wichtig ist, ist die Richtung und nicht die Größe für normale Karten.
Sean Middleditch

Ist eine leere normale Karte tiefblau oder hellblau, wie die meisten normalen Karten aussehen? Das würde mir sehr helfen zu verstehen.
Danijar

1
@danijar Was meinst du mit leer? Es gibt kein leeres Normal. Ein Normaler zeigt immer in eine Richtung. Wenn die Normalen direkt von der Oberfläche weg zeigen (dh alle Normalen auf einer ebenen Fläche), erhalten Sie die Farbe (128, 128, 255), die das Hellblau ist, auf das Sie sich wahrscheinlich beziehen. Es ist auf halbem Weg zwischen blau (0, 0, 255)und weiß (255, 255, 255). Ein Beispiel finden Sie in den Ecken dieses Bildes .
Joseph Mansfield

1
@danijar Das liegt daran, dass die Werte im normalen Vektor zwischen -1 und +1 liegen können. Wenn -1 auf 0 und +1 auf 255 abgebildet wird, wird 0 auf 128 (0, 0, 1)abgebildet (128, 128, 255).
Joseph Mansfield

6

Es ist wahr, dass viele normale Karten im Tangentenraum nur einen begrenzten Farbbereich haben. Normale Karten für den Objektraum oder den Weltraum hätten eine größere Farbpalette, aber wenn wir in unserem Spiel nur normale Karten für den Tangentenraum verwenden (wie die meisten Entwickler), ist es eine rechtmäßige Frage, warum wir dies nicht tun. t Wählen Sie eine Codierung, die außerhalb des Bereichs liegt, den wir nicht verwenden, um mehr Präzision zu erzielen.

Anstatt beispielsweise [-1, 1] für jede Komponente [0, 1] zuzuordnen, könnten wir entscheiden, dass wir [-0,5, 0,5] für die XY-Komponenten [0, 1] und [0, 1] zuordnen. 0,5, 1] ​​bis [0, 1] für die Z-Komponente. Das würde uns die doppelte Präzision geben.

Die Antwort ist, dass wir normalerweise keine höhere Präzision benötigen und die Verwendung der Standardzuordnung uns den Bereich gibt, in dem wir mit allen denkbaren Normalen umgehen können.

Manchmal brauchen wir jedoch mehr Präzision. Auf Oberflächen, die nahezu glatt, aber nicht ganz glatt sind und sehr subtile Unebenheiten aufweisen, kann die Kombination des Bereichs [-1, 1] plus DXT-Komprimierung aufgrund der schlechten Genauigkeit der Normalen durchaus zu sichtbaren Streifen führen. In Spielen, an denen ich gearbeitet habe, haben wir einen Parameter für die "normale Kartenstärke" pro Material hinzugefügt, mit dem Sie die Codierung für eine bestimmte Textur effektiv anpassen können, sodass Sie einen kleineren Bereich wie [-0,5, 0,5] oder [-0,1 verwenden können , 0.1] wenn Sie wollten, und dadurch viel präziser.

Ein Beispiel für die Art von Oberfläche, auf der wir dies verwenden würden, ist eine Motorhaube oder ein Glasfenster an der Seite eines Gebäudes (das nicht ganz flach, aber sehr leicht verzogen ist). Bei beiden handelt es sich um harte, glänzende Oberflächen mit einer recht subtilen Krümmung, was bedeutet, dass Sie aufgrund ihrer Auswirkung auf die Cubemap-Reflexionen leicht Unvollkommenheiten in den Normalen erkennen können. Durch Anpassen der normalen Kartencodierung für mehr Präzision wurde das Erscheinungsbild dieser Oberflächen erheblich verbessert.

Trotzdem waren sie eher die Ausnahme als die Regel, und die Standardcodierung [-1, 1] war für fast alle Oberflächen im Spiel völlig ausreichend.


4

Wer sagt, dass wir nicht? Sie beschränken Ihren Denkprozess auf Tangent Space Normal Maps, die (im Allgemeinen) immer von der Oberfläche weg zeigen, auf die sie abgebildet werden. Es gibt auch Normalkarten für den Welt- / Objektraum, die jede Farbe des Regenbogens enthalten, da sie nicht mit dem Koordinatenraum der Oberfläche zusammenhängen.


Als lustiges Experiment sollten Sie eine Tangentialraum-Normalkarte mit der TBN-Matrix multiplizieren und die resultierende Farbe anstelle der normalen Beleuchtung ausgeben. Beachten Sie, wie sich die Farben dramatisch ändern, da sie sich jetzt im Objektbereich befinden (oder im Ansichtsbereich, je nachdem, wie Sie Ihre TBN-Matrix erstellt haben).

Sie sind jedoch noch nicht fertig. Jetzt, da sich die Normalen im Objekt- / Ansichtsbereich befinden, werden Sie wahrscheinlich einige Vektoren mit negativen Werten haben. Sie müssen die Farben so vorspannen und skalieren, dass negative Werte die untere Hälfte des Farbraums und positive Werte die höhere einnehmen (wenn Sie die normale Karte tatsächlich korrekt darstellen möchten).


Wenn Sie das Experiment nicht selbst durchführen möchten, können Sie den Unterschied zwischen dem Weltraum und dem Tangentenraum im folgenden Bild sehen :

Tangentenraum gegen Weltraum

Normale Karten des Tangentenraums befinden sich in einem speziellen Koordinatenraum, der sicherstellt, dass positives Z immer normal zur Oberfläche ist. Da XYZ normalerweise in RGB codiert wird und die meisten Oberflächen relativ flach sind (z. B. dominiert das Punktprodukt zwischen der Normalen, die die Textur liefert, und einem Vektor, der die Oberfläche an einem beliebigen Punkt tangiert, ziemlich nahe bei 0), dominiert B den Farbraum im Tangentenraum.

Im Welt- / Objektraum gibt es keine dominante Farbe, aber diese normalen Karten möchten nicht deformiert werden. Wenn normale Karten des Tangentenraums verwendet werden, erfolgt die Beleuchtung entweder im Tangentenraum oder die normale Karte wird vor dem Beleuchten in einen Welt- / Ansichtsraum umgewandelt. Indem diese Transformation bis zur Renderzeit verschoben (oder ganz vermieden) wird, können Objekte gedreht und Texturkoordinaten deformiert werden, ohne die normale Karte zu ungültig zu machen. Normale Weltraumkarten sind normalerweise für die statische Weltgeometrie reserviert und können für den normalen G-Puffer in verzögerter Schattierung verwendet werden.


1

Sie können nur zwei Komponenten einer normalisierten normalen Karte in einer RG-Textur speichern und die dritte Komponente trivial neu berechnen. Ich weiß nicht, warum dies nicht häufiger vorkommt als der Leistungseinbruch der Quadratwurzeloperation.

1 = sqrt(x^2 + y^2 + z^2)
z^2 = 1 - x^2 - y^2
z = sqrt(1 - x^2 - y^2)

Meine Frage bezieht sich nicht auf OpenGL-Texturen, sondern auf Texturbilddateien. Bei OpenGL-Texturen im Speicher wurden in einigen Implementierungen nur X- und Y-Komponenten gespeichert. Es tut mir leid, dass mir das nicht klar war.
Danijar

Sie können dasselbe für Dateien auf der Festplatte tun. Quell-Assets liegen normalerweise nur in Formaten vor, die keine RG-Texturen unterstützen.
Sean Middleditch

Ich weiß, aber meine Frage betraf den Grund für die Verwendung eines kleinen Farbtiefenbereichs für normale Kartendateien. Oder ist nur meine Annahme über die Verwendung des Farbbereichs falsch?
Danijar

1
Ja, Ihre Annahme ist völlig falsch. Das gesamte Sortiment wird genutzt. Das Problem ist, dass Sie und alle anderen in diesem Thread an normale Karten mit tangentialem Raum denken. Diese normalen Karten befinden sich in einem speziellen Koordinatenraum, der sicherstellt, dass positives Z immer normal zur Oberfläche ist. Da XYZ normalerweise in RGB codiert wird und die meisten Oberflächen relativ flach sind ("Bump Mapping", nicht "Fold Mapping" = P), dominiert B den Farbraum im Tangentenraum. Im Welt- / Objektraum gibt es keine dominante Farbe, aber diese normalen Karten möchten nicht deformiert werden, so dass sie nicht oft verwendet werden.
Andon M. Coleman

1
@ SeanMiddleditch Ich denke, es ist ziemlich üblich, auf z = 1 normalisierte Normalen zu speichern - auch bekannt als "Ableitungskarte", da die XY-Komponenten der Normalen dann die (negierten) partiellen Ableitungen der Oberfläche sind. Dann können Sie es im Pixel-Shader dekodieren, indem Sie z = 1 setzen und normalisieren, was möglicherweise schneller als die Berechnung ist sqrt(1 - x^2 - y^2).
Nathan Reed

1

Wir verwenden tatsächlich die volle Farbtiefe.

Zunächst sollten Normalen eine Einheitslänge haben, andernfalls müssen wir eine teure (und unnötige) Renormierung im Fragment-Shader durchführen.

Nehmen wir an, Sie betrachten eine Textur wie in einem Bildeditor von vorne.

  • Eine Normale von {0,0,1} ist die Normaleneinheitslänge, die auf Sie zeigt, was zu einer normalen Kartenfarbe von {128, 128, 255} führt.
  • Eine Normale von {0,0, -1} zeigt dagegen von Ihnen weg , und das ist eine Farbe von {128, 128, 0}.
  • Normalen von {1,0,0}, {-1,0,0}, {0,1,0} und {0, -1,0} stehen im rechten Winkel zu Ihrer Blickrichtung, und Sie können arbeiten die Farben selbst raus.

Für nur die sechs Hauptrichtungen (oben / unten / links / rechts / vorne / hinten) benötigen wir bereits Werte von 0, 128 und 255 in jedem der R-, G- und B-Kanäle. Sie sind offensichtlich nicht die einzigen 6 Richtungen, in die etwas zeigen kann, also brauchen wir auch Zwischenwerte. Das ist die volle Farbtiefe.

Der Grund, warum die meisten normalen Karten kreideblau sind, ist, dass sie meistens Normalen codieren, die auf den Betrachter zeigen (mein erster Aufzählungspunkt oben), und die meiste Zeit codieren sie Normalen, die mehr zeigen. oder weniger gegenüber dem Betrachter. Aber sie nicht haben , und ohne die volle Farbtiefe verwendet würden sie die Fähigkeit zu Punkt in jeder beliebigen Richtung verlieren.

Dies hat eigentlich nichts mit dem Begriff "Präzision" zu tun, sondern kommt nur aus der Richtung, in die Normalen zeigen, wenn sie in einer normalen Karte codiert werden.


1
In der Praxis denke ich, dass es notwendig ist, im Fragment-Shader zu renormieren, da die abgetastete Normalität aufgrund von Texturkomprimierungs- und bilinearen Filterproblemen zu einer Nicht-Einheitenlänge führen kann. Es ist auch nicht so teuer - Vektornormalisierung ist eine so häufige Operation, dass ich mich wundern würde, wenn eine GPU heutzutage keinen Hardware-Fast-Path dafür hat.
Nathan Reed

Auf jeden Fall ist eine Normalisierung in den meisten Fällen ein unvermeidbares Übel. Die Zeiten, in denen die Normalisierung so teuer ist, dass eine Cubemap-Suche schneller wäre, sind jedoch lange vorbei. Ich vermisse diese Tage irgendwie :)
Andon M. Coleman
Durch die Nutzung unserer Website bestätigen Sie, dass Sie unsere Cookie-Richtlinie und Datenschutzrichtlinie gelesen und verstanden haben.
Licensed under cc by-sa 3.0 with attribution required.