Ich habe zuvor Marschwürfel / Tetraeder implementiert, um eine IsoSurface zu rendern. Es hat funktioniert ( YouTube ), aber die Leistung war schlecht, da ich nie dazu gekommen bin, eine variable Detailebene basierend auf der Sichtweite zu implementieren (oder sogar alte, entfernte Teile zu entfernen).
Ich beschloss, es noch einmal richtig zu machen. Ich habe damit begonnen, einen OctreeNode zu erstellen, der beim Aufruf wie folgt funktioniert Build()
.
- Wenn der Block zu klein zum Bauen ist, kehren Sie sofort zurück.
- Berechnen Sie, ob die Oberfläche das Volumen dieses Blocks durchläuft.
- Wenn ja, dann entscheiden Sie, ob wir die LOD erhöhen möchten (weil die Kamera in der Nähe ist).
- Wenn ja, dann spawne 8 Kinder und rufe den gleichen Prozess auf
- Wenn nicht, erstellen Sie das Netz anhand der Abmessungen des aktuellen Knotens
Einige PseudoCode:
OctNode Build() {
if(this.ChunkSize < minChunkSize) {
return null;
}
densityRange = densitySource¹.GetDensityRange(this.bounds);
if(densityRange.min < surface < densityRange.max) {
if(loDProvider.DesiredLod(bounds)² > currentLoD) {
for(i 1 to 8) {
if(children[i] == null) {
children[i] = new OctNode(...)
}
children[i] = children[i].Build();
}
} else {
BuildMesh();
}
return this;
}
}
¹ Die Dichtequelle kann nicht nur die Dichte an einem Punkt zurückgeben, sondern auch den möglichen Dichtebereich für ein bestimmtes Volumen bestimmen.
² Der LoD-Anbieter nimmt einen Begrenzungsrahmen und gibt den maximal gewünschten LoD basierend auf Kameraposition / Kegelstumpf, Benutzereinstellungen usw. zurück.
Also ... das alles funktioniert ziemlich gut. Verwenden einer einfachen Kugel als Dichtequelle und Anzeigen aller Knoten:
Und nur die Blätter:
Es gibt jedoch einige Probleme:
- Ich muss das anfängliche Begrenzungsvolumen definieren (und je größer es ist, desto mehr Verarbeitung muss ich durchführen)
- An der Wurzel des Baumes habe ich keine Ahnung, wie tief die Blätter sein werden, daher beginnt meine LoD-Nummerierung bei der niedrigsten Qualität (Wurzel) und nimmt zu, wenn die Brocken kleiner werden. Da LoD jetzt relativ zum Anfangsvolumen ist, ist es nicht sehr nützlich, wenn ich Dinge mit bestimmten Größen / Qualitäten tun möchte.
Ich habe über ein paar Optionen nachgedacht, aber beide scheinen fehlerhaft zu sein:
- Pflegen Sie eine Sammlung von Octrees und fügen Sie sie je nach Entfernung hinzu oder entfernen Sie sie. Ich kann nicht sehen, wie ich gut ineinander greifen würde¹, und ich benötige eine Liste mit bekannten leeren Knoten, insbesondere wenn ich beliebige 3D-Oberflächen möchte (um zu vermeiden, dass leere Volumina wiederholt neu berechnet werden).
- Fügen Sie dem aktuellen Stamm einen übergeordneten Knoten hinzu, und fügen Sie dann sieben Geschwister für den ursprünglichen Knoten hinzu. Dies würde funktionieren und auf Abruf erfolgen, aber es scheint komplex, sich vernünftig zurückzuziehen, wenn sich der Spieler durch die Landschaft bewegt. Dies würde auch die LoD-Zahlen noch weniger aussagekräftig machen.
¹ [Zur Verdeutlichung von Q unten] Wenn sich derzeit zwei physisch benachbarte Knoten im Baum an verschiedenen LODs befinden, habe ich einen Code, um die Verts so zu erzwingen, dass beim Generieren der Netze keine Naht entsteht. Ich kann dies tun, indem ich die Dichte für mehrere umgebende Knoten kenne. In einem Szenario, in dem ich zwei unabhängige Oktrees nebeneinander habe, hätte ich keine einfache Möglichkeit, diese Informationen abzurufen, was zu Nähten führt.
Was ist ein optimaler Weg, um dies zu erreichen?