O tanque do Jolt e o teto do Godot.
A quinzena anterior fechou o arco conceitual do multicorpo no papel. Esta entrada é a parte empírica: rodei um sample real do Jolt, abri os headers em C++ pra descobrir de que peças ele é feito, e depois tentei remontar a mesma ideia no editor do Godot com nós Joint3D. O resultado é o comparativo formal Jolt × Godot — o entregável-âncora da semana — e a confirmação, na prática, de onde o caminho pelo nó pronto termina.
VehicleConstraint que resolve suspensão, contato e atrito de roda dentro do solver. O Godot tem um nó chamado VehicleBody3D que não é essa peça — é uma reimplementação própria, com nome parecido. E as juntas primitivas que sobram (SliderJoint3D) perdem a mola quando rodam sobre Jolt. Ou seja: pela via dos nós prontos, não dá.Os três dias, etapa por etapa
O plano da semana está no roadmap 10 ago – 7 set · Do sample rodando à ponte em C++. Ele separa a semana em duas faixas: a Faixa A (pontos 1 e 2 — provar até onde o Godot vai) de segunda a quarta, e a Faixa B (pontos 3 e 4 — a ponte C++) de quinta em diante. Esta entrada documenta a Faixa A inteira; a Faixa B segue em aberto.
Rodar o sample do Jolt
Demo web do JoltPhysics.js, categoria Constraints e o Tank Controller dirigido na mão. Bloco 01.
Comparativo formal Jolt × Godot
Anatomia do tanque lida nos headers, a distinção VehicleBody3D × VehicleConstraint e a tabela consolidada. Blocos 02 a 05.
Replicar no Godot com Joint3D
Chassi + suspensão por SliderJoint3D, dois achados duros e o teste que bate seco. Bloco 06.
Faixa B · a ponte C++
Ponto 3: ler a doc do GDExtension (conceito, não construir extensão de produção). Ponto 4: espelhar o GDChrono do professor pro Jolt. Nada disso entrou nestes três dias.
Dia 1 · o tanque rodando
10 agoO caminho mais curto pra ver o Jolt de verdade não é compilar os samples nativos: é a build WebAssembly (JoltPhysics.js), que roda no navegador sem nenhum setup. Passei pela categoria Constraints — as juntas “puras”, o vocabulário primitivo do motor — e escolhi como sample-âncora da semana o Tank Controller Demo: um tanque de esteiras acionado por VehicleConstraint + TrackedVehicleController. Dirigi na mão pra ver o comportamento.
Por que ele gira no próprio eixo?
É direção diferencial (skid-steering): cada esteira recebe uma velocidade diferente — uma pra frente, a outra pra trás ou mais devagar — e o torque resultante dos dois lados faz o corpo pivotar. Não tem nada de mágico nem hardcoded: é distribuição de forças normal, com um controlador específico por trás decidindo a velocidade de cada lado.
Por que a física parece tão mais estável?
O solver do Jolt resolve todas as constraints e contatos simultaneamente e de forma implícita, a cada passo. Meu ground_contact.gd aplica força explícita por raycast, quadro a quadro. Foi essa diferença de arquitetura — não a matemática em si — que causou o bug de ejeção que resolvi com o clamp do círculo de atrito.
VehicleWheel3D.steering do Godot, que só cobre esquema Ackermann, não sabe fazer.VehicleConstraint com direção diferencial — Godot não expõe isso.” Foi essa frase que virou a pergunta do dia 2.Dia 2 · de que peças o tanque é feito
11 agoPra montar um comparativo que sustente decisão arquitetural, não dá pra confiar em descrição de tutorial. Clonei o jrouwe/JoltPhysics e fui ler os headers direto, na branch master, dentro de Jolt/Physics/Vehicle/. Cada linha da tabela abaixo saiu de um arquivo real.
VehicleConstraint.h // a constraint composta — o container de tudo
Wheel.h // roda: raycast/shape-cast, suspensão, atrito
TrackedVehicleController.h // o controlador do tanque: motor + transmissão
VehicleTrack.h // uma esteira: razão própria + multiplicador E/D
VehicleDifferential.h // divisão de torque (usado no controlador de carro)| Peça | O que faz (confirmado em código) |
|---|---|
| VehicleConstraint | Constraint composta — containeriza tudo abaixo e entrega o conjunto pronto pro solver. |
| Wheel · contato | Raycast ou shape-cast por roda. Mesmo princípio do meu RayCast3D — só que embutido na constraint, não solto num script. |
| Wheel · suspensão | Mola por roda, com curso dedicado (mSuspensionMinLength / mSuspensionMaxLength). |
| TrackedVehicleController | Dono do motor (VehicleEngine, curva de torque × RPM) e da transmissão (VehicleTransmission) — únicos, compartilhados pelas duas esteiras. |
| VehicleTrack | Uma por lado. Tem razão de engrenagem própria (mDifferentialRatio) mais um multiplicador (mLeftRatio / mRightRatio) — é esse multiplicador que produz o skid-steer. |
| Atrito por roda | Coeficientes fixos (mLongitudinalFriction, mLateralFriction) — mais simples que o modelo de carro, que usa curva de slip. |
VehicleTrack. A diferença importa: o torque disponível é um recurso compartilhado, não dois independentes.Este bloco levanta de que peças o veículo do Jolt é feito. Como elas operam por dentro — o raycast que encontra o chão, o ciclo de um passo de física e as equações de cada roda — está em Um corpo só, quatro bengalas.
A dúvida grande: VehicleBody3D é o VehicleConstraint?
11 agoO Godot 4.6 passou a usar o Jolt como backend padrão de física. A pergunta óbvia, então: quando eu ponho um VehicleBody3D na cena rodando sobre Jolt, estou usando o VehicleConstraint real por baixo? A resposta muda tudo — se fosse sim, a semana inteira seria desnecessária.
VehicleBody3D é uma abstração do próprio Godot, no nível do PhysicsServer3D — cada backend implementa a lógica de veículo por conta própria. O VehicleConstraint do Jolt fica do outro lado da linha, sem porta de entrada pelo editor.É anterior ao Jolt no engine
O VehicleBody3D existe desde antes de o Jolt ser opção no Godot, baseado no sistema clássico de veículo por raycast. Ele vive no nível do PhysicsServer3D, e cada backend de física precisa implementar aquela lógica por conta própria.
O comportamento diverge entre backends
O guia de migração do Godot 4.6 confirma: suspensão, atrito de pneu e trem de força produzem resultados diferentes no GodotPhysics e no Jolt. Se o nó chamasse a mesma peça C++ por baixo, não haveria divergência a documentar.Divergência entre backends é a assinatura de reimplementação, não de reaproveitamento.
A prova mais forte: alguém está pedindo
Existe uma proposal aberta e recente nos godot-proposals pedindo exatamente a exposição das vehicle constraints reais do Jolt — o que só faz sentido se elas ainda não estiverem expostas. Há também uma proposal mais geral sobre as constraints do Jolt indisponíveis no Godot.
VehicleBody3D é um controle remoto universal: os botões (acelerar, frear, virar) são sempre os mesmos, mas cada “TV” — cada motor de física — reage do seu próprio jeito por trás. O VehicleConstraint é o controle de fábrica, feito sob medida pras peças internas do Jolt.VehicleWheel3D.steering só cobre esquema Ackermann — roda que gira, como num carro. Não achei suporte nativo a direção diferencial / skid-steer no VehicleBody3D. Pra ter isso de verdade, o caminho é GDExtension, não o nó pronto.O que é, exatamente, um “Controller”
11 agoO VehicleConstraint resolve só a parte genérica de um veículo: contato de roda, suspensão e atrito. Quem traduz o input do jogador em força nas rodas é uma camada plugável em cima dele — o Controller. Essa separação é a peça de arquitetura que mais me interessa a longo prazo.
Motor
A curva de torque × RPM — quanta força o conjunto tem disponível em cada regime.
Câmbio
As relações de marcha: como o torque do motor é convertido antes de chegar às rodas.
Diferencial
Como o torque se divide entre as rodas — a peça que existe no controlador de carro e não no de tanque.
WheeledVehicleController
Diferencial de verdade mais direção por ângulo de roda (Ackermann). É o modelo que o VehicleBody3D do Godot tenta cobrir.
TrackedVehicleController
Sem diferencial e sem roda que gira: a velocidade de cada esteira vem direto do input L/R. É o modelo que o rover provavelmente vai usar.
O comparativo formal · entregável-âncora
11 agoA tabela que o roadmap da semana pede: feature a feature, o que o Jolt tem nativamente e o que o Godot 4.6 expõe. Não é opinião sobre qual caminho seguir — é o levantamento que fundamenta a decisão.
| Feature | Jolt | Godot expõe? | Observação |
|---|---|---|---|
VehicleConstraint · a constraint composta | sim | não | Só existe como API C++. |
VehicleBody3D · o nó do Godot | — | sim, mas… | Reimplementação própria do Godot; não usa o VehicleConstraint por baixo e diverge no comportamento mesmo rodando sobre Jolt. |
| Raycast de contato por roda | sim | parcial | No Jolt vem embutido na constraint. No Godot o RayCast3D genérico existe, mas solto — não integrado a um sistema de veículo. |
| Suspensão spring-damper por roda | sim | parcial | No Jolt, com curso mín/máx dedicado por roda. No Godot, via VehicleWheel3D — mas com a física própria do backend. |
TrackedVehicleController · motor + câmbio compartilhados | sim | não | — |
VehicleTrack · razão + multiplicador E/D → skid-steer | sim | não | VehicleWheel3D.steering só cobre Ackermann. |
| Atrito da roda · círculo de atrito embutido | sim | não | Reimplementei isso na mão no protótipo raycast — foi de onde veio o bug da ejeção. |
Dia 3 · replicar no Godot com Joint3D
12 agoO ponto 2 do roadmap pede pra tentar reconstruir o cenário do sample usando só nós Joint3D — não pra entregar um veículo, mas pra medir onde a coisa bate no limite. O ajuste de escopo veio antes de abrir o editor.
VehicleConstraint não tem nenhum equivalente em Joint3D — é uma peça composta própria. Replicar o Tank literalmente exigiria simular uma corrente de corpos rígidos (as esteiras), o que é projeto próprio, não tarefa de um dia. Decisão: em vez do tanque, testar o limite com o veículo de rodas físico mais simples possível, reaproveitando a arquitetura já projetada na quinzena anterior — 1 chassi + 4 SliderJoint3D (suspensão) + 4 HingeJoint3D (rodas). Montei só o chassi e uma roda (frente-esquerda): o suficiente pra encontrar o teto.Achado 1 · SliderJoint3D no Jolt não tem mola de verdade
A issue rastreadora do godot-jolt lista, parâmetro a parâmetro, o que o backend Jolt suporta do SliderJoint3D. O status dela é “Done — as much as it can be”: não é um item pendente que um dia será feito, é o teto do que dá pra mapear.
Parâmetro do SliderJoint3D | Funciona no Jolt? |
|---|---|
| Limite superior / inferior (curso) | sim |
| Softness / Restitution / Damping do limite | não · incompatível com a SliderConstraint |
| Softness / Restitution / Damping do movimento livre | não |
| Limites e motor angulares | não · a própria issue recomenda Generic6DOFJoint3D |
SliderJoint3D dá apenas um batente rígido. Todos os parâmetros que produziriam efeito de mola são ignorados silenciosamente — sem erro, sem aviso no editor. O inspetor mostra campos que não fazem nada.Achado 2 · RigidBody3D não pode ser filho de outro RigidBody3D em movimento
O conjunto tombava sozinho em queda livre
Montei RodaSuporte_FE como filho do Chassi — os dois RigidBody3D. O conjunto tombava sozinho durante a queda, mesmo sem tocar o chão, e sempre pro lado onde estava o corpo aninhado.
Aninhamento de corpos rígidos não é confiável
Isolei tirando o chão da equação — só queda livre —, o que confirmou que o problema era estrutural, não de contato. A causa está registrada na issue godotengine/godot#120067: um RigidBody3D não segue de forma confiável um RigidBody3D pai em movimento. É comportamento de longa data do engine, não particularidade do meu setup. Correção: corpos ligados por junta devem ser irmãos na árvore — a junta já faz a ligação física, a hierarquia de nós não precisa (e não deve) refleti-la.
O teste final
Com a estrutura corrigida (chassi e suporte de roda como irmãos, ligados pelo Susp_FE) e o chão de volta, rodei a cena. O contato aconteceu — e o conjunto bateu seco, sem nenhum efeito de suspensão visível.
godot-jolt#109 — o limite existe, a mola não.SliderJoint3D no Godot/Jolt: bate seco, sem mola. Confirma empiricamente a limitação documentada no godot-jolt#109 — a VehicleConstraint nativa do Jolt resolve isso internamente; a via Joint3D não tem substituto.” Isso fecha o ponto 2 da reunião: medir até onde o Godot chega, e onde bate no limite.Síntese dos três dias
Três achados sustentam a decisão arquitetural, todos verificados em fonte primária — código-fonte ou issue oficial, não documentação secundária.
Lacuna de API
O VehicleConstraint do Jolt não tem equivalente em Joint3D, e o VehicleBody3D do Godot não é uma exposição dele — é uma reimplementação própria e paralela.
Lacuna de suporte no backend Jolt
Mesmo as juntas primitivas que existem perdem funcionalidade quando rodam sobre Jolt: o SliderJoint3D fica sem mola. Documentado, e não vai mudar.
Gotcha de implementação
RigidBody3D aninhado em outro RigidBody3D móvel é estruturalmente não confiável no Godot.Regra de ouro pra qualquer rig multicorpos daqui pra frente: juntas conectam irmãos, nunca pai-filho.
Esquema de direção do rover
Skid-steer como o tanque, ou Ackermann como o carro? É decisão do professor e ainda não foi definida — e ela muda qual dos dois controllers do Jolt vira o modelo de referência.
As outras três rodas
Montar o resto do veículo físico é opcional a partir daqui: o achado central já está confirmado e documentado. Só faz sentido se eu precisar do rig pra outra coisa.
Contexto anterior: o arco conceitual está em Constraints, juntas e o Jolt por dentro, e o ponto de partida — por que o VehicleBody3D não é um multicorpo de verdade — está na nota do sandbox no Godot.