Animação no Blender — Trabalho 3D Orientado por Python
Controle o Blender através do bpy, em modo background, a partir de um script que pode ser executado novamente. Trate o arquivo .blend como um artefato de construção do script: o script é a fonte da verdade, o arquivo é o entregável.
Leia references/BLENDER-PLAYBOOK.md para arquitetura e julgamento, e references/BLENDER-RECIPES.md para padrões de código prontos para uso. Verifique cada detalhe da API na documentação da versão instalada do Blender; a API Python muda entre versões.
1. Verifique o ambiente primeiro
blender --version
blender --background --factory-startup --python-expr \
"import bpy, sys; print('BLENDER', bpy.app.version_string); print('PY', sys.version.split()[0]); print('ENGINES', [e.bl_idname for e in bpy.types.RenderEngine.__subclasses__()][:5])"
Regras:
bpypertence ao Python empacotado do Blender. Nunca executepip install bpye nunca execute scripts de cena com o Python do sistema.- Use
--python-exit-code 1para que uma exceção Python faça o comando falhar em vez de produzir um sucesso silencioso. - Use
--factory-startuppara construções limpas; nunca use para destruir um projeto aberto do usuário. - Registre a versão do Blender, motor, intervalo de quadros, resolução, FPS e caminho de saída no início de cada render.
2. Invocações canônicas
# Construir uma cena do zero e salvar o .blend
blender --background --factory-startup --python-exit-code 1 --python blender/scripts/build_scene.py
# Modificar um projeto existente
blender --background project.blend --python-exit-code 1 --python blender/scripts/update_scene.py
# Renderizar a animação salva
blender --background project.blend --render-anim
# Renderizar um quadro
blender --background project.blend --render-frame 120
# Renderizar um intervalo com segurança (sequência de imagens)
blender --background project.blend --python-exit-code 1 --python blender/scripts/render_frames.py
Execute trabalhos longos com saída redirecionada para logs/, e sempre prefira uma sequência de imagens para qualquer coisa que possa precisar ser retomada.
3. Arquitetura do script
Comece com um arquivo para uma cena pequena. Divida quando a cena exceder aproximadamente 300 linhas ou tiver mais de um plano:
blender/
config.py # fps, intervalo de quadros, resolução, paleta, caminhos, semente
build.py # ponto de entrada: reset → setup → construir planos → salvar
scene_setup.py # mundo, unidades, coleções, configurações de render
geometry.py # primitivas, curvas, malhas paramétricas
materials.py # construtores de nós, fábrica reutilizável de materiais
animation.py # keyframes, drivers, movimento procedural
camera.py # rigs, órbita/dolly, profundidade de campo, verificações de enquadramento
lighting.py # luz principal/preenchimento/contra-luz, HDRI, acentos emissivos
simulation.py # partículas, corpo rígido, pano — configuração de cache
render.py # motor, amostras, saída, folha de contato, codificação
shots/ # um módulo por plano: shot_01.py, shot_02.py
Innegociáveis:
- Idempotente. Reexecutar a construção atualiza apenas suas coleções/objetos nomeados; nunca duplica geometria ou apaga conteúdo não relacionado do usuário.
- Nomeado.
Main_Logo,Cam_Orbit,Light_Key,Emitter_Particles. Nunca envieCube.003. - Configurado. Cada valor ajustável reside em
config.pyou em uma dataclass, para que uma revisão seja uma alteração de uma linha. - Assertivo. Falhe ruidosamente se um ativo, câmera, fonte ou diretório de saída estiver faltando.
- Escopo. A limpeza exclui apenas coleções cujos nomes você possui, prefixados, por exemplo,
MS_.
4. Construção da cena
- Prefira a API de dados (
bpy.data.objects.new,bpy.data.meshes.new,collection.objects.link) ao invés dobpy.opssensível ao contexto, que depende de seleção, modo e área. - Quando um operador for realmente necessário, forneça uma substituição de contexto adequada para essa versão e documente o motivo.
- Construa materiais através de nós e uma pequena função de fábrica; não copie-e-cole árvores de 20 nós por objeto.
- Use escala do mundo real e defina o sistema de unidades da cena; escala errada quebra profundidade de campo, física e iluminação.
- Mantenha a árvore de nós do Mundo explícita (cor, intensidade, HDRI) para que os renders sejam reproduzíveis em outra máquina.
- Empacote ou relativize ativos. Caminhos
//assets/...mais uma pasta de pacote são melhores do que caminhos absolutos para a pasta Downloads de alguém.
5. Animação
Escolha o mecanismo deliberadamente:
| Necessidade | Use |
|---|---|
| Posição/rotação/escala/alteração de material criada manualmente | Keyframes com interpolação explícita |
| Propriedade seguindo outra propriedade ou expressão | Drivers (expressões simples e documentadas) |
| Movimento repetido/paramétrico (órbitas, ondas, grades, espirais) | Matemática dependente do quadro, avaliada sem estado |
| Milhares de instâncias, padrões, dispersão | Geometry Nodes |
| Movimento fisicamente emergente | Simulações (cache, verifique o intervalo completo) |
| Caminho de câmera através do espaço | Curva + restrição Follow Path, ou rig com keyframes |
Higiene de keyframes:
obj.location = (0, 0, 0)
obj.keyframe_insert("location", frame=1)
obj.location = (4, 0, 0)
obj.keyframe_insert("location", frame=48)
for fc in obj.animation_data.action.fcurves:
for kp in fc.keyframe_points:
kp.interpolation = 'BEZIER'
kp.easing = 'EASE_IN_OUT'
kp.handle_left_type = kp.handle_right_type = 'AUTO_CLAMPED'
- Defina a interpolação intencionalmente. Bezier padrão é bom para movimentos orgânicos; use
LINEARpara velocidade constante e movimento mecânico; useCONSTANTpara visuais pixelados/quadro a quadro. - Nunca deixe uma suavização não intencional em um ciclo de repetição — isso produz uma batida no ponto de loop.
- Para loops: torne o quadro 1 e o quadro N+1 idênticos, depois renderize
[1, N]. - Tudo procedural deve ser uma função pura do quadro:
f(frame). Sem estado acumulativo, semrandomsem semente.
6. Geometry Nodes e instanciamento
Use Geometry Nodes quando precisar de escala, variação ou controle não destrutivo:
- Dispersão/instanciamento (árvores, detritos, estrelas, blocos de multidão).
- Arrays paramétricos, grades, padrões radiais, mosaicos geométricos islâmicos.
- Deslocamento animado, campos e rotação/escala por instância.
- Converter um loop pesado de 10.000 objetos em Python em uma única árvore de nós.
Construa nós por nome com nodes.new(...) e links.new(...), não por índice frágil. Exponha os controles que o usuário pedirá (contagem, raio, semente, velocidade) como entradas do modificador para que uma revisão não precise de alteração de código.
7. Materiais, iluminação, câmera
- Materiais: Base Principled BSDF; rugosidade/metalicidade explícitas; emissão para acentos (mantenha contido — bloom não conserta uma cena sem graça). Transparência real apenas quando necessário, e verifique-a no motor final.
- Iluminação: principal → preenchimento → contra-luz → ambiente. Forma e profundidade vêm antes da decoração. Verifique a exposição e o corte de realces, não apenas o viewport.
- Câmera: escolha distância focal e enquadramento para o assunto. Órbita, dolly, grua ou parada — cada uma deve ter um motivo. Verifique o enquadramento nos quadros extremos, não apenas no quadro 1. Prefira alças Bezier suaves; adicione um ajuste sutil em vez de uma parada brusca.
- Profundidade de campo: foque no ponto da história; nunca desfoque texto pequeno.
8. Motores e configurações de render
| Motor | Use para | Custo |
|---|---|---|
| EEVEE | Motion graphics, trabalho estilizado, iteração rápida, pré-visualizações | Baixo |
| Cycles | Luz fotorrealista, reflexos, iluminação global, vidro, beleza final | Alto |
| Workbench | Bloqueio, silhuetas, animatics | Muito baixo |
Teste ambos quando estiver em dúvida; a velocidade do motor depende da cena, não do marketing. GPU depende da construção, driver e SO — sempre mantenha um caminho de CPU.
Defina explicitamente e registre:
scene.render.engine = 'BLENDER_EEVEE_NEXT' # 4.2+; versões mais antigas podem usar 'BLENDER_EEVEE'
scene.render.resolution_x, scene.render.resolution_y = 1920, 1080
scene.render.resolution_percentage = 100
scene.render.fps, scene.render.fps_base = 30, 1.0
scene.frame_start, scene.frame_end = 1, 300
scene.render.image_settings.file_format = 'PNG'
scene.render.image_settings.color_mode = 'RGBA'
scene.render.filepath = "//renders/shot_01/frame_"
- Pré-visualização: resolução de 25–50%, amostras baixas, EEVEE ou Workbench.
- Final: resolução total, motor escolhido para o visual, desfoque se ajudar, transformação de visualização correta.
- Cor: decida a transformação de visualização (AgX/Filmic/Standard) uma vez, aplique a todos os passes e corresponda-a downstream no Remotion/FFmpeg. Transformações incompatíveis são a causa mais comum de "a composição parece desbotada".
- Renders longos → sequência PNG (ou EXR quando HDR for necessário), depois codifique. Saída de vídeo direta é para revisões rápidas.
9. Escada de pré-visualização
- Uma imagem estática em um quadro representativo.
- Quadros-chave: primeiro, revelação, pico, cada transição, último.
- Segmento de baixa amostragem e baixa resolução contendo o movimento mais difícil.
- Pré-visualização completa em escala reduzida, FPS real.
- Final apenas após 1–4 parecerem corretos.
Inspecione com uma folha de contato mais quadros direcionados:
ffmpeg -i preview.mp4 -vf "fps=2,scale=320:-1,tile=4x4" -frames:v 1 previews/contact.jpg
Procure por flicker, z-fighting, popping, interseções, textura "nadando", corte de câmera, mudanças de exposição e texto ilegível.
10. Trabalho com texto, multilíngue e logotipos
- Converta texto em malha apenas após confirmar a cópia e a licença da fonte; mantenha um objeto de texto editável na origem.
- Verifique a cobertura de glifos antes de animar. Para persa/árabe, verifique a formação, junção, ordem RTL, diacríticos e pontuação de script misto no quadro renderizado — uma string correta pode renderizar errado se o caminho do texto não formar.
- Para trabalho com marca/logotipo, obtenha fonte vetorial quando possível; se raster, trace deliberadamente e verifique bordas em 4K.
- Chanfro/peso no tipo para que ele sobreviva à luz; evite bordas preto-no-preto ou branco-no-branco puro.
11. Desempenho e confiabilidade
- Instancie, não duplique. Reduza a subdivisão antes de reduzir as amostras.
- Limite camadas transparentes e volumetria; eles são os assassinos usuais de tempo de render.
- Armazene em cache as simulações e confirme que o cache está dentro do projeto ou documentado.
- Renderize em lotes de quadros para trabalhos frágeis; verifique as contagens de quadros e capture quadros faltando antes de codificar.
- Monitore RAM/VRAM/disco. Sequências EXR 4K são grandes; verifique o espaço livre antes de um render longo.
- Faça backup de um
.blendantes de abri-lo/salvá-lo com uma versão mais recente do Blender — arquivos mais novos podem não abrir em versões mais antigas.
12. Exemplo mínimo funcional
# build.py — execute com:
# blender --background --factory-startup --python-exit-code 1 --python build.py
import bpy, bmesh, math, os
scene = bpy.context.scene
scene.frame_start, scene.frame_end = 1, 120
scene.render.fps = 30
scene.render.resolution_x, scene.render.resolution_y = 1920, 1080
scene.render.engine = 'BLENDER_EEVEE_NEXT'
scene.render.filepath = "//renders/frame_"
# limpar coleção própria
col = bpy.data.collections.get("MS_Main") or bpy.data.collections.new("MS_Main")
if col.name not in scene.collection.children:
scene.collection.children.link(col)
def add_sphere(name, loc, radius, mat):
"""Esfera pela API de dados: sem operadores, sem dependência de contexto."""
mesh = bpy.data.meshes.new(name)
bm = bmesh.new()
bmesh.ops.create_uvsphere(bm, u_segments=32, v_segments=16, radius=radius)
bm.to_mesh(mesh)
bm.free()
obj = bpy.data.objects.new(name, mesh)
obj.location = loc
col.objects.link(obj)
obj.data.materials.append(mat)
return obj
mat = bpy.data.materials.new("MS_Emission")
mat.use_nodes = True
bsdf = mat.node_tree.nodes["Principled BSDF"]
bsdf.inputs["Base Color"].default_value = (0.05, 0.6, 0.55, 1)
bsdf.inputs["Emission Color"].default_value = (0.1, 0.9, 0.8, 1)
bsdf.inputs["Emission Strength"].default_value = 3.0
bsdf.inputs["Roughness"].default_value = 0.3
core = add_sphere("MS_Core", (0, 0, 1), 0.8, mat)
core.keyframe_insert("scale", frame=1)
core.scale = (1.15, 1.15, 1.15)
core.keyframe_insert("scale", frame=40)
core.scale = (1.0, 1.0, 1.0)
core.keyframe_insert("scale", frame=90)
# câmera
cam_data = bpy.data.cameras.new("MS_Cam")
cam = bpy.data.objects.new("MS_Cam", cam_data)
col.objects.link(cam)
scene.camera = cam
cam.location = (6, -6, 3)
cam.rotation_euler = (math.radians(75), 0, math.radians(45))
# salvar
os.makedirs(bpy.path.abspath("//renders"), exist_ok=True)
bpy.ops.wm.save_as_mainfile(filepath=bpy.path.abspath("//scene.blend"))
print("BUILD OK", len(col.objects), "objects")
Mais em references/BLENDER-RECIPES.md: rigs de órbita, easing, dispersão Geometry Nodes, partículas, texto, passes alfa, scripts para render farm e comandos de codificação.
13. Blender MCP (conveniência opcional)
Scripts em modo background são o caminho de produção: reproduzíveis, diferenciáveis, depuráveis, compatíveis com CI. MCP é útil para inspeção de cena interativa e ajustes ao vivo em uma sessão já aberta. É uma integração de terceiros, não um componente do Blender.
Se o usuário quiser: revise o repositório e a licença, verifique a compatibilidade com o Blender instalado, entenda que ele concede execução arbitrária de Python dentro do Blender, mantenha-o vinculado ao loopback e nunca o exponha a uma rede não confiável. O nome atual do pacote é mcp-for-blender; siga as instruções de configuração atuais do repositório em vez de trechos antigos blender-mcp. Não o torne uma dependência de nenhum projeto entregue.
14. Entregáveis
Um trabalho no Blender está concluído quando você tiver:
output/final.mp4(ou o formato solicitado), validado comffprobe.blender/scripts/*.py— o código-fonte da construção.scene.blend— o projeto editável, com ativos empacotados ou relativos.renders/sequência de imagens (ou mestre documentado) mantida quando útil.README.md— versão exata do Blender, instalação, construção, pré-visualização, render final e comandos de revisão.- Um breve relatório: ferramentas, resolução, FPS, duração, contagem de quadros, o que foi verificado visualmente.
Nunca entregue apenas o MP4 quando o usuário pediu uma animação que ele pode querer alterar.