Work in progress

The content of this page was not yet updated for Godot 4.2 and may be outdated. If you know how to improve this page or you can confirm that it's up to date, feel free to open a pull request.

Optimierungen durch MultiMeshes

Für eine große Anzahl (Tausende) von Instanzen, die ständig verarbeitet werden müssen (und ein gewisses Maß an Kontrolle beibehalten werden muss), wird Folgendes empfohlen Server direkt verwenden.

Wenn die Anzahl der Objekte Hunderttausende oder Millionen erreicht, ist keiner dieser Ansätze mehr effizient. Abhängig von den Anforderungen ist jedoch noch eine weitere Optimierung möglich.

MultiMeshes

Ein MultiMesh ist ein einzelnes Zeichenelement, das bis zu Millionen von Objekten auf einmal zeichnen kann. Es ist äußerst effizient, da hierfür die GPU-Hardware verwendet wird (in OpenGL ES 2.0 ist es jedoch weniger effizient, da es keine Hardwareunterstützung gibt).

Der einzige Nachteil ist, dass für einzelne Instanzen kein Screen- oder Frustum-Culling möglich ist. Dies bedeutet, dass Millionen von Objekten immer oder nie gezeichnet werden, abhängig von der Sichtbarkeit des gesamten MultiMesh. Es ist möglich, eine benutzerdefinierte Sichtbarkeitsrechteck für sie bereitzustellen, aber es wird immer eine alles oder nichts-Sichtbarkeit sein.

Wenn die Objekte einfach genug sind (nur ein paar Vertices) ist dies im Allgemeinen kein großes Problem, da die meisten modernen GPUs für diesen Anwendungsfall optimiert sind. Eine Umgehung des Problems besteht darin, mehrere MultiMeshes für verschiedene Regionen der Welt zu erstellen.

Es ist auch möglich, eine Logik innerhalb des Vertex-Shaders auszuführen (unter Verwendung der Built-in-Konstanten INSTANCE_ID oder INSTANCE_CUSTOM). Ein Beispiel für das Animieren von Tausenden von Objekten in einem MultiMesh finden Sie in der Anleitung Animieren von Tausenden von Fischen. Informationen für den Shader können über Texturen bereitgestellt werden (es gibt Float-Bild-Formate, die dafür ideal sind).

Eine andere Alternative ist die Verwendung einer GDExtension und C++, was extrem effizient sein sollte (es ist möglich, den gesamten Status für alle Objekte mit linearem Speicher über die Funktion RenderingServer.multimesh_set_buffer() zu setzen). Auf diese Weise kann das Array mit mehreren Threads erstellt und dann in einem Aufruf gesetzt werden, was eine hohe Cache-Effizienz bietet.

Schließlich müssen nicht alle MultiMesh-Instanzen sichtbar sein. Die Anzahl der sichtbaren Instanzen kann mit der Property MultiMesh.visible_instance_count gesteuert werden. Der typische Ablauf besteht darin, die maximale Anzahl der verwendeten Instanzen zuzuweisen und dann die sichtbare Anzahl zu ändern, je nachdem wie viele derzeit benötigt werden.

Ein MultiMesh-Beispiel

Hier ist ein Beispiel für die Verwendung eines MultiMeshs aus Code heraus. Andere Sprachen als GDScript sind möglicherweise für Millionen von Objekten effizienter, aber für einige Tausend sollte GDScript ausreichen.

extends MultiMeshInstance3D


func _ready():
    # Create the multimesh.
    multimesh = MultiMesh.new()
    # Set the format first.
    multimesh.transform_format = MultiMesh.TRANSFORM_3D
    # Then resize (otherwise, changing the format is not allowed).
    multimesh.instance_count = 10000
    # Maybe not all of them should be visible at first.
    multimesh.visible_instance_count = 1000

    # Set the transform of the instances.
    for i in multimesh.visible_instance_count:
        multimesh.set_instance_transform(i, Transform3D(Basis(), Vector3(i * 20, 0, 0)))