Attention: Here be dragons
This is the latest
(unstable) version of this documentation, which may document features
not available in or compatible with released stable versions of Godot.
Checking the stable version of the documentation...
Otimização usando MultiMeshes
Para uma grande quantidade de instâncias (na casa dos milhares), que precisam ser constantemente processadas (e uma certa quantidade de controle precisa ser mantida), usar os servidores diretamente é a otimização recomendada.
Quando a quantidade de objetos atinge as centenas de milhares ou milhões, nenhuma dessas abordagens é mais eficiente. Ainda assim, dependendo dos requisitos, há mais uma otimização possível.
MultiMeshes (Múltiplas Malhas)
Um MultiMesh é uma única primitiva de desenho que pode desenhar até milhões de objetos de uma só vez. É extremamente eficiente porque usa o hardware da GPU para fazer isso.
A única desvantagem é que não é possível realizar culling de tela ou de frustum para instâncias individuais. Isso significa que milhões de objetos serão sempre ou nunca desenhados, dependendo da visibilidade do MultiMesh como um todo. É possível fornecer um retângulo de visibilidade personalizado para eles, mas a visibilidade será sempre do tipo tudo ou nada.
Se os objetos forem simples o suficiente (apenas um par de vértices), isso geralmente não é um grande problema, pois a maioria das GPUs modernas é otimizada para esse caso de uso. Uma solução alternativa é criar vários MultiMeshes para diferentes áreas do mundo.
Também é possível executar alguma lógica dentro do shader de vértice (usando as constantes integradas INSTANCE_ID ou INSTANCE_CUSTOM). Para um exemplo de animação de milhares de objetos em um MultiMesh, veja o tutorial Animando milhares de peixes. As informações para o shader podem ser fornecidas via texturas (existem formatos de Image de ponto flutuante que são ideais para isso).
Outra alternativa é usar um GDExtension e C++, que deve ser extremamente eficiente (é possível definir o estado inteiro para todos os objetos usando memória linear através da função RenderingServer.multimesh_set_buffer()). Dessa forma, o array pode ser criado com várias partes_paralelizáveis e depois configurado em uma chamada, proporcionando alta eficiência de cache.
Finalmente, não é necessário ter todas as instâncias do MultiMesh visíveis. A quantidade de instâncias visíveis pode ser controlada com a propriedade MultiMesh.visible_instance_count. O fluxo de trabalho típico é alocar a quantidade máxima de instâncias que serão usadas e, em seguida, alterar a quantidade visível dependendo de quantas são necessárias no momento.
Exemplo de multimesh
Aqui está um exemplo de uso de um MultiMesh a partir do código. Linguagens diferentes do GDScript podem ser mais eficientes para milhões de objetos, mas para alguns milhares, o GDScript deve funcionar bem.
extends MultiMeshInstance3D
func _ready():
# Create the multimesh.
multimesh = MultiMesh.new()
# Set the format first.
multimesh.transform_format = MultiMesh.TRANSFORM_3D
# Set the mesh that will be duplicated.
multimesh.mesh = BoxMesh.new()
# 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)))
using Godot;
public partial class MyMultiMeshInstance3D : MultiMeshInstance3D
{
public override void _Ready()
{
// Create the multimesh.
Multimesh = new MultiMesh();
// Set the format first.
Multimesh.TransformFormat = MultiMesh.TransformFormatEnum.Transform3D;
// Then resize (otherwise, changing the format is not allowed)
Multimesh.InstanceCount = 1000;
// Maybe not all of them should be visible at first.
Multimesh.VisibleInstanceCount = 1000;
// Set the transform of the instances.
for (int i = 0; i < Multimesh.VisibleInstanceCount; i++)
{
Multimesh.SetInstanceTransform(i, new Transform3D(Basis.Identity, new Vector3(i * 20, 0, 0)));
}
}
}