J'essaie d'écrire du code pour transférer des animations conçues pour qu'un squelette ait l'air correct sur un autre squelette. Les animations source sont constituées uniquement de rotations, à l'exception des traductions à la racine (ce sont les animations mocap de la base de données de capture de mouvement CMU ). De nombreuses applications 3D (par exemple Maya) ont cette fonctionnalité intégrée, mais j'essaie d'en écrire une version (très simple) pour mon jeu.
J'ai fait un peu de travail sur la cartographie osseuse, et parce que les squelettes sont hiérarchiquement similaires (bipèdes), je peux faire une cartographie osseuse 1: 1 pour tout sauf la colonne vertébrale (peut travailler dessus plus tard). Le problème, cependant, est que les poses de base squelette / liaison sont différentes, et les os ont des échelles différentes (plus courtes / plus longues), donc si je copie la rotation directement, cela semble très étrange.
J'ai essayé un certain nombre de choses similaires à la solution de lorancou ci-dessous en vain (c'est-à-dire en multipliant chaque image de l'animation par un multiplicateur spécifique à l'os). Si quelqu'un a des ressources sur des trucs comme ça (papiers, code source, etc.), ce serait vraiment utile.
la source
Réponses:
Le problème était un problème de stabilité numérique. Environ 30 heures de travail sur cela en 2 mois, seulement pour comprendre que je le faisais dès le début. Lorsque j'ai ortho-normalisé les matrices de rotation avant de les brancher dans le code de reciblage, la solution simple de multiplier source * inverse (cible) fonctionnait parfaitement. Bien sûr, le reciblage est bien plus que cela (en particulier, en tenant compte des différentes formes du squelette, c'est-à-dire la largeur des épaules, etc.). Voici le code que j'utilise pour l'approche simple et naieve, si quelqu'un est curieux:
la source
Je crois que votre option la plus simple est simplement de faire correspondre la pose de liaison d'origine avec votre nouveau squelette si vous en avez la possibilité (si votre nouveau squelette n'est pas encore skinné).
Si vous ne pouvez pas faire cela, voici quelque chose que vous pouvez essayer. Ce n'est qu'une intuition, j'oublie probablement beaucoup de choses, mais cela pourrait vous aider à trouver la lumière. Pour chaque os:
Dans votre "ancienne" pose de reliure, vous avez un quaternion qui décrit la rotation relative de cet os par rapport à son os parent . Voici un indice pour savoir comment le trouver. Appelons ça
q_old
.Ibid. pour votre "nouvelle" pose de reliure, appelons-la
q_new
.Vous pouvez trouver la rotation relative de la "nouvelle" pose de liaison à la "vieille" pose de bin, comme décrit ici . Voilà
q_new_to_old = inverse(q_new) * q_old
.Ensuite, dans une clé d'animation, vous avez votre seul quaternion qui transforme cet os de la "vieille" pose de liaison en une pose animée. Appelons celui-ci
q_anim
.Au lieu d'utiliser
q_anim
directement, essayez d'utiliserq_new_to_old * q_anim
. Cela devrait "annuler" les différences d'orientation entre les poses de reliure, avant d'appliquer l'animation.Cela pourrait faire l'affaire.
MODIFIER
Votre code ci-dessus semble suivre la logique que je décris ici, mais quelque chose est inversé. Au lieu de faire ceci:
Vous pouvez essayer ça:
Je pense que vous devez passer de votre cible à votre source avant d'appliquer l'animation source, pour obtenir la même orientation finale.
la source