Problème d'algorithme pour mon moteur 3D

Problème d'algorithme pour mon moteur 3D - Algo - Programmation

Marsh Posté le 04-02-2013 à 04:59:22    

Bonjour   :hello:  
 
Je développe un moteur 3D depuis quelques temps, j'ai implémenté les animations et tout fonctionne correctement mais je suis confronté maintenant à un problème. Tout d'abord voici un résumé de comment ça fonctionne jusqu'à présent :  
 
Je crée un modèle skinné et animé sous un logiciel 3D, je l'exporte dans un format perso, j'exporte également les animations dans un autre format et je charge le tout dans mon moteur. Ensuite je crée mon modèle avec son skin (tableau qui associe à chaque vertex la somme pondérée des bones auquel il est lié) ainsi que son squelette.  
 
Pour assurer la bonne transformation des vertex durant l'animation, j'utilise pour chaque modèle skinné 2 squelettes : un qui est toujours à la même position, celle d'origine, et l'autre qui va bouger conformément à l'animation. Je parcours ensuite la hiérarchie de ces 2 squelettes à chaque frame et je calcule pour chaque bone une matrice qui sera égale à la matrice de passage du squelette d'origine vers le squelette courant. J'obtiens ainsi un tableau contenant autant de matrices qu'il y a de bones dans mon squelette, chaque matrice décrivant la transformation subie pour passer de la position d'origine vers la position courante, et donc la déformation que devra subir le vertex qui l'utilisera pour suivre le mouvement de son bone. J'envoie ensuite le tout au vertex shader qui multiplie alors la matrice de transformation initiale (projection * modelview) par cette matrice. Au moment de l'animation, les déformations sont correctes donc je n'ai pas d'erreur à ce niveau là.  
 
Maintenant, j'aimerais aller un peu plus loin en permettant au moteur de pouvoir lier un mesh à un bone, ce que font tous les moteurs 3D, mais le problème c'est que jusqu'à présent les 2 squelettes de mon mesh n'étaient pas liés à la scène car j'ai constaté que ça provoquait des problèmes dont je n'ai pas réussi à identifier correctement la cause (je ne suis pas très matheux à la base, j'ai déjà beaucoup galéré au niveau des matrices mais il y a encore des trucs qui m'échappent). J'ai donc imaginé plusieurs solutions qui s'apparentent plutôt à du bidouillage mais je vais d'abord essayer de décrire brièvement l'architecture de cette partie de l'application :  
 
J'ai une classe entité qui dérive d'une classe de node et qui contient un pointeur vers les 2 squelettes (eux aussi de type node). Au moment du rendu, l'entité calcule sa matrice de transformation en fonction de sa matrice locale et de la matrice world de son parent. Pour le moment je n'ai pas eu besoin de lier les 2 squelettes à l'entité car je ne m'en sert que pour calculer les transformations locales subies par les différents bones du squelette, et j'envoie ensuite au shader la matrice world de l'entité ainsi que les matrices de déformation de ses différents bones. Le shader va donc composer ces matrices pour calculer la matrice de transformation finale (en pondérant évidemment les transformations pour les vertex influencés par plusieurs bones), ce qui fait que la méthode consistant à ne pas lier les squelettes au graphe de scène marche parfaitement... jusqu'au moment où je décider de lier d'autres entités à certains bones de mon squelette.  
 
Etant donné qu'il n'est pas lié au graphe de scène, le bone parent de l'entité que je viens de linker ne contiendra que la transformation du bone par rapport au root du squelette, mais pas les informations sur les transformations de la caméra, ce qui fait qu'il restera toujours au même endroit par rapport à celle-ci.  
 
Deux solutions possibles se présentent donc :
 
. Soit je link les deux squelettes à mon entité, mais ça me pose alors un problème pour calculer la matrice de passage des bones d'origines vers les bones courants. En effet, si on nomme M0 la matrice world de l'entité et M1...Mn les matrices de tous les bones du squelette d'origine et M1'...Mn' les matrices des bones courants, ça veut dire que pour un bone k, j'aurais sa matrice d'origine de cette forme :  
 
Mg = M1 * ... * Mk  
 
et sa matrice courante de cette forme :  
 
Mc = M1' * ... * Mk'  
 
et donc la matrice de passage vaudra :  
 
Mp = Mc * Mg^-1 = M1' * ... * Mk' * Mk^-1 * ... * M1^-1.
 
Par contre si je link les 2 squelettes à l'entité, j'aurais la matrice de passage d'un bone k de la forme suivante :  
 
Ap = M0 * M1' * ... * Mk' * Mk^-1 * ... * M1^-1 * M0^-1 = M0 * Mp * M0^-1
 
Or, arrêtez moi si je dis une bétise mais normalement pour tout M0 (sauf pour l'identité évidemment), M0 * Mp * M0^-1 =/= Mp, ce qui est d'ailleurs confirmé par les déformations complètement foireuses que subi mon modèle au moment de l'animation si j'utilise cette méthode.  
 
C'est la raison pour laquelle j'ai imaginé une autre solution un peu crade qui consiste simplement à stocker dans chaque entité linkée à un bone un pointeur vers l'entité "maitre", c'est à dire celle qui contient le bone auquel elle est linkée. Au moment du rendu je multiplie la matrice world de l'entité linkée par la matrice world de l'entité maitre de cette manière : WorldBoneLinké = WorldEntitéMaitre * WorldBoneLinké.
Le problème c'est que ça ne marche toujours pas  :fou: , au moment du rendu j'ai mon animation qui est jouée correctement, les déformations du meshes sont bonnes mais en revanche les objets liés se mettent n'importe où [:openutella] (je précise quand même qu'ils suivent bien l'animation, mais ils sont dans un autre repère que l'os auquel ils sont liés).
 
Même si c'est une bidouille et qu'il faudrait sûrement que j'implémente un algo moins crade par la suite, cette méthode me semble pourtant correcte  non  :??:  
 
Sinon j'ai imaginé une 3eme solution mais elle me parait encore plus pourrie que la 2eme, elle consisterait à laisser les deux squelettes non liés à l'entité et à utiliser un 3eme squelette lié à l'entité auxquelles seraient liées les entités filles, mais du coup ça veut dire qu'il faudra faire 3 update de squelette pour chaque entité au lieu de deux actuellement, sachant que ça utilise des inversions et des multiplications de matrices qui ne sont pas particulièrement rapide à calculer (d'autant plus que le modèle que j'utilise pour les test a 53 bones, ce qui est plutôt standard dans le jeu vidéo). En fait j'ai simplement imaginé cette méthode tout à l'heure et je n'ai pas encore bien réfléchi à toutes les conséquences, si ça se trouve je risque d'être confronté à d'autres difficultés ou bidouilles que je n'ose imaginer.  
 
Voilà, merci pour votre patience pour ceux qui ont lu jusqu'au bout, j'aurais bien aimé être plus concis et plus clair mais c'est pas évident  d'expliquer tout ça en peu de mot. Si l'un d'entre vous a déjà travaillé sur un moteur 3D et qu'il connait les techniques qui sont utilisées dans ce genre de cas, car à mon avis il doit exister une solution plus simple et élégante que mes algos, je serais ravi de discuter avec lui :)

Reply

Marsh Posté le 04-02-2013 à 04:59:22   

Reply

Marsh Posté le 04-02-2013 à 12:54:38    

Ton pb ne serait-il pas simplement lié à une expression des coordonnées dans le mauvais repère (ou référentiel) ? En gros, que certains objets ont leurs coordonnées dans un premier repère et que d'autres, dans un autre repère?


---------------
Astres, outil de help-desk GPL : http://sourceforge.net/projects/astres, ICARE, gestion de conf : http://sourceforge.net/projects/icare, Outil Planeta Calandreta : https://framalibre.org/content/planeta-calandreta
Reply

Marsh Posté le 04-02-2013 à 18:30:44    


Oui je pense egalement qu'il s'agit d'une probleme de ce style mais pourtant mon algo me semble correct, c'est pour ca que j'ai essayé d'expliquer ma facon de proceder pour verifier que je fais bien les choses comme il faut, et egalement pour verifier que mes diffentes hypotheses sont correctes (comme je l'expliquais je ne suis pas trop matheux et il est possible que j'ai commis des erreurs sur les calculs matriciels, notamment pour la 1ere solution).  
 
J'ai encore reflechi un peu ces dernieres heures et je me demande si le probleme ne viendrait pas du fait que meme si je link correctement une entite a un bone, je ne precise pas exactement ou elle doit se linker. En effet, l'entite est probablement dans le bon repere (sinon elle ne bougerait pas conformement a l'animation de son parent, car actuellement si je fais un pitch sur son parent l'entite pitch bien dans le bon repere) mais il me semble qu'a aucun moment je ne lui indique precisement ou elle doit se placer. C'est comme si je te disais de monter dans un bus sans te preciser a quelle place, je connaitrais alors ton deplacement (vitesse et acceleration) par rapport a moi mais je ne saurais pas excatement a quel endroit il faut te dessiner.  
 
C'est a mon avis comme ca que fonctionne le link, on dit juste a une entite dans quel referentiel elle doit se situer, sans lui dire precisement a quel endroit elle doit se placer dans ce referentiel, ni quelle orientation elle doit y prendre. Du coup elle vient se placer a un endroit qui ne correspond pas forcement a celui auquel on s'attend (j'ai refais des tests apres avoir poste mon premier message et quand j'utilise la 2eme solution, l'entite que je link semble se mettre a l'endroit ou est situe son bone parent, mais elle n'est pas orientee correctement, ce qui tendrait a confirmer mon hypothèse).

Reply

Marsh Posté le 05-02-2013 à 09:51:51    

Ben le link doit justement apporter l'info de translation à la matrice que tu linkes à celle parent.


---------------
Astres, outil de help-desk GPL : http://sourceforge.net/projects/astres, ICARE, gestion de conf : http://sourceforge.net/projects/icare, Outil Planeta Calandreta : https://framalibre.org/content/planeta-calandreta
Reply

Marsh Posté le 06-02-2013 à 18:52:36    

En fait je ne sais pas si on a la même définition du link, la mienne est peut être fausse. Jusqu'à présent pour moi le link était le fait de dire a un objet de se placer dans la base d'un autre et de subir donc toutes les transformations de ce dernier, en clair a chaque update on aura MatObjWorld = MatParentWorld * MatLocalObj. Donc effectivement l'objet enfant subit les transformations de son parent (en plus des siennes propres) mais avec la formule que je viens de donner il y a une petite subtilité supplémentaire liée au fait que la matrice locale de l'objet, lors d'un link, sera toujours la même qu'avant (en tout cas dans mon moteur). Du coup comme cette base deviendra la base locale de l'objet linke par rapport au nouveau parent, cet objet changera de place (il sera donc bien lié a son parent, mais il ne sera pas situe a position qu'il avait avant le link). Donc dans mon moteur un link n'est pas simplement le fait de dire a un objet de suivre les transformations d'un autre, ça perturbe également sa position initiale (j'avoue que je ne sais pas comment les autres moteurs gèrent ça, c'est peut être ma méthode qui est mauvaise).  
 
Partant de la, j'avais quelques soucis car je voulais linker un objet a un autre sans pour autant changer sa position d'origine. J'ai finalement résolu le problème avant hier soir en multipliant, lors du link, la matrice locale de l'objet enfant par l'inverse de la matrice world de son parent. Ensuite au moment de l'update je me contente d'utiliser la même formule qu'avant. En fait j'avais déjà teste cette méthode peu avant mais j'avais d'autres bugs ailleurs qui me faisait foirer ma transformation et du coup je pensais que la solution que j'ai re-testé avant hier soir était incorrecte. Apres avoir isole chaque partie j'ai pu corriger les bugs que j'avais ailleurs et maintenant ça marche.


Message édité par ailaulit le 07-02-2013 à 02:36:01
Reply

Sujets relatifs:

Leave a Replay

Make sure you enter the(*)required information where indicate.HTML code is not allowed