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.

Optimización usando MultiMeshes

Para un gran número de instancias (en miles) que deben ser procesadas constantemente (y se necesita cierto grado de control), se recomienda la optimización de "usar servidores directamente". Esto implica utilizar servidores de manera directa y eficiente para gestionar y procesar las instancias, lo cual puede ofrecer un rendimiento mejorado y mayor control sobre el procesamiento. Para obtener más información sobre cómo utilizar servidores directamente, puedes consultar la documentación en el enlace "usar servidores directamente".

Cuando la cantidad de objetos alcanza cientos de miles o millones, ninguno de estos enfoques es eficiente. Sin embargo, dependiendo de los requisitos, existe una optimización adicional posible.

MultiMeshes

Un MultiMesh es una primitiva de dibujo única que puede dibujar hasta millones de objetos de una vez. Es extremadamente eficiente porque utiliza el hardware de la GPU para hacer esto (en OpenGL ES 2.0, es menos eficiente porque no hay soporte de hardware para ello).

La única desventaja es que no es posible realizar un culling de pantalla o de frustum para instancias individuales. Esto significa que millones de objetos siempre se dibujarán o nunca se dibujarán, dependiendo de la visibilidad de todo el MultiMesh. Es posible proporcionar un rectángulo de visibilidad personalizado para ellos, pero siempre será una visibilidad todo o nada.

Si los objetos son lo suficientemente simples (solo un par de vértices), esto generalmente no es un gran problema, ya que la mayoría de las GPUs modernas están optimizadas para este caso de uso. Una solución alternativa es crear varios MultiMeshes para diferentes áreas del mundo.

También es posible ejecutar cierta lógica dentro del vertex shader utilizando las constantes integradas "INSTANCE_ID" o "INSTANCE_CUSTOM". Por ejemplo, para animar miles de objetos en un MultiMesh, puedes consultar el tutorial "Animando miles de peces". La información para el shader puede ser proporcionada a través de texturas (hay formatos de imágenes de punto flotante, Image, que son ideales para esto).

Another alternative is to use a GDExtension and C++, which should be extremely efficient (it's possible to set the entire state for all objects using linear memory via the RenderingServer.multimesh_set_buffer() function). This way, the array can be created with multiple threads, then set in one call, providing high cache efficiency.

Finalmente, no es necesario que todas las instancias de MultiMesh sean visibles. La cantidad de instancias visibles se puede controlar con la propiedad MultiMesh.visible_instance_count. El flujo de trabajo típico consiste en asignar la cantidad máxima de instancias que se utilizarán y luego cambiar la cantidad visible según la cantidad necesaria en ese momento.

Ejemplo de Multimesh

Aquí tienes un ejemplo de cómo usar un MultiMesh desde el código. Otros lenguajes además de GDScript pueden ser más eficientes para millones de objetos, pero para unos pocos miles, GDScript debería ser suficiente.

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)))