Comment animer dynamiquement une partie d'un modèle 3D vers quelque chose


8

Je suis curieux de savoir comment ce type d'animation se fait généralement au niveau du code.

Quelques exemples:

  • Un personnage ramasse quelque chose - seule la main est animée vers la cible http://www.youtube.com/watch?v=rW-7uatehx4 voir à partir de 4:50 quand le joueur ramasse l'arme.
  • Le personnage se bloque sur un rebord - les mains sont placées à un emplacement spécifique (le rebord) http://www.youtube.com/watch?v=SOiwArn4Bmw dès le début.
  • Le personnage regarde quelque chose - la tête est dirigée vers la cible (le PNJ regarde le PC)

Réponses:


4

C'est ce qu'on appelle la cinématique inverse. Google est probablement votre meilleur ami sur celui-ci car il peut devenir complexe.


Je comprends, je dois calculer les mouvements nécessaires pour atteindre la position souhaitée. Dans ce cas, je calculerais uniquement les mouvements de l'os souhaité.
Gerstmann

En effet, la description de la vidéo dit "... un système d'animation basé entièrement sur la cinématique inverse ..."
MichaelHouse

0

Article d'origine: comment coder un système IK

Parfois, le CI intégré à Unity ne suffit pas. Je vais vous montrer comment créer votre propre script IK pour Unity. Vous pouvez appliquer ce CI à n'importe quel corps articulé - doigts, mains ou pieds. L'IK que je vais examiner est actuellement utilisé par Unity, Unreal, Panda et plusieurs autres moteurs de jeu. Il s'appelle FABRIK.

FABRIK est une méthode itérative. Une méthode itérative est une méthode qui n'obtient pas immédiatement la solution. Une méthode itérative se rapproche de plus en plus de la bonne solution avec plus d'itérations de la méthode - en d'autres termes, les itérations d'une boucle.

Tout problème IK a un corps articulé donné (un ensemble de membres connectés avec des longueurs et des angles). L'effecteur final (la position du point final du membre final) a une position de départ avec une position de but. Il pourrait avoir d'autres objectifs, tels que des angles.

Chaque itération FABRIK comprend deux parties principales.

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

La première partie itère du membre final au membre racine. Pour le membre final, vous devez changer l'angle / rotation du membre pour pointer vers la position de but (en gardant la position intérieure ancrée et en laissant la position extérieure être traduite par le changement d'angle). Ensuite, vous translatez le membre final le long de l'angle mis à jour vers la position de but, jusqu'à ce que la position extérieure du membre soit égale à la position de but (en maintenant l'angle, mais en laissant la position intérieure du membre changer). C'est à peu près tout pour le dernier membre, sauf que vous devez maintenant mettre à jour la position actuelle de l'objectif. La position actuelle de l'objectif est désormais définie sur la position intérieure mise à jour du membre final.

Pour chaque membre inboard consécutif, vous faites la même chose. Pour être clair, je vais le décrire. Pour le membre actuel, vous devez modifier l'angle / la rotation du membre pour pointer vers la position actuelle du but. Ensuite, vous traduisez le membre actuel le long de l'angle mis à jour vers la position de but actuelle, jusqu'à ce que la position extérieure du membre soit égale à la position de but actuelle. Enfin, vous mettez à jour la position actuelle de l'objectif pour qu'elle soit égale à la position intérieure mise à jour du membre actuel.

Répétez ces opérations jusqu'à ce que vous ayez terminé ces opérations sur le membre racine. Après cela, la première partie est terminée.

/* 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 deuxième partie itère en sens inverse: du membre racine au membre final. Pour le membre racine, vous devez mettre à jour sa position intérieure vers la position racine. Cela devrait traduire l'ensemble du membre (sans étirement). C'est à peu près tout pour le membre racine, sauf que vous devez maintenant mettre à jour la position intérieure actuelle. La position intérieure actuelle est désormais définie sur la position extérieure mise à jour du membre racine. Pour chaque membre extérieur consécutif, vous faites la même chose. Pour être clair, je vais le décrire. Pour le membre actuel, vous devez mettre à jour sa position intérieure vers la position intérieure actuelle. Cela devrait traduire l'ensemble du membre. C'est à peu près tout pour le membre actuel, sauf que vous devez maintenant mettre à jour la position intérieure actuelle. La position intérieure actuelle est désormais définie sur la position extérieure mise à jour du membre actuel.

Répétez ces opérations jusqu'à ce que vous ayez terminé ces opérations sur le dernier membre. Après cela, la deuxième partie est terminée.

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

Une fois la première partie et la deuxième partie terminées, vous avez terminé la première itération de la méthode FABRIK. Continuez à itérer sur les première et deuxième parties jusqu'à ce que l'effecteur terminal soit aussi proche que vous le souhaitez de la position cible, définie par un EPS (valeur epsilon).

C'est ça! C'est la méthode FABRIK. La première partie parcourt en arrière à partir du dernier membre. La deuxième partie se répète à partir du membre racine. La méthode FABRIK itère la première et la deuxième partie jusqu'à ce que l'effecteur terminal soit suffisamment proche de la position cible.

En utilisant notre site, vous reconnaissez avoir lu et compris notre politique liée aux cookies et notre politique de confidentialité.
Licensed under cc by-sa 3.0 with attribution required.