Physique WebGL et détection de collision à l'aide de Babylon.js et Oimo.js

Aujourd'hui, j'aimerais partager avec vous les bases des collisions, de la physique et des boîtiers de contournement en jouant avec le moteur WebGL Babylon.js et un compagnon de moteur physique appelé Oimo.js..

Voici la démo que nous allons construire ensemble: Babylon.js Démo d'Espilit Physics avec Oimo.js.

Vous pouvez le lancer dans un aperçu technique compatible avec WebGL, comme IE11, Firefox, Chrome, Opera, Safari 8 ou Microsoft Edge, puis vous déplacer dans la scène comme dans un jeu FPS. appuyez sur la s clé pour lancer des sphères / boules et la b clé pour lancer des boîtes. À l’aide de votre souris, vous pouvez également cliquer sur l’une des sphères ou des cases pour y appliquer une force d’impulsion..

1. Comprendre les collisions

En regardant la définition de détection de collision de Wikipédia, on peut lire ceci: 

Détection de collision fait généralement référence au problème de calcul de la détection de l'intersection de deux objets ou plus. Bien que le sujet soit le plus souvent associé à son utilisation dans jeux vidéos et autre simulations physiques, il a également des applications dans robotique. En plus de déterminer si deux objets sont entrés en collision, les systèmes de détection de collision peuvent également calculer le temps d'impact (TOI) et signaler un collecteur de contacts (l'ensemble des points d'intersection)..Réponse de collision simule ce qui se passe lorsqu’une collision est détectée (voir moteur physique, physique de ragdoll). La résolution des problèmes de détection des collisions nécessite une utilisation poussée des concepts de algèbre linéaire et géométrie informatique.

Décomposons maintenant cette définition dans une scène 3D cool qui servira de base de départ pour ce tutoriel..

Vous pouvez vous déplacer dans ce grand musée comme dans le monde réel. Vous ne tomberez pas dans le sol, ne traverserez pas les murs et ne volerez pas. Nous simulons la gravité. Tout cela semble assez évident, mais il faut un tas de calculs pour simuler cela dans un monde virtuel 3D. 

La première question que nous devons résoudre lorsque nous pensons à la détection des collisions est de savoir à quel point elle devrait être complexe. En effet, tester si deux maillages complexes entrent en collision peut coûter beaucoup de ressources processeur, encore plus avec un moteur JavaScript où il est complexe de décharger cela sur autre chose que le thread d'interface utilisateur..

Pour mieux comprendre comment nous gérons cette complexité, accédez au musée Espilit situé à proximité de ce bureau:

Vous êtes bloqué par la table même s'il semble y avoir un peu d'espace disponible à droite. Est-ce un bug dans notre algorithme de collision? Non, ce n'est pas le cas (Babylon.js est exempt de bugs!). C'est parce que Michel Rousseau, l'artiste 3D qui a construit cette scène, l'a fait par choix. Pour simplifier la détection de collision, il a utilisé un collisionneur spécifique.

Qu'est-ce qu'un collisionneur??

Plutôt que de tester les collisions avec les maillages détaillés complets, vous pouvez les placer dans des géométries invisibles simples. Ces collisionneurs joueront le rôle de représentation du maillage et seront utilisés par le moteur de collision. La plupart du temps, vous ne verrez pas les différences, mais cela nous permettra d’utiliser beaucoup moins de ressources processeur, car le calcul derrière cela est beaucoup plus simple à calculer.

Chaque moteur supporte au moins deux types de collisionneurs: le cadre de sélection et le sphère englobante. Vous comprendrez mieux en regardant cette image:

Extrait de: Visualisation par ordinateur, Lancer de rayons, Jeux vidéo, Remplacement des boîtes de délimitation

Ce magnifique canard jaune est le maillage à afficher. Plutôt que de tester les collisions sur chacune de ses faces, nous pouvons essayer de l'insérer dans la meilleure géométrie englobante. Dans ce cas, une boîte semble être un meilleur choix qu'une sphère pour agir en tant qu'imposteur de maillage. Mais le choix dépend vraiment du maillage lui-même.

Revenons à la scène Espilit et affichons l'élément englobant invisible dans une couleur rouge semi-transparente:

Vous pouvez maintenant comprendre pourquoi vous ne pouvez pas vous déplacer par le côté droit du bureau. C’est parce que vous entrez en collision (eh bien, la caméra Babylon.js entre en collision) avec cette boîte. Si vous le souhaitez, changez simplement sa taille en diminuant la largeur pour s’adapter parfaitement à la largeur du bureau..

Remarque: si vous souhaitez commencer à apprendre Babylon.js, vous pouvez suivre la formation gratuite de Microsoft Virtual Academy (MVA). Par exemple, vous pouvez accéder directement à Introduction à WebGL 3D avec HTML5 et Babylon.js: Utilisation de Babylon.js pour les débutants, où nous couvrons cette partie de la collision de Babylon.js. Vous pouvez également consulter le code contenu dans notre outil de jeu interactif, Babylon.js playground: Échantillon de collisions.

En fonction de la complexité du moteur de collision ou physique, il existe d’autres types de collisionneurs disponibles: le capsule et le engrener, par exemple.

Extrait de: Premiers pas avec Unity - Colliders & UnityScript

Capsule est utile pour les humains ou les humanoïdes, car il correspond mieux à notre corps qu'une boîte ou une sphère. Engrener n’est presque jamais le maillage complet lui-même; c’est plutôt une version simplifiée du maillage original que vous ciblez, mais il est toujours beaucoup plus précis qu’une boîte, une sphère ou une capsule..

2. Chargement de la scène de départ

Pour charger notre scène Espilit, vous avez différentes options:

Option 1Téléchargez-le depuis notre référentiel GitHub, puis suivez le module Introduction à WebGL 3D avec HTML5 et Babylon.js: Loading Assets de notre cours MVA pour apprendre à charger une scène .babylon. En gros, vous devez héberger les ressources et le moteur Babylon.js sur un serveur Web et définir les types MIME appropriés pour l'extension .babylon..

Option 2: Téléchargez cette solution Visual Studio prédéfinie (fichier .zip).  

Remarque: si vous ne connaissez pas bien Visual Studio, consultez cet article: Développeurs Web, Visual Studio pourrait être un excellent outil gratuit de développement avec… Notez également que la version Pro est désormais gratuite pour de nombreux scénarios différents. Il s'appelle Visual Studio 2013 Community Edition..

Bien sûr, vous pouvez toujours suivre ce tutoriel si vous ne souhaitez pas utiliser Visual Studio. Voici le code pour charger notre scène. N'oubliez pas que la plupart des navigateurs prennent en charge WebGL maintenant: n'oubliez pas de tester Internet Explorer même sur votre Mac.

///  moteur var; toile var; scène var; document.addEventListener ("DOMContentLoaded", startGame, false); fonction startGame () if (BABYLON.Engine.isSupported ()) canvas = document.getElementById ("renderCanvas"); moteur = nouveau BABYLON.Engine (canvas, true); BABYLON.SceneLoader.Load ("Espilit /", "Espilit.babylon", moteur, fonction (LoadScene) scene = LoadScene; // Attend que les textures et les shaders soient prêts scene.executeWhenReady (function () // Connecter la caméra to canvas input scene.activeCamera.attachControl (canvas); // Une fois la scène chargée, il suffit d'enregistrer une boucle de rendu pour la restituer avec engine.runRenderLoop (function () scene.render (););, function (progress) // A faire: donner un retour d'information à l'utilisateur);  

En utilisant ce matériau, vous ne bénéficierez que du moteur de collision intégré de Babylon.js. En effet, nous faisons la différence entre notre moteur de collision et un moteur physique. 

Le moteur de collision est principalement dédié à l'interaction de la caméra avec la scène. Vous pouvez activer ou non la gravité sur la caméra, et vous pouvez également activer la checkCollision option sur la caméra et sur les différentes mailles. 

Le moteur de collision peut également vous aider à savoir si deux mailles entrent en collision. Mais c'est tout (c'est déjà beaucoup, en fait!). Le moteur de collision ne génère pas d'actions, de force ou d'impulsion après la collision de deux objets Babylon.js. Vous avez besoin d'un moteur physique pour que cela donne vie aux objets.

Nous avons intégré la physique dans Babylon.js via un mécanisme de plug-in. Vous pouvez en lire plus à ce sujet ici: Ajouter votre propre plugin de moteur physique à Babylon.js. Nous prenons en charge deux moteurs physiques à code source ouvert: Cannon.js et Oimo.js. Oimo est maintenant le moteur physique par défaut préféré.

Si vous avez choisi l'option 1 pour charger la scène, vous devez télécharger Oimo.js à partir de notre GitHub. C'est une version légèrement mise à jour que nous avons créée pour mieux supporter Babylon.js. Si vous avez choisi l'option 2, elle est déjà référencée et disponible dans la solution VS sous le des scripts dossier.

3. Activer la prise en charge physique dans la scène et transformer les collisionneurs en imposteurs physiques

La première chose à faire est d’activer la physique. Pour cela, veuillez ajouter ces lignes de code:

scene.enablePhysics (nouveau BABYLON.Vector3 (0, -10, 0), nouveau BABYLON.OimoJSPlugin ()); //scene.enablePhysics(new BABYLON.Vector3 (0, -10, 0), new BABYLON.CannonJSPlugin ());

Vous configurez le niveau de gravité (-dix sur l'axe des Y dans cet exemple de code, qui ressemble plus ou moins à ce que nous avons sur Terre) et le moteur physique que vous souhaitez utiliser. Nous utiliserons Oimo.js, mais la ligne commentée montre comment utiliser Cannon.js.

Maintenant, nous devons parcourir tous les colliseurs non visibles utilisés par le moteur de collision et activer les propriétés physiques de celui-ci. Pour cela, il vous suffit de trouver toutes les mailles où checkCollisions est réglé sur vrai mais pas visible dans la scène:

pour (var i = 1; i < scene.meshes.length; i++)  if (scene.meshes[i].checkCollisions && scene.meshes[i].isVisible === false)  scene.meshes[i].setPhysicsState(BABYLON.PhysicsEngine.BoxImpostor,  mass: 0, friction: 0.5, restitution: 0.7 ); meshesColliderList.push(scene.meshes[i]);  

S'il vous plaît déclarer le meshesColliderList également:

var meshesColliderList = [];

Et nous avons fini! Nous sommes prêts à lancer des objets dans notre scène et à mettre beaucoup de désordre dans ce musée magnifique mais trop calme.

4. Créer des sphères et des boîtes avec des états de physique

Nous allons maintenant ajouter quelques sphères (avec une texture Amiga) et quelques boîtes (avec une texture de bois) à la scène. 

Ces maillages auront un état physique défini. Par exemple, cela signifie qu'ils vont rebondir sur le sol si vous les lancez dans les airs, rebondir entre eux après la détection d'une collision, etc. Le moteur physique a besoin de savoir quel type d'imposteur vous souhaitez utiliser pour le maillage (plan, sphère ou boîte aujourd'hui), ainsi que les propriétés de masse et de frottement.

Si vous avez choisi l'option 1, vous pouvez télécharger les deux textures ici..

Ajoutez ce code à votre projet:

function CreateMaterials () materialAmiga = new BABYLON.StandardMaterial ("amiga", scène); materialAmiga.diffuseTexture = new BABYLON.Texture ("assets / amiga.jpg", scène); materialAmiga.emissiveColor = nouveau BABYLON.Color3 (0.5, 0.5, 0.5); materialAmiga.diffuseTexture.uScale = 5; materialAmiga.diffuseTexture.vScale = 5; materialWood = new BABYLON.StandardMaterial ("bois", scène); materialWood.diffuseTexture = new BABYLON.Texture ("assets / wood.jpg", scène); materialWood.emissiveColor = nouveau BABYLON.Color3 (0.5, 0.5, 0.5);  function addListeners () window.addEventListener ("keydown", fonction (evt) // s pour une sphère if (evt.keyCode == 83) pour (var index = 0; index < 25; index++)  var sphere = BABYLON.Mesh.CreateSphere("Sphere0", 10, 0.5, scene); sphere.material = materialAmiga; sphere.position = new BABYLON.Vector3(0 + index / 10, 3, 5 + index / 10); sphere.setPhysicsState(BABYLON.PhysicsEngine.SphereImpostor,  mass: 1 );   // b for box if (evt.keyCode == 66)  for (var index = 0; index < 10; index++)  var box0 = BABYLON.Mesh.CreateBox("Box0", 0.5, scene); box0.position = new BABYLON.Vector3(0 + index / 5, 3, 5 + index / 5); box0.material = materialWood; box0.setPhysicsState(BABYLON.PhysicsEngine.BoxImpostor,  mass: 4 );   ); 

Vous pouvez voir que les boîtes sont plus lourdes que les sphères d'un facteur de 4.

Remarque: si vous avez besoin de comprendre le fonctionnement des matériaux dans Babylon.js, consultez le module Introduction à WebGL 3D avec HTML5 et Babylon.js: Comprendre les matériaux et les entrées, ou jouez avec notre échantillon dédié Playground, Babylon.js Playground: Exemple..

Ajoutez ces deux lignes de code après la scene.enablePhysics ligne:

CreateMaterials (); addListeners ();

Et lancez le projet web. Naviguez jusqu'au centre du musée et appuyez sur le bouton s ou b clés. Vous obtiendrez ce résultat amusant:

5. Ajouter un support de sélection à cliquer sur les mailles

Ajoutons une autre fonctionnalité intéressante: la possibilité de cliquer sur l'un des objets pour le jeter. Pour cela, vous devez envoyer un rayon à partir des coordonnées 2D de la souris à l'intérieur de la scène 3D, vérifier si ce rayon touche l'une des mailles intéressantes et, le cas échéant, lui appliquer une force d'impulsion pour essayer de le déplacer..

Remarque: pour comprendre le fonctionnement de la sélection, consultez le module Introduction à WebGL 3D avec HTML5 et Babylon.js: Fonctions avancées. Ou jouez avec notre échantillon en ligne, Babylon.js Playground: Exemple de prélèvement.

Ajouter ce code dans le addListeners () une fonction:

canvas.addEventListener ("mousedown", fonction (evt) var pickResult = scene.pick (evt.clientX, evt.clientY, fonction (mesh) if (mesh.name.indexOf ("Sphere0")!!! == || mesh.nom.indexOf ("Box0")! == -1) return true; return false;); if (pickResult.hit) var dir = pickResult.pickedPoint.subtract (scene.activeCamera.position ); dir.normalize (); pickResult.pickedMesh.applyImpulse (dir.scale (1), pickResult.pickedPoint););

Lancez votre code dans votre navigateur préféré. Vous pouvez maintenant cliquer sur vos mailles physiques pour jouer avec elles.

6. Afficher les boîtes englobantes pour mieux comprendre toute l'histoire

Enfin, nous allons créer une scène de débogage pour vous permettre d’afficher / masquer les collisionneurs et d’activer / désactiver les propriétés physiques sur ceux-ci..

Nous allons injecter l'interface utilisateur dans cette div:

Et nous allons utiliser cette fonction pour gérer l'interface utilisateur:

function CreateCollidersHTMLList () var listColliders = document.getElementById («listColliders»); pour (var j = 0; j < meshesColliderList.length; j++)  var newLi = document.createElement(“li”); var chkVisibility = document.createElement('input'); chkVisibility.type = “checkbox”; chkVisibility.name = meshesColliderList[j].name; chkVisibility.id = “colvis” + j; var chkPhysics = document.createElement('input'); chkPhysics.type = “checkbox”; chkPhysics.name = meshesColliderList[j].name; chkPhysics.id = “colphysx” + j; (function (j)  chkVisibility.addEventListener( “click”, function (event)  onChangeVisibility(j, event); , false ); chkPhysics.addEventListener( “click”, function (event)  onChangePhysics(j, event); , false ); )(j) newLi.textContent = meshesColliderList[j].name + “ visibility/physx “; newLi.appendChild(chkVisibility); newLi.appendChild(chkPhysics); listColliders.appendChild(newLi);  function onChangeVisibility(id, event)  if (!meshesColliderList[id].isVisible)  meshesColliderList[id].isVisible = true; meshesColliderList[id].material.alpha = 0.75; meshesColliderList[id].material.ambientColor.r = 1;  else  meshesColliderList[id].isVisible = false;   function onChangePhysics(id, event)  if (!meshesColliderList[id].checkCollisions)  meshesColliderList[id].checkCollisions = true; meshesColliderList[id].setPhysicsState(BABYLON.PhysicsEngine.BoxImpostor,  mass: 0, friction: 0.5, restitution: 0.7 );  else  meshesColliderList[id].checkCollisions = false; meshesColliderList[id].setPhysicsState(BABYLON.PhysicsEngine.NoImpostor);   

Je sais, cela génère une interface utilisateur très laide, mais j'étais trop paresseux pour passer plus de temps dessus. N'hésitez pas à l'améliorer!

Appelez cette nouvelle fonction et lancez le projet Web. Maintenant, par exemple, affichez les collisionneurs 12 et 17:

Vous pouvez également, avec la deuxième case à cocher, activer / désactiver les propriétés physiques. Par exemple, si vous désactivez les propriétés physiques sur le collisionneur 12 et lancez les sphères, elles passeront maintenant à travers ce mur! Ceci est montré dans la capture d'écran suivante comme la sphère entourée du carré rouge:

Vous pouvez jouer avec cet échantillon de débogage directement dans votre navigateur ici: démonstration de Babylon.js Espilit Physicsdebug.

Veuillez également jeter un coup d'œil à cette démo impressionnante construite par Samuel Girardin qui utilise également Oimo.js sur des personnages amusants:

J'espère que vous avez apprécié ce tutoriel! Ne hésitez pas à me cingler sur Twitter pour commenter à ce sujet, ou utilisez le champ commentaires ci-dessous.

Cet article fait partie de la série Web de développement Web de Microsoft. Nous sommes ravis de partager Microsoft Edge et le nouveau Moteur de rendu EdgeHTML avec toi. Obtenez des machines virtuelles gratuites ou testez à distance sur votre appareil Mac, iOS, Android ou Windows @ http://dev.modern.ie/.