PDA

Voir la version complète : Rotation Parenting



clemz
04/01/2010, 13h39
bonjour ..et HEEEELLLLLLLlllppppppp :cry2:

j'ai un problême que j'arrive pas à tracker :

j'ai 2 hiérarchies d'objets ( en fait une chaine d'os animés ( fichier moccap importé ) et une chaine de joint libre à coté ) , avec même nombre d'éléments dans chaque .

je voudrais pouvoir appliquer les rotations/animations de la chaine d'os , à ma chaine de joints , mais en mode relatif :
c'est à dire que je calle grosso modo mon squelette de joint par dessus la chaine d'os animés , et là je ' verrouille ' les offsets qu'il peut y avoir ( car les joints et les os ne sont peut-être pas orientés pareil ) et je veux que les joints subissent les mêmes animations en rotation que les os , par dessus leur rotation d'édition initiale là .

par ex avec le 1er élément de chaque chaine , on va imaginer que le premier joint a un décallage en P de 35° par rapport au 1er os ..donc je veux que le joint ait la même animation que l'os , mais avec ce décallage en P de 35° sur toute l'animation .

donc ce que j'ai fais :
-jai une liste de liens DU où je mets le début de chaque chaine ( chaine Spinale moccap , chaine jambeD moccap , chaine jambeG moccap , chaine brasD moccap et chaine brasG moccap ) ..j'ai la même liste de liens DU pour le squelette de joint .

-j'ai un bouton bouléen Edition/Verrouillage : qui me permet de placer mon squelette de joints par dessus le squelette d'os moccap , grosso modo

-une fois le squelette de joints placé à peu près sur le squelette d'os , je passe ce bouton bouléen en mode vérrouillage . ce qui a pour effet de stocker dans un container ( celui du tag coffee ...qui porte les DU d'ailleur) ces décallages de rotation entre chaque os/joint

ma fonction de lecture du différentiel entre chaque os/joint :
GetAngle(Source,Dest)
{
var m1 = Source->GetMg(); // le premier os par ex
var m2 = Dest->GetMg(); // avec le 1er joint par ex
angle1 = m1->GetHPB(); // me donne un vecteur de la rotation globale HPB
angle2 = m2->GetHPB(); // pareil
a = angle2-angle1; // -> le différentiel de rotation que je stocke dans le container du tag
}

ensuite je freeze ce vecteur a en copiant sa valeur en b.. et un peu plus loin dans le code j'injecte sur le squelette de joint , la rotation globale de l'os + ce différentiel de rotation b (bloqué biensur sinon il se mettrait à jour tout le temps )

ApplyAngle(Source,Dest,b) // source = moccap , dest = joints et b = differentiel bloqué
{
var m1 = Source->GetMg();
var m2 = Dest->GetMg();
pos1 = m1->GetV0();
pos2 = m2->GetV0();
m2->SetRotHPB(angle1+b); // on insert la nvelle rotation = angle os + differentiel initial freezé d'angle entre os+joint)
m2->SetV0(pos2); // ici on re-set la position car la fonction SetRotHPB écrase la position ..c'est con mais c'est dans le SDK
m2->SetV1(vnorm(m2->GetV1()));
m2->SetV2(vnorm(m2->GetV2()));
m2->SetV3(vnorm(m2->GetV3()));
Dest->SetMg(m2); // et là on set la nvelle matrice de 'Dest' qui est le joint .. tout en mode globale pour ne pas être emmerdé
par des problêmes d'angles locaux ..
}

mais bon voila ça marche pas top ..voir pas du tout :( .. j'ai essayé de brider les rotations des différents éléments à -180° +180° .. mais ça change rien .. passer certains angles la chaine de joints tourne dans l'autre sens .. c'est assez bisard ..
est-ce que je fais complêtement fausse route là ? est-ce bien d'utiliser les matrices globales ? ( j'ai choisis les globales pour ne pas tenir compte des différences d'orientation locales entre les squelettes ..mais peut-être que je me gourre ? )

any ideas les cocos ? :art:

paspas
04/01/2010, 14h38
salut

dure a dire comme ca sans voir une anime ou une image du souci :coup:

mais a l aveugle je dirait


....
m2->SetV1(vnorm(m2->GetV1()));
m2->SetV2(vnorm(m2->GetV2()));
m2->SetV3(vnorm(m2->GetV3()));
....

pq utiliser (vnorm(m2->GetV1())) et non pas directement m2->GetV1() ??

vnorm sert a crée un vecteur direction ici tu doit juste récupère les vecteur de la matrice m2 non ??

nmt si tu a un glibal lock ca vient du fait que tu recrée un matrice complète ce que je te déconseille ,
il vaut mieux utiliser comme tu la fait SetRotHPB et utiliser GetmulP si mes souvenir sons exacte pour lui applique une rotation ( a la matrice )

paspas

clemz
04/01/2010, 15h11
salut Paspas ! :odile:




....
m2->SetV1(vnorm(m2->GetV1()));
m2->SetV2(vnorm(m2->GetV2()));
m2->SetV3(vnorm(m2->GetV3()));
....

pq utiliser (vnorm(m2->GetV1())) et non pas directement m2->GetV1() ??

vnorm sert a crée un vecteur direction ici tu doit juste récupère les vecteur de la matrice m2 non ??


ha en fait j'ai repris exactement ce qu'ils mettent dans le SDK pour la fonction "SetGlobaleRotation() " où comme le SetHPB() écrase la position V0 il rajoute ça après mais c'est vrai que tu as raison mes vecteurs v1 v2 v3 n'ont pas été modifiés donc pas besoin de les normaliser :)

voila une vid :
http://kiteclem35.free.fr/3D/C4D/Coffee%20moccap.mov 10mo

donc tu vois quand je pivote l'os 'hip' source , mon joint 'hip' target ne pivote pas pareil .. moi je veux qu'ils soient "contraints- parents " en rotation :)

donc tu parles de GetMulP ? plutôt GetMulM ? mais comment ferais-tu pour lier ces rotations exactement ? :oops:

merki

oli_d
04/01/2010, 16h16
Salut,

je sais pas si j'ai bien saisi tout le problème (je suis vraiment un bille en nonos et animation), mais je sais que les matrices au début c'est :coup: (enfin à la fin aussi, mais c'était juste pour te donner l'espoir !)



ha en fait j'ai repris exactement ce qu'ils mettent dans le SDK pour la fonction "SetGlobaleRotation() " où comme le SetHPB() écrase la position V0 il rajoute ça après mais c'est vrai que tu as raison mes vecteurs v1 v2 v3 n'ont pas été modifiés donc pas besoin de les normaliser :)



Oui sauf que dans le SDK ils récupèrent l'échelle d'abord et ensuite il font : m->SetV1(vnorm(m->GetV1()) * scale.x);

Met en enfant un objet et tu tritures les axes de l'objet parent



main(doc,op)
{
var rot = op->GetRotation();
rot.x=rot.x+Radians(15);
op->SetRotation(rot);
}


ce code tourne de 15 degrés à chaque fois selon les références parent donc en local



SetGlobalRotation(obj, rot)
{
var m = obj->GetMg();//matrice globale
var pos = m->GetV0();//on prend la position initale
var scale = vector(vlen(m->GetV1()),
vlen(m->GetV2()),
vlen(m->GetV3()));//on récupère l'échelle initiale

m->SetRotHPB(rot);//on tourne

m->SetV0(pos);//on réapplique la position initiale...
m->SetV1(vnorm(m->GetV1()) * scale.x);
m->SetV2(vnorm(m->GetV2()) * scale.y);
m->SetV3(vnorm(m->GetV3()) * scale.z);//... et l'échelle initiale

obj->SetMg(m);//on applique la matrice transformée à l'objet
}



main(doc,op)
{
var rot = op->GetMg()->GetHPB();
rot.x=rot.x+Radians(15);
SetGlobalRotation(op,rot);
}

celui-ci tournera toujours selon les axes du monde donc en global....

Dans ton exemple, il me semble que tu pourrais travailler en local , mais encore une fois j'ai peut-être pas tout compris...

clemz
04/01/2010, 16h57
Salut,

je sais pas si j'ai bien saisi tout le problème (je suis vraiment un bille en nonos et animation), mais je sais que les matrices au début c'est :coup: (enfin à la fin aussi, mais c'était juste pour te donner l'espoir !)

salut Oli_D :) .. oué les matrices c'est assez chiant mais je pense que lorsqu'on a bien capté toutes les possibilités autour avec les produits matriciels , les inversions de matrices etc on peut arrvier à faire des trucs délirants .. on est les rois du moooooonde !



Dans ton exemple, il me semble que tu pourrais travailler en local , mais encore une fois j'ai peut-être pas tout compris...


merci pour le bout de code . en fait moi ce que je veux faire , c'est exactement comme si je mettais un tag constraint en mode parent sur chaque joint avec pour source cible les os correspondant .. donc au moment où tu mets l'os dans le lien du tag constraint , il enregistre l'offset et "soude" le joint et l'os . ( bon moi je veux pas de "soudure de position " , mais juste rotation ) .

bon je vais tenter par produits de matrices alors , et non pas avec les vecteurs HPB ( GetHPB() / SetHPB() ) qui me flip mes angles n'importe comment :cry2:

:odile:

valkaari
04/01/2010, 17h32
moi pas tout comprendre non plus avec les matrices. mais je suis de tout coeur avec vous.

bon le vnorm sert simplement à faire en sorte que la longueur du vecteur soit égale à 1. C'est pour ça qu'il faut récup l'échelle avant et la réinjecter après, la direction ne change pas.

pour ton soucis il faut peut être que la rotation global de l'os devienne une rotation local par rapport à la rotation freezé de ton joint.

je sais que pour passer une position local en global, il faut multiplier la position par la matrice global. ou l'inverse de la matrice (enfin dans un sens c'est la matrice et dans l'autre l'inverse de la matrice) par contre pour la rotation je sais pas trop. peut être simplement multiplier les matrices et les normaliser.

bref je suis de tout coeur avec toi et je suis le pb en essayant de trouver un truc parce que c'est très intéressant ^^

clemz
05/01/2010, 12h34
dites , j'ai peut-être trouvé une soluc mais je trouve ça vraiment 'lourd' :

j'ai testé un peu toutes les combinaisons possibles de multiplications de matrices entre elles mais c'est jamais bon .. il y a un truc qui m'échappe
donc j'ai pensé à passer par une copie de ma source insérée dans la chaine de ma target :

j'utilise un nul object que je crée et inserts au même niveau que mon objet target (ob2). je l'oriente comme mon objet source (ob1) en matrice globale ..donc il est bien supperposé à mon objet source dont je veux lire les rotations .. mais il est enfant du même parent que mon objet target , donc je n'ai plus qu'à faire un différentiel local des rotations ..

...
mynul = AllocObject(Onull);
mynul->InsertUnder(dest->GetUp());
mynul->SetMg(m1g); // m1g est la matrice globale de mon objet source ob1
...

mais le probleme c'est quil me crée un vrai objet pour ça ( mynul ) ..que je supprime avant la fin du code biensur avec
mynul->Remove();
mais bon ça fait un peu enfilage de mouche pour si peu ^^ ... est-ce qu'il n'y aurait pas moyen de passer par un nul virtuel dans le code sans avoir à créer un 'objet' ? je trouve pas comment faire .

valkaari
05/01/2010, 15h27
ben en théorie les calculs tu peux les faire avec n'importe quoi que les objets soient virtuels ou pas. Par contre ce que je sais pas c'est comment passer de local à global en rotation :calim:

clemz
06/01/2010, 00h35
hehe moi aussi j'ai du mal avec les transformations locales globales de matrices ^^

bon un grand merci à Cactus Dan qui m'a filé le truc :
je le cite :


// get the source object inverse matrix
var invM = source->GetMg();
invM->Invert();

// calculate the rotational offset matrix
var opM = dest->GetMg();
var rotM = invM->GetMulM(opM);
rotM->SetV0(vector(0,0,0));

// calculate the object's transformation matrix
var targM = source->GetMg();
var transM = targM->GetMulM(rotM);
transM->SetV0(opM->GetV0());

dest->SetMg(transM);

pff honnêtement j'ai testé presque toutes les combinaisons possibles mais pas celle là :lol: ..enfin j'étais pas loin .
bon donc base du code de contrainte 'parent' en rotation, réglée ! yapluka !
:odile:

exemple fonctionnement :
rotation parenting (http://kiteclem35.free.fr/3D/C4D/RotationParenting.mov) 1.6mo

donc concrêtement , ceci va me permettre de lire chaque os de mon rig source ( moccap ) en rotation , et quelque soit leur orientation par rapport aux joint/os de mon rig target , je stocke ces offsets de rotations et applique la rotation du moccap sans altérer l'orientation initiale des joints target .
il y a un tag 'Retarget' dans menu character qui fait quelque part une transmission de rotations d'une chaine à une autre mais c'est exactement ce que je ne voulais pas , car ça ne stocke pas les offsets .

donc étape suivante : injection de ce petit bout de code dans le vrai code

http://kiteclem35.free.fr/3D/C4D/moccap.jpg

valkaari
06/01/2010, 01h38
ha ben j'étais pas loin t'avouera mais je savais pas que ça marchait pour les rotations de multiplier par la matrice ou son inverse


encore un truc appris :bounce:

oli_d
06/01/2010, 07h29
Merci pour le retour, qui me sera également bien utile. :efface:

comme valkaari, je commençais à bien piger pour les positions, mais je m'étais jamais encore vraiment attaqué aux rotations.

clemz
14/01/2010, 21h21
saluche :)

bon après 15j de galères j'ai enfin un truc qui marche :mrgreen: ..enfin à part 2 trucs :

- j'arrive pas a stocker des valeurs . je sauve et je réouvre mon fichier et j'ai perdu ces valeurs .. ça a réinitialisé quelque part :S
- lorsque je blend entre le rig IK et le rig mocap (voir dans la vid ) , par ex je vais mixer entre un angle de 10° vers un angle de 0° et bein ce con il me fais 10° vers 360° et c'est pas cette même logique partout :cry2:.. donc on peut voir certain os de la colone vertébrale tourner dans un sens et d'autres dans l'autre ... j'arrive pas à controller le sens de rotation d'un angle A vers B pour l'instant .

scusez pour la vid , elle est un peu longue , j'aurais du zapper des trucs .
vid (http://www.vimeo.com/8744036)

:odile:

oli_d
15/01/2010, 07h33
- j'arrive pas a stocker des valeurs . je sauve et je réouvre mon fichier et j'ai perdu ces valeurs .. ça a réinitialisé quelque part :S


Si tu as utilisé un container fais gaffe que le n° pour arriver sur ta valeur soit unique. Si tu en as beaucoup à stocker tu peux utiliser un sous-container qui lui aura un n° unique et ensuite les valeurs qu'il contient peuvent avoir la référence de ton choix.



- lorsque je blend entre le rig IK et le rig mocap (voir dans la vid ) , par ex je vais mixer entre un angle de 10° vers un angle de 0° et bein ce con il me fais 10° vers 360° et c'est pas cette même logique partout :cry2:.. donc on peut voir certain os de la colone vertébrale tourner dans un sens et d'autres dans l'autre ... j'arrive pas à controller le sens de rotation d'un angle A vers B pour l'instant .


C'est vrai que 360 ou 0 c'est le même angle en gros. Essaie peut-être d'utiliser une valeur du type 0.0001 au lieu du zéro ou 359.9999 au lieu du 360, je pense que cela ne se verra pas et cela risque de régler le pb

clemz
15/01/2010, 12h46
salut Oli_D :)

ouep oki pour les angles ( Lennart de c4dcafe m'a aussi indiqué une fonction que j'avais pas vue : MinimizeAngle(vectorA,vectorB) ; )
je vais tester vos astuces .

pour le stockage je crois que j'ai peut-être trouvé d'où ça pourrait venir : en fait je bloque des valeurs dans le container via un booléen 0-1 qui est à la base mis à 0 puis dès la fin du stockage , est mis à 1 .. et plus rien dans le code ne le remet à 0 , tant qu'il ne se passe pas quelque chose de particulier . code du style :

......
var temp=0;
.....
main ()...
{
var bc = tag->GetContainer();
.......
if (temp ==0)
{
var myvalue= ....
bc->SetData(id,myvalue);
tag->SetContainer(bc); .. etc
temp=1;
}
.....
}

et donc même si je sauve le fichier et que 'temp' =1 ( donc verrouillé ) , quand je réouvre le fichier , il s'est remis à 0 et donc réenregistre en l'état mes offsets concrêtement . Donc je pensais que mon pb pourrait être résolu en stockant dans le container , ce 'temp' , à la fin du code et en l'appellant dans le container au début du code ? je vais tester.

oh tient autre pitite question : les ids dans le container , on peut utiliser tout ce qu'on veut ? il y en a pas qui seraient deja attribuées pour des trucs particuliers ? par ex je parts de l'id = 0 et je monte jusqu'à 240 par là ( j'ai une fonction auto de calcul des ids en fonction du nombre d'éléments qu'on doit stocker ..qui s'incrémente tte seule ) .. je n'écrase rien sur cette range 0-240 ? c'est pas très clair dans le sdk pour ça, est-ce que les containers des objets sont vides par défaut ?

merki :odile:

oli_d
16/01/2010, 03h36
oh tient autre pitite question : les ids dans le container , on peut utiliser tout ce qu'on veut ? il y en a pas qui seraient deja attribuées pour des trucs particuliers ? par ex je parts de l'id = 0 et je monte jusqu'à 240 par là ( j'ai une fonction auto de calcul des ids en fonction du nombre d'éléments qu'on doit stocker ..qui s'incrémente tte seule ) .. je n'écrase rien sur cette range 0-240 ? c'est pas très clair dans le sdk pour ça, est-ce que les containers des objets sont vides par défaut ?


Fait attention tu risques de rentrer en conflit avec un n° déjà attribué. Quand j'ai beaucoup de données à stocker, j'utilise un sous-container dans lequel je peux mettre les numéros que je veux, exemple :

main(doc,op)
{
var myId =1024910; // N° unique obtenu sur http://www.plugincafe.com/forum/developer.asp
var bc = op->GetContainer(); //on récupère le container de l'objet
var ss_bc = new(BaseContainer);//on crée un sous-container ...
ss_bc->SetData(1,"Hello world");//...on lui affecte des valeurs...
ss_bc->SetData(2,12345);// ... et là tu choisis n'importe quel id...
ss_bc->SetData(3,3.1416);

bc->SetData(myId,ss_bc);//...et on affecte ce ss-cont au container de l'objet...
op->SetContainer(bc);// ... on met à jour le container de l'objet
}

ensuite pour récupérer tes valeurs :



main(doc,op)
{
var myId =1024910;
var bc = op->GetContainer();
var ss_bc = bc->GetContainer(myId);

println(ss_bc->GetString(1));
println(ss_bc->GetInt(2));
println(ss_bc->GetFloat(3));;
}


(on peut mettre ces deux bouts de code dans deux tags COFFEE sur le même objet et normalement ça affiche un truc dans la console)

Sinon pour ton problème via le booléen je pense que ton analyse est juste et qu'il y a bien une couille dans le potage ou un bool dans le stockage...

clemz
16/01/2010, 10h55
salut Oli_D :) merci pour ton retour . ok j'ai demandé un id sur plugincafe .je vais faire comme tu dis en utilisant des souscontainers . Lennart de C4Dcafe m'adit que normalement une fois mis en coffee plugin tag , ce script ne devrait plus être "recompilé" à chaque réouverture de c4d ( c'est apparement le problême : c4d recompile le code entièrement à chaque réouverture , et donc reset ce temp à sa toute 1ère lecture) .

donc prochaine étape ..mise en plugin avec tes corrections ..croisons les doigts :mrgreen:

merki
clem

nitros
24/02/2010, 17h11
Salut Clemz,

je bosse sur le même sujet (c'est pour éviter un investissement interposer ? :) ),
et je poste mes résultats en fin de semaine dans la section programmation,

en attendant je prends un siège aussi.

poumpouny2
25/02/2010, 10h20
Merde on dirait que vous viviez sur une autra planete :mrgreen:

clemz
25/02/2010, 11h25
vas y Nitros fais péter tes tests ? :love: