Resolver una colisión con fuerzas

14

En mi motor de física 2D, puedo detectar colisiones AABB vs AABB, y resolverlas al encontrar el vector de penetración más corto y agregarlo a la posición de AABB.

Hacer esto "empuja" al primer AABB fuera del segundo AABB, pero no trata en absoluto los cambios de velocidad / aceleración.

Si agrego aceleración por gravedad a mi simulación, la velocidad del primer AABB dinámico sigue creciendo incluso cuando descansa sobre el segundo AABB estático. Finalmente, la velocidad será demasiado grande y no se detectará la colisión (el AABB dinámico caerá a través del estático).

Intenté establecer la velocidad a cero después de la resolución, pero obviamente no funcionó bien, y creé simulaciones poco realistas.

Leí en línea que resolver colisiones trabajando manualmente en la posición o la velocidad no es correcta. Intenté implementar fuerzas (la masa es un "codificado" 1 por ahora):

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

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

    acceleration = {0, 0};
}

Si aplico el vector de penetración más corto como fuerza durante la resolución de colisión, el AABB dinámico será "expulsado" del estático, pero su velocidad nunca disminuirá en una simulación sin gravedad y seguirá moviéndose para siempre.

¿Hay alguna forma de aplicar una fuerza "temporal"? ¿Una fuerza que trata de empujar al primer AABB fuera del segundo AABB, y luego se detiene cuando el AABB ya no choca?

Todo el código fuente disponible aquí: https://github.com/SuperV1234/SSVSCollision

Vittorio Romeo
fuente
1
Estoy interesado en esto ¿Ya has encontrado una solución?
TravisG
@TravisG: aún no, desafortunadamente. Agregaré una recompensa mañana si no recibo ninguna respuesta.
Vittorio Romeo
La fuerza no es igual a la aceleración, en primer lugar. Necesitas masa para calcular la aceleración. Si está modificando posiciones para evitar que los dos cuerpos penetren, también debe usar masa y mover ambos cuerpos en función de ella. Aplicar una fuerza igual al vector de penetración no tiene mérito. Box2D está basado en impulsos, funciona directamente en velocidades, puede que no sea "correcto", pero es lo suficientemente bueno. Tratar los cambios de velocidad en un motor basado en impulsos es muy simple, por lo que podría especificar si definitivamente desea una solución basada en la fuerza, o si la solución basada en impulsos es mucho más simple y suficientemente buena.
Dreta
Personalmente, sugeriría tomar un libro sobre motores de física, al menos leer los primeros capítulos sobre física newtoniana. Sus suposiciones son incorrectas y tratar de responder a esta pregunta significaría tener que enseñarle conceptos básicos de física al tratar de explicar algoritmos de alto nivel para resolver colisiones.
Dreta
@dreta sus suposiciones están bien. Señaló que su masa para todos los objetos es simplemente "1" por ahora, lo que hace que sus secciones de código sean válidas. Por cierto, aunque Box2D puede tratar con velocidades directamente, de alguna manera debe tratar con el mismo problema. Si en lugar de aplicar una fuerza, Box2D aplica un impulso, de alguna manera debe lidiar con el hecho de que el impulso no solo desaparece una vez que los objetos se separan. Sin embargo, es posible que de hecho no se ocupe de esto en absoluto y solo permita que los objetos conserven su energía (después de todo, sería así en el mundo real)
TravisG

Respuestas:

13

Primero, recomiendo usar una biblioteca de física gratuita y de código abierto como Box2D y ¡solo enfocarme en los aspectos de tu juego que lo hacen único! Si insiste en reinventar la rueda, siga leyendo ... tenga en cuenta que todos los motores de física son aproximaciones, y aunque el método que describo a continuación será más preciso que su modelo actual, los resultados de Box2D serán mucho más realistas.


Para una forma rápida de modelar una resolución de colisión más precisa de dos objetos A y B:

  1. Encuentra las posiciones justo antes de la colisión. Ya está aproximando esto al: "encontrar el vector de penetración más corto y agregarlo a la posición de AABB".
  2. Encuentre las velocidades justo después de la colisión usando la física newtoniana :
    • Para el caso donde la masa está codificada como 1, simplemente cambie las velocidades (esto no se aplica a los objetos estáticos que deben tener una masa infinita):
      • Av = Bu
      • Bv = Au
    • Si los objetos A y B tienen masas diferentes:
      • Av = (Au * (Am - Bm) + (2 * Bm * Bu)) / (Am + Bm)
      • Bv = (Bu * (Bm - Am) + (2 * Am * Au)) / (Am + Bm)
    • dónde:
      • v: velocidad después de la colisión
      • u: velocidad antes de la colisión
      • m: masa (use el mayor número posible para la masa de un objeto fijo y estático)
  3. Establezca la aceleración en 0: la aceleración de la colisión fue explicada anteriormente por los cálculos de velocidad en el paso número 2.

Eche un vistazo a mi programa de muestra de asteroides que demuestra estos conceptos.


A continuación, tenga en cuenta los objetos apilados:

Como ha notado, usar la velocidad para simular objetos apilados / en reposo no funciona bien: la velocidad es la velocidad a la que se mueve un objeto, por lo que si está descansando sobre un objeto estático, la velocidad debería estar cerca de 0. No tiene sentido aumentar La velocidad de un objeto para que aparezca en reposo:

Si agrego aceleración por gravedad a mi simulación, la velocidad del primer AABB dinámico sigue creciendo incluso cuando descansa sobre el segundo AABB estático. Finalmente, la velocidad será demasiado grande y no se detectará la colisión (el AABB dinámico caerá a través del estático).

Lo que realmente debería suceder es una fuerza de aceleración que vaya en la dirección opuesta, ya que la gravedad debería cancelar la gravedad. (Esto se llama la fuerza de contacto normal). Un atajo es simplemente no aplicar la gravedad a los cuerpos que no están en el aire:

  • Un método para hacer esto es mantener un estado "conectado a tierra":
    • No aplique gravedad a los objetos en un estado conectado a tierra.
    • Si un objeto choca con un objeto desde abajo y su velocidad es muy pequeña, entra en el estado conectado a tierra.
    • Un objeto sale del estado conectado a tierra cuando su velocidad vertical excede un cierto valor positivo.

Actualizar:

  • En términos simples, la física newtoniana dice que la energía total antes y después de una colisión debe coincidir. Cuando dos objetos chocan entre sí, su energía se redistribuye. La energía es una combinación de velocidad y peso: las cosas más pesadas y más rápidas tienen más energía. Eso es intuitivo Sin embargo, lo que no es intuitivo es la forma exacta en que los pesos afectan la redistribución de energía.
  • El intercambio de velocidades es un acceso directo solo para dos cuerpos dinámicos no fijados que tienen la misma masa (los objetos fijos estáticos tienen masas muy grandes e infinitas).
  • El atajo cuando un cuerpo estático es fijo es: el otro cuerpo dinámico y sin fijar mantiene la misma velocidad; solo se cambia el ángulo (imagine una mesa de billar cuando una pelota golpea el riel. El riel tiene esencialmente una masa muy grande e infinita).
  • Para otros casos, como tres o más objetos, se deben resolver las ecuaciones de movimiento newtonianas completas (conservación del momento y conservación de la energía cinética).
  • No estoy seguro de si las ecuaciones newtonianas para el movimiento pueden resolverse para más de dos cuerpos. Afortunadamente, sin embargo, tres objetos casi nunca chocan al mismo tiempo. Es suficiente manejar los dos primeros cuerpos que colisionan, luego manejar las siguientes colisiones usando las nuevas velocidades de las resoluciones de colisión anteriores. Esta es una buena razón para mantener sus pasos de tiempo de física lo más pequeños posible y manejar colisiones antes de que ocurra cualquier penetración.
  • Notarás que en mi demostración de asteroides se crean muchos cuerpos a medida que las rocas más grandes se dividen en otras más pequeñas. Sin embargo, siempre manejo las colisiones entre pares de cuerpos; nunca manejando explícitamente una colisión con más de dos cuerpos.
Leftium
fuente
Gracias por la respuesta detallada. Sin embargo, hay algo que no entiendo: las velocidades de intercambio funcionan bien en una colisión con 2 cuerpos; sin embargo, no veo cómo puede funcionar cuando múltiples cuerpos (y también cuerpos estáticos) chocan todos al mismo tiempo. Incluso sin gravedad, tener un cuerpo dinámico choca al mismo tiempo con un cuerpo estático y otro cuerpo dinámico causa problemas. Dado que la velocidad se intercambia, todo depende del orden de colisión. Si el cuerpo estático choca en último lugar, el cuerpo dejará de moverse. Si el dinámico es, el cuerpo se moverá nuevamente. ¿Cómo se soluciona esto?
Vittorio Romeo
@Vee: ¡Buenas preguntas! Tres cuerpos + y cuerpos estáticos son dos cuestiones separadas. Me dirigí a ambos en una actualización. Resumen: manejar colisiones de dos objetos a la vez; Los cuerpos estáticos tienen una masa muy grande e infinita.
Leftium
Su modelo para descansar contactos es extraño. Los contactos de descanso no son solo por gravedad, deberían funcionar para cualquier fuerza. La forma más fácil que funciona es simplemente eliminar la velocidad obtenida debido a la aceleración en el cuadro anterior al contacto. También para velocidades pequeñas, puede eliminar la restitución por completo, aunque sus cálculos no tienen en cuenta la restitución. Este enfoque funciona para todas las fuerzas, es fácil de implementar y se ve lo suficientemente bien.
Dreta
16

Resolver este problema requiere ajustar la posición y posiblemente la velocidad. Los motores de física de cuerpo rígido tienen un solucionador que hace avanzar los objetos en el tiempo usando las leyes de movimiento de Newton y al mismo tiempo resuelve las restricciones de no penetración y la fricción. Estos motores pueden calcular la combinación correcta de movimiento lineal y angular para crear trayectorias plausibles.

Si solo desea resolver la superposición, puede usar pseudovelocidades que generan trayectorias de separación sin agregar impulso. Esto se hace en el solucionador de posición de Box2D.

Recomiendo obtener mis presentaciones de GDC de 2006 y 2007 aquí:

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

Además, puede mirar Box2D Lite para una implementación simplificada.

Erin Catto
fuente
+1 para la observación de que es necesario ajustar también la posición. Pocas personas se dan el gusto, pero para aumentar la estabilidad de la simulación, la mayoría de los motores hacen trampa ajustando las posiciones directamente. Con todo, si es plausible, funciona para juegos.
teodron
Gracias por la respuesta. Quería saber algo que probablemente me perdí en la presentación: ¿los cuerpos estáticos se manejan de manera especial en Box2D? Quiero decir, ¿qué sucede cuando un cuerpo dinámico golpea un cuerpo estático?
Vittorio Romeo
2

ingrese la descripción de la imagen aquí

En el mundo real, no hay fuerza que "empuje" un cuerpo fuera de otro porque los objetos nunca se penetran entre sí. Lo más cercano es la fuerza normal : creada en el momento del contacto en colisiones del mundo real, evita la penetración en primer lugar.

El ángulo de esta fuerza normal es perpendicular a la superficie de contacto de los dos objetos que chocan. La magnitud depende de cuánta fuerza se necesita para evitar la penetración. (Tenga en cuenta que solo se debe usar el componente y de la fuerza normal a menos que también se modelen otras fuerzas como la fuerza de fricción).

Si bien es posible modelar explícitamente la fuerza normal, es más sencillo modelar solo sus efectos:

  1. Evite la intersección de objetos por:
    • Ajuste de velocidades resolviendo colisiones en el momento del impacto. (mejor)
    • Ajuste manual de las posiciones de los cuerpos para que no se crucen. (más fácil) Ya está haciendo esto "al encontrar el vector de penetración más corto y agregarlo a la posición de AABB".
  2. No aplique la gravedad donde haya una fuerza normal que cancele la fuerza de la gravedad.
    • Un objeto en contacto con otro objeto debajo está sujeto a la fuerza normal. Por lo tanto, se trata de hacer un seguimiento de esos objetos. (En realidad, cualquier objeto que esté en contacto debe tener una fuerza normal aplicada, pero no todos tendrán un efecto neto con respecto a la gravedad).
    • Si desea agregar objetos que puedan deslizarse hacia abajo sobre otros objetos que están en ángulo, deberá agregar la fuerza de fricción y el componente x de la fuerza normal.

Describí esto de manera ligeramente diferente en mi otra respuesta, que es más sobre colisiones en general .

Leftium
fuente