Ich verwende OpenGL (Version 4.4) (und C ++, wenn das wichtig ist).
Ich habe einen Terrain-Renderer erstellt. Das Terrain wird als 3D-Skalarfeld (Isofläche / Voxel) gespeichert. Es wird eine leicht modifizierte Version von Marching Cubes verwendet , um eine Polygonisierung durchzuführen (Konvertieren des Skalarfelds in Dreiecke).
Derzeit texturiere ich das Gelände mit einer horizontalen (Gras) Textur und einer vertikalen (Schmutz) Textur. Wenn ich dann die Textur anwende, berechne ich einfach den Betrag der horizontalen und vertikalen Textur, der für das aktuelle Dreieck erforderlich ist, abhängig von den Normalen des aktuellen Dreiecks. Je mehr eine Normale nach oben (oder unten) zeigt, desto dominanter ist die horizontale (Gras-) Textur.
Terrain Renderer in Aktion
Die Frage ist nun, was der beste (oder ein guter) Weg wäre, um Multi-Texturing im Gelände durchzuführen. Ich werde allen Werten im Skalarfeld auch einen Voxeltypwert geben . Die Hauptfrage ist also, wie mit dem Rendern umgegangen werden soll. Ich habe ein paar Ideen, wie dies getan werden könnte, aber ich bin mir nicht sicher, welche meiner Ideen die beste wäre oder ob es noch einen besseren Weg gibt.
Erste Idee
- Binden Sie alle benötigten Texturen und fordern Sie dabei
glActiveTexture(...)
jede Textur auf, die es gibt. - Jetzt kann das Netz mit einem einzigen
glDraw*(...)
Aufruf gerendert werden . - Dies funktioniert natürlich nur, wenn der Shader weiß, wann und wo jede Textur verwendet werden soll oder dass die Informationen zur Verwendung jeder Textur im Puffer gespeichert sind, als eine Art Wert, den der Shader verwendet, um zu "erkennen", welche Textur sein soll benutzt. Wie bereits erwähnt, kann dies der Wert vom Voxeltyp sein.
Problem: Die maximale Anzahl von Texturen, die gleichzeitig gebunden werden können, ist sehr begrenzt, so dass (und wahrscheinlich) einige Probleme auftreten können.
Zweite Idee
- Binden Sie eine einzelne Textur und Anruf
glDraw*(...)
mit einem bestimmtenfirst
undcount
Wert, so dass nur ein Teil des Netzes gemacht wird. Welches ist natürlich der Teil, der die gebundene Textur verwendet. - Schleifen Sie dabei das Obige, bis das gesamte Netz mit allen einzelnen Texturen gerendert ist.
Ich sehe kein wirkliches Problem mit dieser Idee. Das einzige zusätzliche, was wir berücksichtigen müssen, ist, dass alle Dreiecke nach ihrem voxel type
Wert sortiert werden müssen .
Obwohl wir die Texturen nicht verblassen könnten, wie im obigen Bild.
Dritte Idee
- Teilen Sie das Netz in einzelne Puffer (VBOs und VAOs) auf, sodass jeder Puffer nur eine einzige (oder mehrere) Textur (en) verwendet. Grundsätzlich das gleiche wie bei der zweiten Idee, obwohl hier der Puffer physisch gemäß den Texturen aufgeteilt würde.
Vierte Idee?
oder gibt es einen noch besseren weg?
Randnotiz
- Jede Textur hat einen eigenen Griff, daher kann keiner von ihnen als Texturatlas verwendet werden .
Wenn Sie kreativ mit den Daten sind, die Sie in Ihre Verts packen, können Sie einen Texturatlas erstellen.
Grundsätzlich benötigen Sie 3 Sätze UV-Daten anstelle des üblichen Einzelsatzes. Jedes repräsentiert die Zuordnung für eine der 3 Texturen, die von diesem Dreieck verwendet werden. Ihr Farbkanal bestimmt, wie viel diese durchscheinen.
Mit einem Voxelfeld können Sie diese Mischung durch die Entfernung vom Scheitelpunkt berechnen.
quelle
Aus den von Ihnen vorgeschlagenen Optionen würde ich mich daran halten, das Netz in Teilnetze aufzuteilen, die nach Material / Textur sortiert sind. Dies kann tatsächlich schneller gerendert werden, wenn Ihr Datensatz wirklich riesig ist. OpenGL-Draw-Aufrufe schlagen möglicherweise aufgrund von Speichermangel fehl, obwohl Sie es wirklich hart pushen müssten, um dies zu erreichen.
Wenn Sie es jedoch wirklich ernst meinen, Ihren Terrain-Renderer zu optimieren, sollten Sie sich wahrscheinlich mit Virtual Texture Mapping (manchmal auch als "Megatextures" bezeichnet) befassen. Dies ist wahrscheinlich die effizienteste Methode zur Verwaltung großer Texturdatensätze.
quelle