Resolvendo uma colisão com forças

14

No meu mecanismo de física 2D, posso detectar colisões AABB vs AABB e resolvê-las, encontrando o menor vetor de penetração e adicionando-o à posição da AABB.

Fazer isso "empurra" o primeiro AABB para fora do segundo AABB, mas não lida com as mudanças de velocidade / aceleração.

Se eu adicionar aceleração por gravidade à minha simulação, a velocidade do primeiro AABB dinâmico continua crescendo, mesmo quando está apoiada no segundo AABB estático. Eventualmente, a velocidade se tornará muito grande e a colisão não será detectada (o AABB dinâmico passará pelo estático).

Tentei ajustar a velocidade para zero após a resolução, mas obviamente não funcionou bem e criei simulações irrealistas.

Li online que a resolução de colisões trabalhando manualmente na posição ou a velocidade não está correta. Tentei implementar forças (massa é um "codificado" 1 por enquanto):

void Body::applyForce(sf::Vector2f mForce) { acceleration += mForce; }

void Body::integrate(float mFrameTime)
{
    velocity += acceleration * mFrameTime;
    position += velocity * mFrameTime;

    acceleration = {0, 0};
}

Se eu aplicar o menor vetor de penetração como força durante a resolução de colisão, o AABB dinâmico será "empurrado" para fora do estático, mas sua velocidade nunca diminuirá em uma simulação sem gravidade e continuará se movendo para sempre.

Existe uma maneira de aplicar uma força "temporária"? Uma força que lida com empurrar o primeiro AABB para fora do segundo AABB e depois para quando o AABB não colide mais?

Código fonte completo disponível aqui: https://github.com/SuperV1234/SSVSCollision

Vittorio Romeo
fonte
1
Estou interessado nisso. Você já encontrou uma solução?
TravisG 03/02
@ TravisG: ainda não, infelizmente. Adicionarei uma recompensa amanhã se não receber nenhuma resposta.
Vittorio Romeo
A força não é igual à aceleração, antes de tudo. Você precisa de massa para calcular a aceleração. Se você estiver modificando as posições para impedir a penetração dos dois corpos, use também a massa e mova os dois corpos com base nela. A aplicação de uma força igual ao vetor de penetração não tem mérito. O Box2D é baseado em impulso, funciona diretamente nas velocidades, pode não estar "correto", mas é bom o suficiente. Lidar com mudanças de velocidade em um mecanismo baseado em impulsos é muito simples; portanto, você pode especificar se deseja definitivamente uma solução baseada em força ou se a solução baseada em impulsos muito mais simples é boa o suficiente.
Dreta
Pessoalmente, sugiro pegar um livro sobre motores de física, pelo menos ler os primeiros capítulos sobre física newtoniana. Suas suposições estão incorretas e tentar responder a essa pergunta significaria ter que ensinar noções básicas de física enquanto tentava explicar algoritmos de alto nível para resolver colisões.
dreta
@dreta suas suposições estão bem. Ele ressaltou que sua massa para todos os objetos é simplesmente "1" por enquanto, o que torna suas seções de código válidas. A propósito, embora o Box2D possa lidar diretamente com as velocidades, ele deve, de alguma forma, lidar com o mesmo problema. Se, em vez de aplicar uma força, o Box2D aplica um impulso, de alguma forma ainda deve lidar com o fato de que o impulso não desaparece apenas depois que os objetos são separados. Embora, é possível que ele faz na verdade não lidar com isso em tudo e só permite que os objetos manter sua energia (que seria como este no mundo real depois de tudo)
TravisG

Respostas:

13

Primeiro, recomendo o uso de uma biblioteca física gratuita e de código aberto, como o Box2D, e focando apenas nos aspectos do seu jogo que o tornam único! Se você insistir em reinventar a roda, continue lendo ... note que todos os mecanismos de física são aproximações e, embora o método descrito abaixo seja mais preciso do que o seu modelo atual, os resultados do Box2D serão muito mais realistas.


Para uma maneira rápida de modelar uma resolução de colisão mais precisa de dois objetos A e B:

  1. Encontre as posições logo antes da colisão. Você já está aproximando isso: "encontrando o menor vetor de penetração e adicionando-o à posição da AABB".
  2. Encontre as velocidades logo após a colisão usando a física newtoniana :
    • Para o caso em que a massa é codificada como 1, basta trocar as velocidades (isso não se aplica a objetos estáticos que devem ter massa infinita):
      • Av = Bu
      • Bv = Au
    • Se os objetos A e B tiverem massas diferentes:
      • Av = (Au * (Am - Bm) + (2 * Bm * Bu)) / (Am + Bm)
      • Bv = (Bu * (Bm - Am) + (2 * Am * Au)) / (Am + Bm)
    • Onde:
      • v: velocidade após colisão
      • u: velocidade antes da colisão
      • m: massa (use o maior número possível para a massa de um objeto estático fixo)
  3. Defina a aceleração como 0: a aceleração da colisão foi explicada acima pelos cálculos de velocidade na etapa número 2.

Por favor, dê uma olhada no meu programa de asteróides de amostra que demonstra esses conceitos.


Em seguida, considere os objetos empilhados:

Como você observou, o uso da velocidade para simular objetos empilhados / em repouso não funciona bem: velocidade é a velocidade que um objeto está se movendo; portanto, se estiver descansando em um objeto estático, a velocidade deve estar próxima de 0. Não faz sentido aumentar a velocidade de um objeto para fazê-lo aparecer em repouso:

Se eu adicionar aceleração por gravidade à minha simulação, a velocidade do primeiro AABB dinâmico continua crescendo, mesmo quando está apoiada no segundo AABB estático. Eventualmente, a velocidade se tornará muito grande e a colisão não será detectada (o AABB dinâmico passará pelo estático).

O que realmente deveria acontecer é uma força de aceleração que está indo na direção oposta, pois a gravidade deve cancelar a gravidade. (Isso é chamado de força de contato normal). Um atalho é simplesmente não aplicar gravidade a corpos que não estão no ar:

  • Um método para fazer isso é manter um estado "fundamentado":
    • Não aplique gravidade a objetos em um estado aterrado.
    • Se um objeto colide com um objeto de baixo e sua velocidade é muito pequena, ele entra no estado aterrado.
    • Um objeto sai do estado aterrado quando sua velocidade vertical excede um determinado valor positivo.

Atualizar:

  • Nos termos dos leigos, a física newtoniana diz que a energia total antes e depois de uma colisão deve corresponder. Quando dois objetos se chocam, sua energia é redistribuída. Energia é uma combinação de velocidade e peso: coisas mais pesadas e rápidas têm mais energia. Isso é intuitivo. No entanto, o que não é intuitivo é a maneira exata como os pesos afetam a redistribuição de energia.
  • A troca de velocidades é um atalho apenas para dois corpos dinâmicos não fixados que possuem a mesma massa (objetos fixos estáticos têm massas infinitas muito grandes).
  • O atalho quando um corpo estático é fixo é: o outro corpo dinâmico e não fixo mantém a mesma velocidade; o único ângulo é alterado (imagine uma mesa de bilhar quando uma bola bate no trilho. O trilho tem essencialmente uma massa infinita muito grande).
  • Para outros casos, como três ou mais objetos, as equações de movimento newtonianas completas devem ser resolvidas (conservação do momento e conservação da energia cinética).
  • Não tenho certeza se as equações newtonianas de movimento podem ser resolvidas por mais de dois corpos. Felizmente, no entanto, três objetos quase nunca colidem exatamente ao mesmo tempo. É suficiente lidar com os dois primeiros corpos que colidem e, em seguida, lidar com as colisões seguintes usando as novas velocidades das resoluções de colisão anteriores. Esse é um bom motivo para manter o tempo físico mais pequeno possível e lidar com colisões antes que ocorram penetrações.
  • Você notará na minha demonstração de asteróides que muitos corpos são criados à medida que rochas maiores são divididas em outras menores. No entanto, eu sempre manejo colisões entre pares de corpos; nunca lidar explicitamente com uma colisão com mais de dois corpos.
Leftium
fonte
Obrigado pela resposta detalhada. Há algo que eu não entendo: velocidades de troca funcionam bem em uma colisão com 2 corpos - no entanto, não vejo como isso pode funcionar quando vários corpos (e também corpos estáticos) colidem ao mesmo tempo. Mesmo sem a gravidade, ter um corpo dinâmico colide ao mesmo tempo com um corpo estático e outro corpo dinâmico causa problemas. Como a velocidade é trocada, tudo depende da ordem da colisão. Se o corpo estático for colidido por último, ele parará de se mover. Se o dinâmico for, o corpo se moverá novamente. Como isso é corrigido?
Vittorio Romeo
@Vee: Boas perguntas! Três corpos + e corpos estáticos são duas questões separadas. Eu me dirigi a ambos em uma atualização. Resumo: lida com colisões de dois objetos por vez; corpos estáticos têm massa infinita muito grande.
Leftium
Seu modelo para contatos de repouso é estranho. Contatos de descanso não são apenas para a gravidade, eles devem trabalhar para qualquer força. A maneira mais fácil de trabalhar é apenas remover a velocidade obtida devido à aceleração no quadro anterior ao entrar em contato. Também para pequenas velocidades, você pode remover completamente a restituição, embora seus cálculos não considerem a restituição. Essa abordagem funciona para todas as forças, é fácil de implementar e parece boa o suficiente.
dreta
16

Resolver este problema requer o ajuste da posição e possivelmente da velocidade. Os motores de física do corpo rígido têm um solucionador que marcha os objetos para a frente no tempo, usando as leis do movimento de Newton, além de resolver restrições de atrito e não penetração. Esses mecanismos podem calcular a combinação certa de movimento linear e angular para criar trajetórias plausíveis.

Se você deseja resolver apenas a sobreposição, pode usar pseudo-velocidades que geram trajetórias de separação sem aumentar o momento. Isso é feito no solucionador de posição do Box2D.

Eu recomendo minhas apresentações do GDC de 2006 e 2007 aqui:

http://code.google.com/p/box2d/downloads/list

Além disso, você pode consultar o Box2D Lite para uma implementação simplificada.

Erin Catto
fonte
+1 para a observação de ser necessário ajustar a posição também. Poucas pessoas aceitam isso, mas, para aumentar a estabilidade da simulação, a maioria dos mecanismos trapaceia ajustando as posições diretamente. Em suma, se é plausível, funciona para jogos.
Teodron # 6/13
Obrigado pela resposta. Eu queria saber algo que provavelmente perdi na apresentação: os corpos estáticos são tratados de uma maneira especial no Box2D? Quero dizer - o que acontece quando um corpo dinâmico atinge um corpo estático?
Vittorio Romeo
2

insira a descrição da imagem aqui

No mundo real, não há força que "empurre" um corpo para fora de outro, porque os objetos nunca se penetram. O mais próximo é a força normal : criada no momento do contato em colisões no mundo real, impede a penetração em primeiro lugar.

O ângulo dessa força normal é perpendicular à superfície de contato dos dois objetos em colisão. A magnitude depende de quanta força é necessária para impedir a penetração. (Observe que apenas o componente y da força normal deve ser usado, a menos que outras forças como a força de atrito também sejam modeladas).

Embora seja possível modelar explicitamente a força normal, é mais simples modelar apenas seus efeitos:

  1. Evite a interseção de objetos:
    • Ajustando velocidades resolvendo colisões no momento do impacto. (melhor)
    • Ajustando manualmente as posições dos corpos para que não se cruzem. (mais fácil) Você já está fazendo isso "encontrando o menor vetor de penetração e adicionando-o à posição da AABB".
  2. Não aplique a gravidade onde houver uma força normal cancelando a força da gravidade.
    • Um objeto em contato com outro objeto abaixo dele está sujeito à força normal. Portanto, é uma questão de acompanhar esses objetos. (Na verdade, qualquer objeto que esteja em contato deve ter uma força normal aplicada, mas nem todos terão um efeito líquido em relação à gravidade.)
    • Se você deseja adicionar objetos que podem deslizar para baixo outros objetos que estão em ângulo, será necessário adicionar a força de atrito ex componente da força normal.

Descrevi isso de maneira um pouco diferente em minha outra resposta, que é mais sobre colisões em geral .

Leftium
fonte