{"id":2073,"date":"2019-06-23T01:08:42","date_gmt":"2019-06-22T22:08:42","guid":{"rendered":"http:\/\/demensdeum.com\/blog\/?p=2073"},"modified":"2024-12-16T22:32:36","modified_gmt":"2024-12-16T19:32:36","slug":"skeletal-animation-1","status":"publish","type":"post","link":"https:\/\/demensdeum.com\/blog\/fr\/2019\/06\/23\/skeletal-animation-1\/","title":{"rendered":"Animation squelettique (Partie 1 &#8211; shader)"},"content":{"rendered":"<p>Dans cet article, je d\u00e9crirai ma compr\u00e9hension de l&#8217;animation squelettique, qui est utilis\u00e9e dans tous les moteurs 3D modernes pour animer des personnages, des environnements de jeu, etc.<br \/>Je vais commencer la description par la partie la plus tangible\u00a0: vertex shader, car l&#8217;ensemble du chemin de calcul, aussi complexe soit-il, se termine par le transfert des donn\u00e9es pr\u00e9par\u00e9es pour l&#8217;affichage vers le vertex shader.<\/p>\n<p><img loading=\"lazy\" decoding=\"async\" class=\"alignnone size-full wp-image-2080\" src=\"https:\/\/demensdeum.com\/blog\/wp-content\/uploads\/2019\/06\/flower-love-friendship-human-body-illustration-skeleton-913687-pxhere.com_.jpg\" alt=\"\" width=\"360\" height=\"228\" \/><\/p>\n<p>L&#8217;animation du squelette, apr\u00e8s avoir \u00e9t\u00e9 trait\u00e9e sur le CPU, passe dans le vertex shader.<br \/>Laissez-moi vous rappeler la formule du sommet sans animation squelettique\u00a0:<br \/>gl_Position = projectionMatrix * viewMatrix * modelMatrix * sommet;<br \/>Pour ceux qui ne comprennent pas comment est n\u00e9e cette formule, vous pouvez lire mon article d\u00e9crivant le principe du travail avec des matrices pour afficher du contenu 3D dans le contexte d&#8217;OpenGL.<br \/>Pour le reste &#8211; formule pour impl\u00e9menter l&#8217;animation squelettique\u00a0:<br \/>&#8221; vec4 anim\u00e9Vertex = bone0matrix * sommet * bone0weight +&#8221;<br \/>&#8220;bone1matrix * sommet * bone1weight +&#8221;<br \/>&#8220;bone2matrix * sommet * bone2weight +&#8221;<br \/>&#8220;bone3matrix * sommet * bone3weight;\\n&#8221;<br \/>&#8221; gl_Position = projectionMatrix * viewMatrix * modelMatrix * animationVertex;\\n&#8221;<\/p>\n<p>C&#8217;est-\u00e0-dire que nous multiplions la matrice de transformation osseuse finale par le sommet et par le poids de cette matrice par rapport au sommet. Chaque sommet peut \u00eatre anim\u00e9 par 4 os, la force de l&#8217;impact est r\u00e9gul\u00e9e par le param\u00e8tre poids de l&#8217;os, la somme des impacts doit \u00eatre \u00e9gale \u00e0 un.<br \/>Que faire si moins de 4 os affectent le sommet ? Nous devons diviser le poids entre eux et rendre l&#8217;impact du reste \u00e9gal \u00e0 z\u00e9ro.<br \/>Math\u00e9matiquement, multiplier un poids par une matrice est appel\u00e9 \u00ab multiplication matricielle-scalaire \u00bb. La multiplication par un scalaire vous permet de r\u00e9sumer l&#8217;effet des matrices sur le sommet r\u00e9sultant.<\/p>\n<p><strong>Les matrices de transformation osseuse elles-m\u00eames sont transmises sous forme de tableau. <\/strong>De plus, le tableau contient des matrices pour l&#8217;ensemble du mod\u00e8le dans son ensemble, et non pour chaque maillage s\u00e9par\u00e9ment.<\/p>\n<p>Mais pour chaque sommet les informations suivantes sont transmises s\u00e9par\u00e9ment\u00a0:<br \/>&#8211; Index de la matrice qui affecte le sommet<br \/>&#8211; Poids de la matrice qui affecte le sommet<br \/>Plus d&#8217;un os est transmis, g\u00e9n\u00e9ralement l&#8217;effet de 4 os sur le sommet est utilis\u00e9.<br \/>Aussi, la somme des poids des 4 d\u00e9s doit toujours \u00eatre \u00e9gale \u00e0 un.<br \/>Voyons ensuite \u00e0 quoi cela ressemble dans le shader.<br \/>Tableau matriciel\u00a0:<br \/>&#8220;uniform mat4 bonesMatrices[kMaxBones];&#8221;<\/p>\n<p>Informations sur l&#8217;effet de 4 os sur chaque sommet\u00a0:<br \/>&#8220;attribut vec2 bone0info;&#8221;<br \/>&#8220;attribut vec2 bone1info;&#8221;<br \/>&#8220;attribut vec2 bone2info;&#8221;<br \/>&#8220;attribut vec2 bone3info;&#8221;<\/p>\n<p>vec2 &#8211; dans la coordonn\u00e9e X, nous stockons l&#8217;index de l&#8217;os (et le convertissons en int dans le shader), dans la coordonn\u00e9e Y, nous stockons le poids de l&#8217;impact de l&#8217;os sur le sommet. Pourquoi devez-vous transmettre ces donn\u00e9es dans un vecteur bidimensionnel\u00a0? Parce que GLSL ne prend pas en charge la transmission de structures lisibles en C avec des champs valides au shader.<\/p>\n<p>Ci-dessous, je vais donner un exemple d&#8217;obtention des informations n\u00e9cessaires \u00e0 partir d&#8217;un vecteur pour une substitution ult\u00e9rieure dans la formule animationVertex\u00a0:<\/p>\n<p>&#8220;int bone0Index = int(bone0info.x);&#8221;<br \/>&#8220;float bone0weight = bone0info.y;&#8221;<br \/>&#8220;mat4 bone0matrix = bonesMatrices[bone0Index];&#8221;<\/p>\n<p>&#8220;int bone1Index = int(bone1info.x);&#8221;<br \/>&#8220;float bone1weight = bone1info.y;&#8221;<br \/>&#8220;mat4 bone1matrix = bonesMatrices[bone1Index];&#8221;<\/p>\n<p>&#8220;int bone2Index = int(bone2info.x);&#8221;<br \/>&#8220;float bone2weight = bone2info.y;&#8221;<br \/>&#8220;mat4 bone2matrix = bonesMatrices[bone2Index];&#8221;<\/p>\n<p>&#8220;int bone3Index = int(bone3info.x);&#8221;<br \/>&#8220;float bone3weight = bone3info.y;&#8221;<br \/>&#8220;mat4 bone3matrix = bonesMatrices[bone3Index];&#8221;<\/p>\n<p>Maintenant, la structure des sommets renseign\u00e9e sur le processeur devrait ressembler \u00e0 ceci\u00a0:<br \/>x, y, z, u, v, bone0index, bone0weight, bone1index, bone1weight, bone2index, bone2weight, bone3index, bone3weight<\/p>\n<p>La structure du vertex buffer est remplie une fois lors du chargement du mod\u00e8le, mais les matrices de transformation sont transf\u00e9r\u00e9es du CPU vers le shader \u00e0 chaque image de rendu.<\/p>\n<p>Dans les parties restantes, je d\u00e9crirai le principe de calcul de l&#8217;animation sur le CPU, avant de la transf\u00e9rer vers le vertex shader, je d\u00e9crirai l&#8217;arbre des n\u0153uds osseux, en parcourant la hi\u00e9rarchie animation-mod\u00e8le-n\u0153uds-mesh, la matrice interpolation.<\/p>\n<h3>Sources<\/h3>\n<p><a href=\"http:\/\/ogldev.atspace.co.uk\/www\/tutorial38\/tutorial38.html\" target=\"_blank\" rel=\"noopener noreferrer\">http:\/\/ogldev.atspace.co. fr\/www\/tutorial38\/tutorial38.html<\/a><\/p>\n<h3>Code source<\/h3>\n<p><a href=\"https:\/\/gitlab.com\/demensdeum\/skeletal-animation\" target=\"_blank\" rel=\"noopener noreferrer\">https:\/\/gitlab.com\/demensdeum\/skeletal-animation<\/a <\/p>\n","protected":false},"excerpt":{"rendered":"<p>Dans cet article, je d\u00e9crirai ma compr\u00e9hension de l&#8217;animation squelettique, qui est utilis\u00e9e dans tous les moteurs 3D modernes pour animer des personnages, des environnements de jeu, etc.Je vais commencer la description par la partie la plus tangible\u00a0: vertex shader, car l&#8217;ensemble du chemin de calcul, aussi complexe soit-il, se termine par le transfert des<a class=\"more-link\" href=\"https:\/\/demensdeum.com\/blog\/fr\/2019\/06\/23\/skeletal-animation-1\/\">Continue reading <span class=\"screen-reader-text\">&#8220;Animation squelettique (Partie 1 &#8211; shader)&#8221;<\/span><\/a><\/p>\n","protected":false},"author":1,"featured_media":0,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"_monsterinsights_skip_tracking":false,"_monsterinsights_sitenote_active":false,"_monsterinsights_sitenote_note":"","_monsterinsights_sitenote_category":0,"_jetpack_memberships_contains_paid_content":false,"footnotes":""},"categories":[61,52],"tags":[108],"class_list":["post-2073","post","type-post","status-publish","format-standard","hentry","category-techie","category-tutorials","tag-skeletal-animation","entry"],"translation":{"provider":"WPGlobus","version":"3.0.2","language":"fr","enabled_languages":["en","ru","zh","de","fr","ja","pt","hi"],"languages":{"en":{"title":true,"content":true,"excerpt":false},"ru":{"title":true,"content":true,"excerpt":false},"zh":{"title":true,"content":true,"excerpt":false},"de":{"title":true,"content":true,"excerpt":false},"fr":{"title":true,"content":true,"excerpt":false},"ja":{"title":true,"content":true,"excerpt":false},"pt":{"title":true,"content":true,"excerpt":false},"hi":{"title":false,"content":false,"excerpt":false}}},"jetpack_featured_media_url":"","jetpack_sharing_enabled":true,"_links":{"self":[{"href":"https:\/\/demensdeum.com\/blog\/fr\/wp-json\/wp\/v2\/posts\/2073","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/demensdeum.com\/blog\/fr\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/demensdeum.com\/blog\/fr\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/demensdeum.com\/blog\/fr\/wp-json\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/demensdeum.com\/blog\/fr\/wp-json\/wp\/v2\/comments?post=2073"}],"version-history":[{"count":13,"href":"https:\/\/demensdeum.com\/blog\/fr\/wp-json\/wp\/v2\/posts\/2073\/revisions"}],"predecessor-version":[{"id":3953,"href":"https:\/\/demensdeum.com\/blog\/fr\/wp-json\/wp\/v2\/posts\/2073\/revisions\/3953"}],"wp:attachment":[{"href":"https:\/\/demensdeum.com\/blog\/fr\/wp-json\/wp\/v2\/media?parent=2073"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/demensdeum.com\/blog\/fr\/wp-json\/wp\/v2\/categories?post=2073"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/demensdeum.com\/blog\/fr\/wp-json\/wp\/v2\/tags?post=2073"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}