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

8

Tengo curiosidad acerca de cómo este tipo de animación generalmente se realiza en código.

Algunos ejemplos:

Gerstmann
fuente

Respuestas:

4

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

n3XusSLO
fuente
Lo entiendo, tengo que calcular los movimientos necesarios para lograr la posición deseada. En este caso, solo calcularía los movimientos para el hueso deseado.
Gerstmann
De hecho, la descripción del video dice "... un sistema de animación basado completamente en cinemática inversa ..."
MichaelHouse
0

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

A veces, el IK que está integrado en Unity no es suficiente. Te mostraré cómo crear 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 juegos. 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 bucle.

Cualquier problema de IK tiene un cuerpo articulado dado (un conjunto de extremidades conectadas con longitudes y ángulos). El efector final (la posición del punto final de la extremidad final) tiene una posición inicial con una posición de gol. Puede tener otros objetivos, como ángulos.

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 extremidad raíz. Para la extremidad final, debe cambiar el ángulo / rotación de la extremidad para apuntar a la posición de meta (manteniendo la posición interna anclada y dejando que la posición externa se traduzca por el cambio de ángulo). Luego, traslada la extremidad final a lo largo del ángulo actualizado hacia la posición de meta, hasta que la posición externa de la extremidad sea igual a la posición de meta (manteniendo el ángulo, pero dejando que cambie la posición interna de la extremidad). Eso es más o menos para la extremidad final, excepto que ahora necesita actualizar la posición del objetivo actual. La posición de meta actual ahora se establece en la posición interna actualizada de la extremidad final.

Por cada miembro interno consecutivo, haces lo mismo. Para que quede claro, lo resumiré. Para la extremidad actual, debe cambiar el ángulo / rotación de la extremidad para apuntar hacia la posición de meta actual. Luego, traslada la extremidad actual a lo largo del ángulo actualizado hacia la posición de meta actual, hasta que la posición externa de la extremidad sea igual a la posición de meta actual. Finalmente, actualiza la posición del objetivo actual para que sea igual a la posición interna actualizada de la extremidad actual.

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

/* 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 extremidad raíz hasta la extremidad final. Para la extremidad raíz, debe actualizar su posición interna a la posición raíz. Esto debería traducir toda la extremidad (sin estirar). Eso es más o menos para la extremidad raíz, excepto que ahora necesita actualizar la posición interna actual. La posición interna actual ahora está configurada en la posición externa actualizada de la rama raíz. Por cada miembro externo consecutivo, haces lo mismo. Para que quede claro, lo resumiré. Para la extremidad actual, debe actualizar su posición interna a la posición interna actual. Esto debería traducir toda la extremidad. Eso es más o menos para la extremidad actual, excepto que ahora necesita actualizar la posición interna actual. La posición interna actual se establece ahora en la posición externa 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 se ha completado.

/* 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 han completado la primera parte y la segunda parte, ha completado la primera iteración del método FABRIK. Continúe iterando en las partes uno y dos hasta que el efector final esté lo más cerca posible de la posición objetivo, definida por algunos EPS (valor de epsilon).

¡Eso es! Ese es el método FABRIK. La primera parte itera hacia atrás desde la extremidad final. La segunda parte itera hacia adelante desde la raíz. El método FABRIK itera la Parte Uno y la Parte Dos hasta que el efector final esté lo suficientemente cerca de la posición del objetivo.

Luis B
fuente