¿Por qué OnCollisionEnter de Unity no me da normales de superficie y cuál es la forma más confiable de obtenerlas?

11

El evento Unity's on collision le proporciona un objeto Collision que le brinda información sobre la colisión que ocurrió (incluida una lista de ContactPoints con normales de hit).

Pero lo que no obtienes son normales de superficie para el colisionador que golpeas. Aquí hay una captura de pantalla para ilustrar. La línea roja es de ContactPoint.normaly la línea azul es de RaycastHit.normal.

ingrese la descripción de la imagen aquí

¿Es esta una instancia de Unity que oculta información para proporcionar una API simplificada? ¿O las técnicas estándar de detección de colisiones en 3D en tiempo real simplemente no recopilan esta información?

Y para la segunda parte de la pregunta, ¿cuál es una forma segura y relativamente eficiente de obtener una superficie normal para una colisión?

Sé que la emisión de rayos le da normales de superficie, pero parece que necesito hacer varias transmisiones de rayos para lograr esto en todos los escenarios (tal vez un punto de contacto / combinación normal pierde el colisionador en el primer lanzamiento, o tal vez necesite hacer un promedio de todos las normales de los puntos de contacto para obtener el mejor resultado).

Mi método actual:

  1. Copia de seguridad a lo Collision.contacts[0].pointlargo de su golpe normal

  2. Raycast por el golpe negado normal para float.MaxValue, enCollision.collider

  3. Si eso falla, repita los pasos 1 y 2 con la normalidad no negada

  4. Si eso falla, intente los pasos 1 a 3 con Collision.contacts[1]

  5. Repita 4 hasta que tenga éxito o hasta que se agoten todos los puntos de contacto.

  6. Ríndete, vuelve Vector3.zero.

Esto parece captar todo, pero todas esas emisiones de rayos me marean, y no estoy seguro de cómo probar que esto funciona para suficientes casos. ¿Hay una mejor manera?

EDITAR Si esto es así como están las cosas con la colisión 3D, una descripción general de por qué en el caso general sería tan bienvenida como algo específico de Unity.

michael.bartnett
fuente
¿Es solo por curiosidad, o estás tratando de hacer algo y te estás atascando? Es decir, ¿por qué crees que necesitas la superficie normal? Haga una pregunta sobre qué efecto está tratando de lograr, en lugar de cómo "solucionar" una solución a un problema no especificado, y alguien podría ayudarlo a resolverlo. :)
Sean Middleditch
@SeanMiddleditch No estoy de acuerdo. La pregunta está bien planteada y es exactamente lo que estaba buscando. Esta pregunta y sus respuestas me ayudaron a corregir algunas cosas que estaba haciendo mal.
SteakOverflow

Respuestas:

12

Esto realmente es así como son las cosas con la colisión. No solo en 3D, sino también en 2D. Tome el siguiente ejemplo:

AABB superpuestos

Los AABB verdes y rojos están colisionando, y el múltiple de contacto es el área azul. Los puntos de contacto estarán en el área azul en algún lugar (exactamente donde puede variar con el algoritmo, pero las esquinas donde se encuentra el azul / rojo / verde son ideales).

¿Qué superficie normal se debe devolver? ¿El borde superior del AABB rojo o el borde izquierdo? Si el cuadro verde se está cayendo, tal vez podamos adivinar razonablemente el borde superior. si se mueve hacia la derecha, tal vez podamos adivinar razonablemente el borde izquierdo. ¿Qué pasa si se mueve hacia abajo y hacia la derecha? ¿Tomamos el eje de menor penetración? ¿El eje de velocidad de mayor velocidad? ¿Alguna heurística de ambos? ¿Qué pasaría si las cajas hubieran chocado exactamente en las esquinas?

Extienda esto a una superficie 3D compleja compuesta potencialmente por cientos de tris / caras. Todavía solo tendrá una pequeña cantidad de puntos de contacto ideales. ¿Qué superficie normal se debe devolver? ¿La superficie promedio normal sobre toda la malla triple (que no tiene sentido para la mayoría de los objetos)? ¿Los puntos directamente "debajo" de las esquinas del cuadro de colisión (que no están bien definidos para la mayoría de las otras formas)? ¿Intenta encontrar la cara más cercana a los puntos de contacto generados (lo que requeriría una segunda pasada, ya que los puntos de contacto no se calculan directamente a partir de ninguna cara de malla)? Si encuentra la cara más cercana, ¿toma la cara normal o interpola los vértices de la cara en el punto de contacto para obtener la normal correcta para los objetos "lisos"?

Realmente, el problema principal es que los puntos de contacto no son todos los puntos de contacto. En muchos casos, eso sería un conjunto infinito de puntos, después de todo. Son solo unos pocos puntos que se distribuyen bien y hacen que sea razonablemente posible aproximar la reacción física aplicando fuerzas en dichos puntos para empujar los objetos que colisionan de una manera razonable. Los puntos / ubicaciones específicos del contacto real con el objeto se abstraen detrás de un modelo matemático simplificado. Por lo tanto, la idea de una superficie específica normal de contacto simplemente no tiene mucho sentido en el caso general.

Por supuesto, con restricciones y limitaciones más específicas en sus objetos, mundo y movimiento, puede crear algoritmos de colisión alternativos que pueden informarle sobre la superficie normal. En el caso 2D anterior, si suponemos que las cajas nunca giran y que conocemos la velocidad relativa y la última posición de cada una, podríamos usar la detección de colisión continua para averiguar exactamente cuándo colisionarían y qué características colisionaron, proporcionándonos el característica exacta donde ocurrió la colisión, que luego podría usarse como contacto / colisión / superficie normal. Los juegos de plataformas se basan completamente en supuestos y trucos especiales (razón por la cual usar una biblioteca de física general como Box2D o Havok o la luz nunca produce el tipo de control estricto y preciso que se encuentra en plataformas clásicas como Mario o Sonic; no lo haría quiero decirlo

Las bibliotecas generales de física newtoniana, como la utilizada en Unity3D, no pueden hacer ese tipo de simplificaciones y suposiciones. Por lo tanto, no obtienes normales de superficie de colisión, obtienes un colector de contacto, generalmente simplificado hasta los puntos de contacto, y eso es todo.

Sean Middleditch
fuente
Esta es una respuesta fantástica, y exactamente lo que estaba buscando, gracias. El problema específico era obtener un vector de reflexión convincente en un cuerpo rígido cinemático en colisión. ¿Es el enfoque habitual si desea que este tipo de información elija si desea emitir por rayos o tomar 3 puntos de contacto (si están disponibles) y tomar el producto cruzado?
michael.bartnett