Wie kann virtuelle Texturierung tatsächlich effizient sein?


27

Als Referenz beziehe ich mich auf den "generischen Namen" für die Technik, die zuerst (glaube ich) mit der MegaTexture- Technologie von idTech 5 eingeführt wurde . Sehen Sie sich das Video hier an, um einen kurzen Blick darauf zu werfen, wie es funktioniert.

Ich habe in letzter Zeit einige Artikel und Veröffentlichungen überflogen, und was ich nicht verstehe, ist, wie es möglicherweise effizient sein kann. Erfordert es nicht eine ständige Neuberechnung der UV-Koordinaten vom Bereich "Globale Textur" in die virtuellen Texturkoordinaten? Und wie bremst das die meisten Versuche, Geometrie zusammenzufassen? Wie kann ein beliebiges Einzoomen möglich sein? Wäre es nicht irgendwann erforderlich, Polygone zu unterteilen?

Es gibt so viel, was ich nicht verstehe, und ich konnte keine wirklich leicht zugänglichen Ressourcen zu diesem Thema finden.

Antworten:


20

Überblick

Der Hauptgrund für Virtual Texturing (VT) oder Sparse Virtual Textures , wie es manchmal genannt wird, ist eine Speicheroptimierung. Das Wesentliche dabei ist, nur die Texel (verallgemeinert als Seiten / Kacheln), die Sie für einen gerenderten Frame benötigen, in den Videospeicher zu verschieben. Auf diese Weise können Sie viel mehr Texturdaten im Offline- oder langsamen Speicher (Festplatte, optische Festplatte, Cloud) speichern, als es ansonsten in den Videospeicher oder sogar in den Hauptspeicher passt. Wenn Sie das Konzept des virtuellen Speichers verstehen, das von modernen Betriebssystemen verwendet wird, ist es im Wesentlichen dasselbe (der Name ist nicht zufällig vergeben).

VT erfordert keine Neuberechnung der UV-Werte in dem Sinne, dass Sie dies für jeden Frame vor dem Rendern eines Netzes tun und dann die Scheitelpunktdaten erneut übermitteln würden. Es sind jedoch einige umfangreiche Arbeiten in den Scheitelpunkt- und Fragment-Shadern erforderlich, um die indirekte Suche nach den eingehenden UV-Werten durchzuführen. In einer guten Implementierung sollte es jedoch für die Anwendung vollständig transparent sein, wenn eine virtuelle oder eine herkömmliche Textur verwendet wird. Tatsächlich mischt eine Anwendung die meiste Zeit beide Arten der Texturierung, virtuell und traditionell.

Das Batching kann theoretisch sehr gut funktionieren, obwohl ich mich nie mit den Details befasst habe. Da die üblichen Kriterien für das Gruppieren von Geometrie die Texturen sind und mit VT jedes Polygon in der Szene dieselbe "unendlich große" Textur haben kann, können Sie theoretisch mit 1 Zeichenaufruf eine vollständige Szenenzeichnung erzielen. In Wirklichkeit spielen jedoch andere Faktoren eine Rolle, die dies unpraktisch machen.

Probleme mit VT

Das Ein- und Auszoomen und plötzliche Bewegen der Kamera sind die schwierigsten Aufgaben in einem VT-Setup. Es kann für eine statische Szene sehr ansprechend aussehen, aber sobald sich die Dinge bewegen, werden mehr Textur-Seiten / Kacheln angefordert, als Sie zum externen Speichern streamen können. Async-Datei-E / A und Threading können helfen, aber wenn es sich um ein Echtzeitsystem handelt, wie in einem Spiel, müssen Sie nur ein paar Frames mit Kacheln mit niedrigerer Auflösung rendern, bis hin und wieder die hochauflösenden eintreffen , was zu einer verschwommenen Textur führt. Hier gibt es keine Silberkugel und das ist das größte Problem mit der Technik, IMO.

Virtuelle Texturierung geht auch nicht einfach mit Transparenz um, sodass transparente Polygone einen separaten traditionellen Renderpfad für sie benötigen.

Alles in allem ist VT interessant, aber ich würde es nicht jedem empfehlen. Es kann gut funktionieren, aber es ist schwer zu implementieren und zu optimieren, und es gibt einfach zu viele Eckfälle und fallspezifische Optimierungen, die für meinen Geschmack erforderlich sind. Für große Open-World-Spiele oder Datenvisualisierungs-Apps ist dies möglicherweise die einzige Möglichkeit, den gesamten Inhalt in die verfügbare Hardware einzupassen. Mit viel Arbeit kann erreicht werden, dass es auch auf begrenzter Hardware ziemlich effizient läuft, wie wir in den Versionen PS3 und XBOX360 von id's Rage sehen können .

Implementierung

Bis zu einem gewissen Grad habe ich es geschafft, VT unter iOS mit OpenGL-ES zum Laufen zu bringen. Meine Implementierung ist nicht "versendbar", aber ich könnte es so machen, wenn ich wollte und die Ressourcen hatte. Sie können den Quellcode hier anzeigen , um eine bessere Vorstellung davon zu bekommen, wie die Teile zusammenpassen. Hier ist ein Video einer Demo, die auf dem iOS-Sim ausgeführt wird. Es sieht sehr nachlässig aus, weil der Simulator Shader schrecklich emuliert, aber auf einem Gerät reibungslos läuft.

Das folgende Diagramm zeigt die Hauptkomponenten des Systems in meiner Implementierung. Es unterscheidet sich einiges von Seans SVT-Demo (Link-Down-Balg), ist aber architektonisch näher an der , die in dem Artikel Accelerating Virtual Texturing Using CUDA vorgestellt wurde , der im ersten GPU Pro-Buch (Link-Balg) zu finden ist.

virtuelles Texturierungssystem

  • Page Filessind die virtuellen Texturen, die bereits als Vorverarbeitungsschritt in Kacheln (AKA-Seiten) geschnitten wurden, sodass sie bei Bedarf von der Festplatte in den Videospeicher verschoben werden können. Eine Auslagerungsdatei enthält auch den gesamten Satz von Mipmaps, auch virtuelle Mipmaps genannt .

  • Page Cache Managerbehält eine anwendungsseitige Darstellung der Page Tableund Page IndirectionTexturen bei. Da das Verschieben einer Seite vom Offlinespeicher in den Arbeitsspeicher teuer ist, benötigen wir einen Cache, um ein erneutes Laden der bereits verfügbaren Inhalte zu vermeiden. Dieser Cache ist ein sehr einfacher LRU-Cache ( Least Recent Used ). Der Cache ist auch die Komponente, die dafür verantwortlich ist, die physischen Texturen mit ihrer eigenen lokalen Darstellung der Daten auf dem neuesten Stand zu halten.

  • Die Page Providerist eine asynchrone Jobwarteschlange, die die Seiten abruft, die für eine bestimmte Ansicht der Szene benötigt werden, und diese an den Cache sendet.

  • Die Page IndirectionTextur ist eine Textur mit einem Pixel für jede Seite / Kachel in der virtuellen Textur, die die eingehenden UVs der Page TableCache-Textur mit den tatsächlichen Texeldaten zuordnet . Diese Textur kann sehr groß werden, daher muss ein kompaktes Format wie RGBA 8: 8: 8: 8 oder RGB 5: 6: 5 verwendet werden.

Wir vermissen hier aber immer noch ein Schlüsselstück, und so kann festgestellt werden, welche Seiten aus dem Speicher in den Cache und folglich in den Cache geladen werden müssen Page Table. Hier kommen der Feedback Pass und der Page ResolverEnter.

Der Feedback Pass ist ein Pre-Rendering der Ansicht mit einem benutzerdefinierten Shader und einer viel niedrigeren Auflösung, mit dem die IDs der erforderlichen Seiten in den Farbrahmenpuffer geschrieben werden. Das bunte Patchwork des Würfels und der Kugel oben sind tatsächliche Seitenindizes, die als RGBA-Farbe codiert sind. Dieses Pre-Pass-Rendering wird dann in den Hauptspeicher eingelesen und von der verarbeitet Page Resolver, um die Seitenindizes zu decodieren und die neuen Anforderungen mit der auszulösen Page Provider.

Nach dem Feedback-Pre-Pass kann die Szene mit den VT-Lookup-Shadern normal gerendert werden. Beachten Sie jedoch, dass wir nicht auf den Abschluss einer neuen Seitenanforderung warten. Dies wäre schrecklich, da wir nur die synchrone Datei-E / A blockieren würden. Die Anforderungen sind asynchron und können zum Zeitpunkt des Renderns der endgültigen Ansicht fertig sein oder auch nicht. Wenn sie bereit sind, süße, aber wenn nicht, behalten wir immer eine gesperrte Seite einer niedrig aufgelösten Mipmap im Cache als Fallback, sodass wir einige Texturdaten verwenden können, die jedoch verschwommen sind.

Andere Ressourcen sind einen Besuch wert

VT ist immer noch ein heißes Thema in der Computergrafik. Es gibt also jede Menge gutes Material, und Sie sollten in der Lage sein, viel mehr zu finden. Wenn ich dieser Antwort noch etwas hinzufügen kann, können Sie uns gerne kontaktieren. Ich bin ein bisschen verrostet, habe im letzten Jahr nicht viel darüber gelesen, aber es ist immer gut für die Erinnerung, Dinge zu überdenken :)


Hey, danke für die hervorragende Antwort. Ich weiß, dass dies in der Regel verpönt ist, aber ich habe verschiedene Probleme, daher gehe ich meistens nur die Dinge durch - um einen intuitiven Überblick über die Themen der Zukunft zu erhalten (ich fürchte, richtig zu lernen und Dinge umzusetzen, ist momentan nicht in meiner Reichweite ) - Könnten Sie, wenn möglich, ein Pseudocode-Beispiel posten, das den Prozess selbst beschreibt, idealerweise, aber nicht unbedingt, illustriert?
Llamageddon

1
@ Lamageddon, es kommt einfach so vor, dass ich noch ein Diagramm zur Hand hatte;) Ich fürchte, Pseudo-Code wird ein bisschen schwer zu liefern sein, da es einiges an echtem Code gibt. Ich hoffe jedoch, dass die erweiterte Antwort dazu beiträgt, einen allgemeinen Eindruck von der Technik zu gewinnen.
Glampert

3
Es ist erwähnenswert, dass die meiste moderne Hardware jetzt programmierbare Seitentabellen verfügbar macht, sodass keine Umleitungstextur mehr erforderlich ist. Dies wird beispielsweise durch reservierte DirectX12- Ressourcen , die auf gekachelten DirectX11- Ressourcen aufbauen , oder durch OpenGL- Sparse-Texturen ermöglicht .
MooseBoys

1
@ Lamageddon, der Feedback-Pre-Pass kann mit einer niedrigeren Auflösung durchgeführt werden, um so viel Rechenaufwand und Speicher wie möglich zu sparen, da sich Pixel für eine Seite im Allgemeinen wiederholen (Sie können die großen farbigen Quadrate in meiner Demo bemerken). Sie haben Recht, dass eventuell eine solche sichtbare Seite übersehen wird, aber dies wird normalerweise keine große visuelle Auswirkung haben, da das System immer mindestens die niedrigste Mipmap der gesamten VT im Cache verfügbar halten sollte. Das zweite Papier, das ich verlinkt habe, enthält alle Shader-Beispiele im Anhang. Sie können auch auf das Repo für mein eigenes Projekt verweisen, sie sind ähnlich.
Glampert

1
@glampert Ahh, ich verstehe; Das macht Sinn. Trotzdem denke ich, dass es viele Möglichkeiten gibt, mit Transparenzen umzugehen. Im Seiten-ID-Durchgang können Sie zittern (bei der Histogrammierung werden alle Seiten angezeigt, sofern nicht eine große Anzahl transparenter Ebenen vorhanden ist) oder einen K-Buffer-Ansatz verwenden oder einfach die transparente Textur als Grundlage verwenden, auf der sich Objekte in der Nähe des befinden Kamera (im Gegensatz zum Rendern in einem Feedback-Durchlauf).
Nathan Reed

11

Virtuelle Texturierung ist das logische Extrem von Texturatlanten.


Ein Texturatlas ist eine einzelne riesige Textur, die Texturen für einzelne Netze enthält:

Beispiel für einen Texturatlas

Texturatlanten wurden populär, weil das Ändern von Texturen ein vollständiges Pipeline-Flush auf der GPU verursacht. Beim Erstellen der Netze werden die UVs komprimiert / verschoben, sodass sie den korrekten „Anteil“ des gesamten Texturatlas darstellen.

Wie @ nathan-reed in den Kommentaren erwähnte, besteht einer der Hauptnachteile von Texturatlanten darin, die Umbruchmodi wie Wiederholen, Klemmen, Rahmen usw. zu verlieren. Wenn die Texturen nicht genügend Rahmen haben, können Sie dies versehentlich tun Probe aus einer angrenzenden Textur beim Filtern. Dies kann zu Blutungsartefakten führen.

Texturatlanten haben eine wesentliche Einschränkung: Größe. Grafik-APIs begrenzen die Größe einer Textur auf weiche Weise. Trotzdem ist der Grafikspeicher nur so groß. Es gibt also auch eine feste Grenze für die Texturgröße, die durch die Größe Ihres V-RAMs vorgegeben wird. Virtuelle Texturen lösen dieses Problem, indem sie Konzepte aus dem virtuellen Speicher ausleihen .

Virtuelle Texturen nutzen die Tatsache aus, dass Sie in den meisten Szenen nur einen kleinen Teil aller Texturen sehen. Es muss sich also nur diese Teilmenge der Texturen in vram befinden. Der Rest kann sich im Hauptspeicher oder auf der Festplatte befinden.

Es gibt einige Möglichkeiten, es umzusetzen, aber ich werde die von Sean Barrett in seinem GDC-Vortrag beschriebene Implementierung erläutern . (was ich sehr empfehlen zu sehen)

Wir haben drei Hauptelemente: die virtuelle Textur, die physische Textur und die Nachschlagetabelle.

Virtuelle Textur

Die virtuelle Textur repräsentiert den theoretischen Mega-Atlas, den wir hätten, wenn wir genug RAM hätten, um alles unterzubringen. Es existiert eigentlich nirgendwo im Speicher. Die physische Textur gibt an, über welche Pixeldaten wir tatsächlich im VRAM verfügen. Die Nachschlagetabelle ist die Zuordnung zwischen den beiden. Der Einfachheit halber teilen wir alle drei Elemente in gleich große Kacheln oder Seiten auf.

In der Nachschlagetabelle wird die Position der oberen linken Ecke der Kachel in der physischen Textur gespeichert. Wie erhalten wir also die entsprechende UV-Strahlung für die physische Textur, wenn wir der gesamten virtuellen Textur eine UV-Strahlung zuweisen?

Zuerst müssen wir den Ort der Seite innerhalb der physischen Textur finden. Dann müssen wir die Position des UV innerhalb der Seite berechnen. Schließlich können wir diese beiden Offsets addieren, um die Position des UV innerhalb der physikalischen Textur zu ermitteln

float2 pageLocInPhysicalTex = ...
float2 inPageLocation = ...
float2 physicalTexUV = pageLocationInPhysicalTex + inPageLocation;


Berechnung von pageLocInPhysicalTex

Wenn wir die Nachschlagetabelle so groß wie die Anzahl der Kacheln in der virtuellen Textur machen, können wir die Nachschlagetabelle nur mit dem nächsten Nachbarn abtasten und wir erhalten die Position der oberen linken Ecke der Seite innerhalb der physischen Textur.

float2 pageLocInPhysicalTex = lookupTable.Sample(virtTexUV, nearestNeighborSampler);


Berechnung von inPageLocation

inPageLocation ist eine UV-Koordinate, die relativ zur oberen linken Ecke der Seite und nicht zur oberen linken Ecke der gesamten Textur ist.

Eine Möglichkeit, dies zu berechnen, besteht darin, den UV-Wert oben links auf der Seite abzuziehen und dann auf die Größe der Seite zu skalieren. Dies ist jedoch ein ziemlicher Rechenaufwand. Stattdessen können wir ausnutzen, wie IEEE-Gleitkomma dargestellt wird. IEEE-Gleitkomma speichert den Bruchteil einer Zahl durch eine Reihe von Basis-2-Brüchen.

Bildbeschreibung hier eingeben

In diesem Beispiel lautet die Nummer:

number = 0 + (1/2) + (1/8) + (1/16) = 0.6875

Sehen wir uns nun eine vereinfachte Version der virtuellen Textur an:

Einfache virtuelle Textur

Das 1/2 Bit sagt uns, ob wir uns in der linken Hälfte der Textur oder in der rechten befinden. Das 1/4-Bit gibt an, in welchem ​​Viertel der Hälfte wir uns befinden. In diesem Beispiel geben die ersten beiden Bits an, auf welcher Seite wir uns befinden, da die Textur in 16 oder 4 Seiten aufgeteilt ist Bits teilen uns die Position innerhalb der Seite mit.

Die restlichen Bits erhalten wir, indem wir den float mit exp2 () verschieben und mit fract () entfernen.

float2 inPageLocation = virtTexUV * exp2(sqrt(numTiles));
inPageLocation = fract(inPageLocation);

Dabei ist numTiles ein int2, das die Anzahl der Kacheln pro Seite der Textur angibt. In unserem Beispiel wäre dies (4, 4)

Berechnen wir also die inPageLocation für den grünen Punkt (x, y) = (0.6875, 0.375)

inPageLocation = float2(0.6875, 0.375) * exp2(sqrt(int2(4, 4));
               = float2(0.6875, 0.375) * int2(2, 2);
               = float2(1.375, 0.75);

inPageLocation = fract(float2(1.375, 0.75));
               = float2(0.375, 0.75);

Noch etwas, bevor wir fertig sind. Derzeit ist inPageLocation eine UV-Koordinate im virtuellen Texturraum. Wir wollen jedoch eine UV-Koordinate in der physischen Textur "Raum". Dazu müssen wir inPageLocation nur um das Verhältnis der virtuellen Texturgröße zur physischen Texturgröße skalieren

inPageLocation *= physicalTextureSize / virtualTextureSize;



Die fertige Funktion ist also:

float2 CalculatePhysicalTexUV(float2 virtTexUV, Texture2D<float2> lookupTable, uint2 physicalTexSize, uint2 virtualTexSize, uint2 numTiles) {
    float2 pageLocInPhysicalTex = lookupTable.Sample(virtTexUV, nearestNeighborSampler);

    float2 inPageLocation = virtTexUV * exp2(sqrt(numTiles));
    inPageLocation = fract(inPageLocation);
    inPageLocation *= physicalTexSize / virtualTexSize;

    return pageLocInPhysicalTex + inPageLocation;
}

Ich meine nicht die virtuelle Texturierung, die als MegaTexture- Technologie von idTech 5 bekannt ist. Siehe auch dies und das . Ich habe es im Überblick über die Rendering-Pipelines vieler moderner Engines und in einigen Abhandlungen gesehen, die einen ähnlichen Ansatz für Shadowmaps verwenden. Es hat viel mit Texturatlanten zu tun, ja, es verwendet sie in gewisser Weise, aber ich verwechsle es nicht mit Texturatlanten.
Llamageddon

Ahh. Danke für die Links. Können Sie sie der Frage hinzufügen? Ich werde meine Antwort entsprechend aktualisieren
RichieSams

3
IMO, der Hauptnachteil von einfachen Texturatlanten (nicht virtuellen Texturen) besteht darin, dass Sie die Umbruchmodi wie Wiederholen und Klemmen verlieren und aufgrund von Filtern / Mipmapping Ausblutungen auftreten - nicht aufgrund von Gleitkommapräzision. Es würde mich überraschen, wenn Float-Präzision bei normalen (nicht virtuellen) Texturen zum Problem wird. Selbst eine 16K-Textur (die von den aktuellen APIs maximal zulässige) ist nicht groß genug, um die Float-Präzision wirklich zu belasten.
Nathan Reed

@RichieSams BTW, ich denke, Ihre Antwort ist gut, auch wenn auf eine andere Frage. Sie sollten einen Q & A-Beitrag machen.
Llamageddon

Hmm, das erklärt es ganz gut, obwohl ich nicht wirklich verstehe, wie es mit MIP-Levels funktioniert. Ich wünschte, ich könnte mein spezifisches Problem mit dem Verstehen aufschreiben, aber es entgeht mir irgendwie ...
Llamageddon
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.