La detección de colisiones es la aplicación de los campos de distancia con signo más natural en el desarrollo de videojuegos. El campo que describe una forma para el renderizado también la describe para las consultas de contacto: evalúa el SDF en cualquier punto y obtienes dos respuestas a la vez, qué tan lejos está el punto de la superficie y en qué lado se encuentra. Este artículo cubre los tres tipos de consulta que los motores de física construyen sobre ese contrato (contención de puntos, profundidad de penetración con dirección de separación y sphere casting para detección de colisiones continua), con el código GLSL, ejemplos prácticos, casos límite y la comparación de rendimiento con los enfoques basados en mallas.
Para la visión general de los SDF en todo el motor, consulta los SDF en el desarrollo de videojuegos . Si necesitas repasar la convención de signos o el concepto de gradiente, la visión general de los Campos de Distancia con Signo construye ambos desde los primeros principios.
El Contrato de Consulta
Tres hechos sobre un SDF convierten cada consulta de colisión de abajo en una expresión puramente aritmética:
- Signo: significa dentro, significa fuera, significa en la superficie.
- Magnitud: es la distancia a la superficie más cercana, exacta para SDF analíticos, aproximada para los muestreados.
- Gradiente: apunta en dirección opuesta a la superficie más cercana, así que en el límite es la normal hacia afuera.
Ninguno de estos requiere recorrer un árbol ni probar pares de triángulos. El costo de una consulta es el costo de evaluar la expresión del campo.
Consultas de Punto en Volumen
La pregunta de colisión más simple es si un punto se encuentra dentro de un volumen. Con un SDF, la respuesta es una sola verificación de signo:
bool isInside(vec3 point, SDF volume) {
return evaluateSDF(point, volume) < 0.0;
}
Esa línea de una sola instrucción reemplaza lo que de otro modo sería una prueba de punto en malla que requiere ray casting o cálculo de número de enrollamiento. Para un SDF de esfera, la evaluación de distancia cuesta una resta de vectores y un cálculo de longitud. Para un árbol CSG complejo construido con docenas de primitivas, el costo escala con la profundidad del árbol, pero sigue siendo una expresión puramente aritmética sin estructura de búsqueda con ramificaciones.
Un ejemplo práctico hace concreta la aritmética. Considera un SDF de esfera centrado en el origen con radio 2:
Prueba el punto . Su distancia al centro es . El valor del SDF es , así que el punto está dentro, y se encuentra 0.882 unidades por debajo de la superficie. La misma consulta contra una malla de triángulos necesitaría encontrar el triángulo más cercano y calcular el punto más próximo sobre él, una operación mucho más costosa para la misma respuesta.
Profundidad de Penetración y Dirección de Separación
Una respuesta binaria dentro/fuera rara vez es suficiente para un motor de física. Cuando dos objetos se superponen, el solucionador necesita saber qué tan profundamente se interpenetran y en qué dirección separarlos. El SDF proporciona ambas cosas.
Para un punto dentro de un volumen, la profundidad de penetración es y la dirección de separación es el gradiente normalizado que apunta hacia la superficie. Juntos forman el vector de traslación mínima : mueve el punto por ese vector y aterriza exactamente en la superficie.
Continuando con el ejemplo de la esfera, el punto tiene profundidad 0.882 y dirección de gradiente . Empujar el punto 0.882 unidades en esa dirección da , cuya distancia al origen es , exactamente el radio. La aritmética cuadra: una sola consulta produjo tanto la cantidad de superposición como la corrección.
En la práctica, muestreas el SDF en cada vértice del objeto penetrante y tomas la penetración más profunda:
struct PenetrationResult {
float depth;
vec3 direction;
vec3 contactPoint;
};
PenetrationResult computePenetration(MeshVolume mesh, SDF volume) {
PenetrationResult result;
result.depth = 0.0;
for (int i = 0; i < mesh.vertexCount; i++) {
vec3 p = mesh.vertices[i];
float d = evaluateSDF(p, volume);
if (d < result.depth) {
result.depth = d;
result.direction = normalize(gradientSDF(p, volume));
result.contactPoint = p;
}
}
return result;
}
Debido a que el gradiente del SDF apunta hacia afuera desde la superficie, la dirección de separación empuja naturalmente el punto penetrante hacia el límite más cercano.
Los casos límite son donde el enfoque requiere cuidado. Para volúmenes convexos definidos por SDF exactos, el vértice de penetración más profunda siempre apunta hacia la dirección de separación correcta. Para SDF no convexos o muestreados, el muestreo solo de vértices puede pasar por alto penetraciones delgadas: una caja puede interpenetrar una superficie no convexa a través de un borde o una cara sin que ninguno de sus vértices cruce el límite. Por lo tanto, un solucionador de producción añade muestreo borde-borde y cara-vértice, y para campos muestreados trata la distancia interpolada como aproximada, apoyándose en un pequeño margen de seguridad para que el solucionador no vibre con valores ruidosos. Muestrear puntos adicionales multiplica el costo de la consulta, razón por la cual la propiedad de tiempo constante por evaluación importa tanto: puedes permitirte varias muestras por objeto cuando cada muestra es una búsqueda en la rejilla.
Sphere Casting para Detección de Colisiones Continua
Los objetos que se mueven rápido pueden atravesar geometría delgada entre fotogramas cuando se usan verificaciones de colisión discretas. Una bala que se mueve 50 unidades por fotograma contra una pared de 0.1 unidades de grosor puede estar a un lado al inicio del fotograma y al otro al final, sin que ninguna prueba discreta vea la superposición. La solución estándar es la detección de colisiones continua (CCD), que barre un volumen a lo largo de la trayectoria del movimiento y encuentra el tiempo de impacto más temprano.
Con un SDF, puedes implementar CCD usando sphere casting. La idea es avanzar un punto a lo largo del vector de movimiento usando el campo de distancia como tamaño de paso, exactamente como el sphere tracing pero a lo largo de un vector de desplazamiento en lugar de un rayo de visión:
float sphereCast(vec3 origin, vec3 direction, float maxDist, float radius,
SDF volume) {
float t = 0.0;
for (int i = 0; i < MAX_STEPS; i++) {
vec3 p = origin + direction * t;
float d = evaluateSDF(p, volume) - radius;
if (d < EPSILON) return t; // Hit
t += d;
if (t > maxDist) break; // No hit within the motion segment
}
return -1.0; // No hit
}
Quien llama pasa la longitud del desplazamiento del fotograma como maxDist y una dirección de movimiento unitaria como direction. El t devuelto es la distancia de impacto a lo largo de esa dirección, y t / maxDist es el tiempo del primer contacto como una fracción del movimiento del fotograma, que el motor de física usa para detener el objeto exactamente en la superficie de colisión.
Dos detalles importan. Restar el radio del objeto en movimiento del valor del campo encoge la forma contra la que se barre: el cast trata la superficie del mundo como si hubiera sido inflada por el radio del proyectil, que es exactamente la superficie con la que colisiona el punto central del proyectil. Y la garantía de paso se mantiene porque el SDF nunca sobreestima la distancia, así que ningún paso puede saltar por encima de una superficie.
Un ejemplo práctico: un proyectil de radio 0.25 comienza en y se mueve en la dirección hacia una esfera de radio 1 centrada en el origen, con maxDist = 4. En , el valor del campo es , así que el cast avanza hasta . En esa posición, , el valor es , y el cast informa un impacto en . La respuesta analítica es , así que el cast encontró el primer contacto exactamente, en un solo paso.
Los casos límite del sphere casting reflejan los del sphere tracing. Si el campo es un SDF muestreado o suavizado que solo aproxima la garantía de distancia, el avance puede sobrepasar características delgadas, así que o bien mantienes un épsilon conservador, limitas el número de pasos, o recurres a una prueba discreta cuando el cast no informa ningún impacto. Los objetos que comienzan el fotograma ya interpenetrados (el valor del campo es negativo en el origen) devuelven un impacto inmediato en , que el motor debe tratar como una superposición a resolver, no como un evento de colisión nuevo.
Casts de Rayos y Cápsulas
El sphere casting se generaliza a otras formas barridas. Un ray cast es un sphere cast con radio cero, útil para verificaciones de línea de visión y hitscan de armas. Un capsule cast reemplaza el avance desde un origen puntual con un segmento que mantiene una distancia fija de una línea, lo que requiere muestrear el SDF en los extremos del segmento y tomar el mínimo, o usar un SDF de cápsula directamente para el volumen barrido. El mismo bucle de paso seguro funciona en todos los casos; solo cambia la consulta de distancia dentro del bucle. Esta uniformidad es una ventaja práctica: un bucle de cast, muchos tipos de consulta, sin estructuras de colisión nuevas.
Perfil de Rendimiento
Las consultas de colisión con SDF escalan de manera diferente a los enfoques tradicionales. Una prueba de colisión malla contra malla requiere recorrer jerarquías de volúmenes envolventes para ambos objetos y probar pares de triángulos. Una prueba SDF contra malla reemplaza una jerarquía con una evaluación de distancia en tiempo constante por vértice de la otra forma.
Esto hace que los SDF sean especialmente fuertes en escenarios donde una forma es simple y la otra compleja, o donde muchos objetos necesitan consultas de colisión contra el mismo entorno estático. Muchos juegos hornean campos de distancia para la geometría estática del nivel y los consultan en tiempo de ejecución contra cientos de objetos dinámicos. El costo de horneado se paga una vez en tiempo de compilación; el costo en tiempo de ejecución es un puñado de búsquedas en la rejilla por consulta. Cuando el entorno es estático, el campo nunca necesita actualizarse. Cuando cambia, reconstruir o actualizar localmente el campo horneado es una preocupación de canalización aparte, cubierta en los campos de distancia con signo horneados .
Los SDF no son la herramienta adecuada para cada par de colisiones. Dos mallas dinámicas densas que chocan entre sí siguen siendo más baratas como malla contra malla, porque evaluar un campo muestreado para ambas formas todavía cuesta búsquedas en la rejilla e interpolación mientras que el camino de la malla usa hardware de función fija. El punto óptimo es una forma fija y con muchas consultas (el nivel) contra muchas formas dinámicas baratas (proyectiles, personajes, vehículos).
Resumen
El contrato de los SDF convierte las tres consultas de colisión de caballo de batalla en aritmética:
- Contención es una verificación de signo.
- Profundidad de penetración y dirección de separación son la magnitud y el gradiente en el punto muestreado más profundo, combinados en un vector de traslación mínima.
- Detección de colisiones continua es un sphere cast con la misma garantía de paso seguro que el sphere tracing, usando el valor del campo menos el radio en movimiento como tamaño de paso.
La misma matemática de gradiente y penetración alimenta el siguiente subsistema del motor: la respuesta de colisión de partículas y los campos de fuerza resuelven exactamente estas superposiciones a escala de partícula individual.