WebGL avec Three.js modèles et animation

Les graphiques 3D dans le navigateur sont un sujet brûlant depuis leur introduction. Mais si vous deviez créer vos applications à l'aide de l'ancien WebGL, cela prendrait des siècles. C'est pourquoi certaines bibliothèques vraiment utiles ont vu le jour. Three.js est l’un des plus populaires. Dans cette série, je vais vous montrer comment en tirer le meilleur parti pour créer de superbes expériences 3D pour vos utilisateurs..

Je m'attends à ce que vous ayez une connaissance de base de l'espace 3D avant de commencer à lire ce didacticiel, car je n'expliquerai pas les sujets tels que les coordonnées et les vecteurs..


Préparation

Comme d'habitude, nous allons commencer par le code que vous avez créé précédemment. Téléchargez et décompressez les ressources que j'ai fournies et vous serez prêt à partir.


Étape 1: Un mot sur l'exportation de modèles dans Blender

Avant de commencer la partie programmation, je vais expliquer quelque chose avec lequel beaucoup de gens ont des problèmes. Lorsque vous avez créé un modèle dans Blender et que vous souhaitez l'exporter au format Three.js, gardez à l'esprit les points suivants:

  • Tout d'abord, supprimez le rôle parental. L'exportateur Three.js n'exportera aucune animation si vous le laissez (cela s'applique également au modificateur d'armature).
  • Deuxièmement, les sommets de groupe. Si vous souhaitez que l'os déplace les sommets, vous devez les grouper et nommer le groupe avec le nom de l'os..
  • Troisièmement, vous ne pouvez avoir qu'une seule animation. Cela peut sembler un gros problème, mais je vais expliquer la solution de contournement plus tard..

De plus, lors de l'exportation, vous devez vous assurer que ces options sont sélectionnées dans l'exportateur: Dépouillement, Des os et Animation squelettique.


Étape 2: Importer le modèle

Comme avec à peu près tout dans Three.js, l'importation de modèles est très simple. Il y a une classe spéciale, TROIS.JSONLoader cela fera tout pour nous. Bien sûr, il ne charge que les modèles JSON, mais il est recommandé de les utiliser. Je ne couvrirai donc que ce chargeur (les autres fonctionnent à peu près de la même manière). Initialisons-le d'abord:

 var loader = new THREE.JSONLoader; animation var;

Aucun argument nécessaire. Nous devons aussi définir une variable pour l'animation, pour pouvoir y accéder plus tard. Maintenant nous pouvons charger le modèle:

 loader.load ('./ model.js', fonction (géométrie, matériaux) var skinnedMesh = nouveau THREE.SkinnedMesh (géométrie, nouveau THREE.MeshFaceMaterial (matériaux)); skinnedMesh.position.y = 50; skinnedMesh.scale. set (15, 15, 15); scene.add (skinnedMesh); animate (skinnedMesh););

le charge La méthode accepte deux paramètres: un chemin d'accès au modèle et une fonction de rappel. Cette fonction sera appelée lors du chargement du modèle (vous pouvez donc afficher une barre de chargement à l’intention de l’utilisateur). Une fonction de rappel sera appelée avec deux paramètres: la géométrie du modèle et ses matériaux (ceux-ci sont exportés avec lui). Dans le rappel, nous créons le maillage, mais cette fois, c’est TROIS.SkinnedMesh, qui supporte les animations.

Ensuite, nous déplaçons le modèle de 50 unités pour le placer au-dessus de notre cube, nous l’échelonnons 15 fois (car j’ai tendance à créer de petits modèles dans Blender) et nous l’ajoutons à la scène. Ensuite nous appelons le animer fonction qui va configurer et jouer l'animation.


Étape 3: animation

Maintenant, nous mettons en place l'animation. Ceci est la source pour le animer une fonction:

 fonction animate (skinnedMesh) var materials = skinnedMesh.material.materials; pour (var k dans les matériaux) matériaux [k] .skinning = true;  THREE.AnimationHandler.add (skinnedMesh.geometry.animation); animation = new THREE.Animation (skinnedMesh, "ArmatureAction", THREE.AnimationHandler.CATMULLROM); animation.play (); 

Nous devons d’abord activer le skinning (animations) dans tous les matériaux du modèle. Ensuite, nous devons ajouter l'animation du modèle à TROIS.AnimationHandler et créer le TROIS.Animation objet. Les paramètres sont dans l'ordre suivant: le maillage à animer, le nom de l'animation dans le modèle et le type d'interpolation (utile lorsque vous avez un modèle complexe comme un corps humain, dans lequel vous souhaitez que le maillage se plie sans à-coups). Enfin, nous jouons l'animation.

Mais si vous ouvrez le navigateur maintenant, vous verrez que le modèle ne bouge pas:

Pour résoudre ce problème, nous devons ajouter une ligne à notre rendre fonction, juste en dessous du Système de particules rotation:

 if (animation) animation.update (delta);

Cela mettra à jour l'heure sur l'animation, donc TROIS.AnimationHandler sait quel cadre rendre. Maintenant, ouvrez le navigateur et vous devriez voir le cube en haut se plier à gauche et à droite:


Étape 4: Animations multiples

Oui, il existe une solution de contournement pour une séquence d'animation unique dans un modèle, mais vous devez la modifier. L'idée est que vous ajoutiez chaque animation à une séquence, puis, lorsque celle-ci se termine, la suivante commence. Ensuite, après avoir exporté votre modèle, vous devez modifier le code d'animation. Supposons que nous ayons une animation debout du début à la troisième seconde et une animation en marche de la troisième seconde à la fin. Puis dans notre rendre Nous devons vérifier en quelle seconde est l’animation, et si elle atteint l’heure de fin de la séquence en cours, arrêtez-la et lisez-la depuis le début:

 var currentSequence = 'debout'; fonction (rendu) … if (animation) animation.update (delta); if (currentSequence == 'standing') if (animation.currentTime> 4) animation.stop (); animation.play (false, 0); // lit l'animation sans boucle, à partir de 0 else if (currentSequence == 'walking') if (animation.currentTime <= 4 || animation.currentTime > 8) animation.stop (); animation.play (false, 4); // joue l'animation non bouclée, à partir de 4s…

Vous devez vous rappeler de démarrer les animations non bouclées et à partir du bon moment. Ce sera bien sûr un bug si le taux de trame de l'utilisateur est vraiment bas, car le delta sera plus élevé et animation.currentTime peut être beaucoup plus élevé que la limite pour une séquence particulière, entraînant la lecture d'une partie de la séquence suivante. Mais ce ne sera visible que si les deltas sont à environ 300-500ms.

Maintenant pour changer le animer pour jouer l’animation de marche, ajoutez simplement ces arguments à la animation.play une fonction:

 animation.play (false, 0);

En outre, permettons à l’utilisateur de basculer d’une animation à l’autre en utilisant le une clé. Ajoutez ce code à la fin du fichier, juste avant le rendre() appel:

 document.addEventListener ('keyup', fonction (e) if (e.keyCode == 'A'.charCodeAt (0)) currentSequence = (currentSequence ==' debout '?' en marche ':' debout '); );

Étape 5: attacher à l'os

Cette technique est particulièrement utile dans les JdR, mais elle peut également s’appliquer à d’autres genres. Ça implique attachant un autre objet à l'os de l'objet animé: vêtements, armes, etc..

Commençons par modifier notre loader.load rappeler. Ajouter ce code sous le scene.add (skinnedMesh '):

 item = new THREE.Mesh (new THREE.CubeGeometry (100, 10, 10), new THREE.MeshBasicMaterial (color: 0xff0000)); item.position.x = 50; pivot = new THREE.Object3D (); pivot.scale.set (0,15, 0,15, 0,15); pivot.add (item); pivot.useQuaternion = true; skinnedMesh.add (pivot);

le article Le maillage simule quelque chose que vous voudrez peut-être attacher à un objet animé. Pour le faire pivoter autour d’un point spécifique, et non du centre, nous allons l’ajouter à un pivot objet et déplacez-le 50 unités (la moitié de la largeur) vers la droite. Nous devons l'adapter à 0,15, car il sera ajouté à la skinnedMesh qui a une échelle de 15. Enfin, avant de l'ajouter à notre objet animé, nous lui demandons d'utiliser des quaternions..

En gros, les quaternions sont un système numérique, mais comme Three.js gère tout pour nous, vous n'avez pas à approfondir ce sujet si vous ne le souhaitez pas (mais si vous le souhaitez, jetez un coup d'œil à sa page Wikipedia). Ils sont utilisés pour faire pivoter des objets sans risque de blocage de la nacelle.

Maintenant, dans le rendre fonction nous devons mettre à jour la position et la rotation de l'objet:

 pivot.position = new THREE.Vector3 (). getPositionFromMatrix (skinnedMesh.bones [2] .skinMatrix); pivot.quaternion.setFromRotationMatrix (skinnedMesh.bones [2] .skinMatrix);

Laissez-moi vous expliquer ce qui se passe ici. Tout d'abord, nous définissons la position sur le même os que dans le dernier os du modèle. Nous utilisons le skinMatrix propriété pour le calculer. Ensuite, nous utilisons la même propriété pour calculer le quaternion pour le pivotla rotation de. Après cela, vous pouvez ouvrir le navigateur et vous devriez voir le faisceau rouge attaché à notre modèle:


Conclusion

J'espère que vous avez appris quelques nouvelles techniques intéressantes de ce tutoriel. Comme toujours, n'hésitez pas à expérimenter avec l'application que nous avons créée. Dans le prochain (et dernier) tutoriel de cette série, je vais vous montrer le vrai pouvoir d'OpenGL / WebGL-Shaders..