Cómo animar dinámicamente una parte de un model 3D hacia algo

Tengo curiosidad acerca de cómo este tipo de animation normalmente se realiza en código.

Algunos ejemplos:

  • Un personaje recoge algo: solo la mano está animada hacia el objective http://www.youtube.com/watch?v=rW-7uatehx4. Ve a partir de 4:50 cuando el jugador coge el arma.
  • El carácter se cuelga de una repisa: las manos se establecen en una location específica (la repisa) http://www.youtube.com/watch?v=SOiwArn4Bmw al principio.
  • El personaje mira algo: la cabeza apunta al objective (npc mira la pc)

Esto se llama cinemática inversa. Google es probablemente tu mejor amigo en este caso, ya que puede volverse complejo.

Artículo original: Cómo codificar un sistema IK

A veces, el IK que está integrado en la Unidad no es suficiente. Voy a mostrarte cómo build tu propio script IK para Unity. Puede aplicar este IK a cualquier cuerpo articulado: dedos, manos o pies. El IK que voy a revisar es utilizado actualmente por Unity, Unreal, Panda y varios otros motores de juego. Se llama FABRIK.

FABRIK es un método iterativo. Un método iterativo es un método que no obtiene la solución de inmediato. Un método iterativo se acerca cada vez más a la solución correcta con más iteraciones del método, en otras palabras, iteraciones de un ciclo.

Cualquier problema IK tiene un cuerpo articulado determinado (un set de extremidades conectadas con longitudes y angularjs). El efector final (la position del punto final de la extremidad final) tiene una position de inicio con una position de objective. Puede tener otros objectives, como angularjs.

Cada iteración de FABRIK tiene dos partes principales.

void FABRIK() { while( abs(endEffectorPosition — goalPosition) > EPS ) { FinalToRoot(); // PartOne RootToFinal(); // PartTwo } } 

La primera parte itera desde la extremidad final hasta la raíz del miembro. Para la extremidad final, debe cambiar el ángulo / rotation de la extremidad para apuntar a la position de la meta (manteniendo la position interna anclada, y dejando que la position del fueraborda se traduzca por el cambio de ángulo). Luego, traduce la extremidad final a lo largo del ángulo actualizado hacia la position de la meta, hasta que la position exterior del miembro sea igual a la position de la portería (manteniendo el ángulo, pero dejando que la position interna del miembro cambie). Eso es más o less para la extremidad final, excepto que ahora necesita actualizar la position actual del objective. La position del objective actual ahora se establece en la position interna actualizada de la extremidad final.

Para cada extremidad interna consecutiva, haces lo mismo. Para ser claro lo resumiré. Para la extremidad actual, debe cambiar el ángulo / rotation de la extremidad para apuntar hacia la position de la meta actual. Luego, traduce la extremidad actual a lo largo del ángulo actualizado hacia la position actual del objective, hasta que la position exterior del miembro sea igual a la position actual del objective. Finalmente, actualiza la position del objective actual para que sea igual a la position interna actualizada de la extremidad actual.

Repita estas operaciones hasta que haya completado estas operaciones en la twig raíz. Después de eso, la primera parte ha sido completada.

 /* Part One */ void FinalToRoot() { currentGoal = goalPosition; currentLimb = finalLimb; while (currentLimb != NULL) { currentLimb.rotation = RotFromTo(Vector.UP, currentGoal — currentLimb.inboardPosition); currentGoal = currentLimb.inboardPosition; currentLimb = currentLimb->inboardLimb; } } 

La segunda parte itera en la dirección inversa: desde la raíz hasta la extremidad final. Para la raíz del miembro, debe actualizar su position interna a la position raíz. Esto debería traducir todo el miembro (sin estirar). Eso es más o less para la raíz del miembro, excepto que ahora necesita actualizar la position interna actual. La position interna actual está ahora configurada en la position fuera de borda actualizada de la twig raíz. Para cada miembro externo consecutivo, haces lo mismo. Para ser claro lo resumiré. Para la extremidad actual, debe actualizar su position interna a la position interna actual. Esto debería traducir todo el miembro. Eso es más o less para la extremidad actual, excepto que ahora necesita actualizar la position interna actual. La position interna actual está ahora configurada en la position fuera de borda actualizada de la extremidad actual.

Repita estas operaciones hasta que haya completado estas operaciones en la extremidad final. Después de eso, la segunda parte ha sido completada.

 /* Part Two */ void RootToFinal() { currentInboardPosition = rootLimb.inboardPosition; currentLimb = rootLimb; while (currentLimb != NULL) { currentLimb.inboardPosition = currentInboardPosition; currentInboardPosition = currentLimb.outboardPosition; currentLimb = currentLimb->inboardLimb; } } 

Una vez que se hayan completado la primera parte y la segunda parte, habrá completado la primera iteración del método FABRIK. Continúe iterando en la parte uno y dos hasta que el efector final esté lo más cerca posible de la position del objective, definida por algún EPS (valor épsilon).

¡Eso es! Ese es el método FABRIK. La Parte Uno itera hacia atrás desde la extremidad final. La Parte Dos itera hacia adelante desde la raíz del miembro. El método FABRIK itera la Parte Uno y la Parte Dos hasta que el efector final esté lo suficientemente cerca de la position del objective.