MultiMesh na Godot 4: desenhar milhares de objetos sem travar

Aprenda a usar MultiMesh na Godot 4 para desenhar milhares de objetos iguais numa unica draw call, com GDScript tipado, cores por instancia e limites.
Voce fez o basico na Godot, montou sua cena, e ai resolveu preencher o mundo: um campo de grama, uma chuva de moedas, um enxame de inimigos, um ceu estrelado. Instanciou algumas centenas de nos iguais e viu o FPS despencar. A boa noticia e que existe uma ferramenta feita exatamente para isso, e ela se chama MultiMesh. Neste post voce vai entender por que muitos nos iguais matam a performance e como usar MultiMesh na Godot 4 para desenhar milhares de copias do mesmo objeto numa unica draw call, com GDScript tipado do comeco ao fim.
Por que muitos nos iguais derrubam o FPS
Cada Node na sua arvore tem um custo. Ele ocupa memoria, participa do processamento da arvore de cena e, se for visual (um Sprite2D, um MeshInstance3D), precisa ser desenhado. O desenho e o ponto mais caro aqui.
Toda vez que a engine manda a GPU desenhar algo, ela emite uma "draw call". Uma draw call carrega estado: qual mesh, qual material, qual textura, quais parametros. Emitir uma draw call e barato quando voce faz isso algumas dezenas de vezes por frame. Quando voce faz isso milhares de vezes por frame, o custo de preparar e enviar cada chamada se acumula e vira o gargalo. Nao e o pixel na tela que pesa, e a conversa constante entre CPU e GPU.
Repare no detalhe cruel: os objetos sao iguais. Mil tufos de grama compartilham o mesmo mesh e o mesmo material. Mesmo assim, mil MeshInstance3D viram (na pior das hipoteses) mil draw calls, cada uma reconfigurando um estado praticamente identico. E desperdicio puro. A Godot faz algum agrupamento automatico em 2D, mas voce nao deve contar com isso para milhares de nos, e cada no ainda paga o custo de existir na arvore.
Se o seu jogo esta travando e voce quer um diagnostico mais amplo antes de mexer em MultiMesh, vale ler o guia de como otimizar FPS e performance na Godot para achar o gargalo real com o profiler antes de assumir que o problema e o numero de nos.
O que o MultiMesh resolve
MultiMesh inverte a logica. Em vez de um no por objeto, voce tem um no (MultiMeshInstance2D ou MultiMeshInstance3D) que carrega um recurso MultiMesh. Esse recurso guarda um unico mesh e uma lista de transforms, uma para cada instancia. Na hora de desenhar, a engine manda a GPU renderizar aquele mesh N vezes de uma so vez, passando as transforms como dados. Isso e "instancing" de hardware, e o resultado e uma unica draw call (ou pouquissimas) para milhares de copias.
O que voce ganha:
- Um no na arvore em vez de milhares.
- Uma draw call em vez de milhares.
- Muito menos pressao na CPU para preparar o frame.
O que voce perde (e precisa aceitar):
- Todas as instancias compartilham o mesmo mesh e o mesmo material.
- Instancias nao sao nos: nao tem script, nao tem filhos, nao tem sinais, nao tem colisao.
MultiMesh e uma ferramenta de renderizacao em lote. Ele responde a pergunta "como desenho muita coisa igual barato", e nada alem disso.
MultiMesh nao e object pooling
Essa confusao aparece toda hora, entao vale cravar a diferenca.
Object pooling ataca o custo de criar e destruir nos em runtime. Instanciar uma cena e liberar da memoria tem preco, e fazer isso muitas vezes por segundo (tiros, particulas de gameplay, inimigos que morrem e nascem) gera picos de lag e trabalho para o garbage collector. Pooling resolve isso reaproveitando um conjunto fixo de nos: em vez de destruir, voce esconde e devolve para uma fila; em vez de criar, voce pega um da fila e reativa. Se esse for o seu problema, o passo a passo esta em object pooling para otimizacao na Godot.
MultiMesh ataca o custo de desenhar muita coisa. Ele nao reaproveita nada e nao tem fila de objetos. Ele so pinta N copias do mesmo mesh de forma eficiente.
Sao problemas ortogonais. Pooling pode ter draw calls demais se cada objeto do pool for um no visual. MultiMesh pode ter logica de negocio pesada se voce processar cada instancia toda frame. Em jogos maiores voce combina os dois: gerencia a logica e o ciclo de vida dos objetos com pooling ou com arrays proprios, e delega o desenho para um MultiMesh. Escolha pela pergunta que voce esta tentando responder: "criar e destruir esta caro" pede pooling; "desenhar esta caro" pede MultiMesh.
Configurando um MultiMesh por codigo (2D)
Vamos ao concreto. Adicione um MultiMeshInstance2D na cena e anexe o script abaixo. Ele monta um campo de grama espalhando tufos numa area, cada um numa posicao e rotacao aleatorias.
O ponto central e o recurso MultiMesh. Antes de definir quantas instancias voce quer, e obrigatorio configurar o transform_format e o mesh. Se voce definir instance_count antes disso, a Godot reclama.
extends MultiMeshInstance2D
@export var quantidade: int = 2000
@export var area: Vector2 = Vector2(1024.0, 600.0)
func _ready() -> void:
var mm: MultiMesh = MultiMesh.new()
mm.transform_format = MultiMesh.TRANSFORM_2D
mm.mesh = _criar_quad(Vector2(8.0, 24.0))
mm.instance_count = quantidade
var i: int = 0
while i < quantidade:
var pos: Vector2 = Vector2(
randf() * area.x,
randf() * area.y
)
var angulo: float = randf_range(-0.15, 0.15)
var t: Transform2D = Transform2D(angulo, pos)
mm.set_instance_transform_2d(i, t)
i += 1
multimesh = mm
O while percorre cada indice de 0 ate quantidade - 1 e escreve uma Transform2D. Uma Transform2D(rotacao, origem) ja monta a matriz com rotacao e posicao de uma vez, que e tudo que a grama precisa. No fim, atribuimos o recurso ao no com multimesh = mm.
Falta o mesh. Em 2D o mais comum e usar um QuadMesh com uma textura, ou construir a geometria a mao. Aqui vai um helper tipado que devolve um quad simples:
func _criar_quad(tamanho: Vector2) -> QuadMesh:
var quad: QuadMesh = QuadMesh.new()
quad.size = tamanho
return quad
Para aplicar a textura da grama, defina o material do proprio MultiMeshInstance2D (a propriedade texture do no, ou um CanvasItemMaterial), porque todas as instancias compartilham esse material. Nao existe textura por instancia.
Perguntas frequentes
O que e MultiMesh na Godot 4?
MultiMesh e um recurso que desenha muitas copias do mesmo mesh numa unica draw call. Voce define quantas instancias quer e a transform de cada uma, e a GPU renderiza tudo de uma vez, sem criar um no por objeto.
Qual a diferenca entre MultiMesh e object pooling?
Object pooling reaproveita nos para evitar o custo de criar e destruir objetos em runtime. MultiMesh e sobre renderizacao em lote: ele nao reaproveita nada, ele desenha muitas instancias visuais numa draw call. Sao ferramentas para problemas diferentes e podem ser usadas juntas.
MultiMesh tem colisao?
Nao. Cada instancia do MultiMesh e apenas visual. Se voce precisa de colisao ou logica individual, precisa gerenciar isso por fora, com Area2D, RayCast ou seus proprios dados.
Quando NAO usar MultiMesh?
Quando os objetos precisam de meshes ou materiais diferentes, de nos filhos, de scripts individuais, de animacao complexa por objeto ou quando sao poucos. Para dezenas de objetos com logica propria, nos normais sao mais simples e o ganho de MultiMesh e irrelevante.


