Física de WebGL y detección de colisiones usando Babylon.js y Oimo.js

Hoy, me gustaría compartir con ustedes los conceptos básicos de colisiones, física y cuadros de límites jugando con el motor WebGL Babylon.js y un compañero del motor de física llamado Oimo.js.

Aquí está la demostración que vamos a construir juntos: Demo de Babylon.js Espilit Physics con Oimo.js.

Puede iniciarlo en un navegador compatible con WebGL, como IE11, Firefox, Chrome, Opera, Safari 8 o Microsoft Edge en Windows 10 Technical Preview, y luego moverse dentro de la escena como en un juego de FPS. presione el s clave para lanzar algunas esferas / bolas y la segundo Clave para lanzar algunas cajas. Usando el mouse, también puede hacer clic en una de las esferas o cuadros para aplicarle algo de fuerza de impulso..

1. Entendiendo las colisiones

En cuanto a la definición de detección de colisiones de Wikipedia, podemos leer que: 

Detección de colisiones típicamente se refiere al problema computacional de detectar la intersección de dos o más objetos. Si bien el tema se asocia más a menudo con su uso en videojuegos y otra simulaciones físicas, también tiene aplicaciones en robótica. Además de determinar si dos objetos han colisionado, los sistemas de detección de colisiones también pueden calcular el tiempo de impacto (TOI) e informar una variedad de contactos (el conjunto de puntos de intersección).Respuesta de colisión se ocupa de simular lo que sucede cuando se detecta una colisión (ver motor de física, física ragdoll). Resolver problemas de detección de colisiones requiere el uso extensivo de conceptos de álgebra lineal y geometría Computacional.

Ahora desempaquetemos esa definición en una escena 3D genial que actuará como nuestra base de inicio para este tutorial.

Puedes moverte en este gran museo como lo harías en el mundo real. No caerás por el suelo, caminarás por las paredes o volarás. Estamos simulando la gravedad. Todo eso parece bastante obvio, pero requiere un montón de cálculos para simular eso en un mundo virtual 3D. 

La primera pregunta que debemos resolver cuando pensamos en la detección de colisiones es cuán complejo debe ser. De hecho, probar si dos mallas complejas chocan podría costar una gran cantidad de CPU, incluso más con un motor de JavaScript donde es complejo descargar eso en otra cosa que no sea el subproceso de la interfaz de usuario.

Para comprender mejor cómo gestionamos esta complejidad, navegue hasta el museo Espilit cerca de este escritorio:

Está bloqueado por la mesa, incluso si parece que hay espacio disponible a la derecha. ¿Es un error en nuestro algoritmo de colisión? No, no lo es (Babylon.js está libre de errores). Es porque Michel Rousseau, el artista 3D que construyó esta escena, lo ha hecho por elección. Para simplificar la detección de colisiones, ha utilizado un colisionador específico.

Que es un colisionador?

En lugar de probar las colisiones contra las mallas detalladas completas, puede colocarlas en simples geometrías invisibles. Esos colisionadores actuarán como la representación de malla y serán usados ​​por el motor de colisión en su lugar. La mayoría de las veces, no verá las diferencias, pero nos permitirá usar mucho menos CPU, ya que la matemática subyacente es mucho más sencilla de calcular..

Cada motor soporta al menos dos tipos de colisionadores: el cuadro delimitador y el esfera delimitadora. Lo entenderás mejor mirando esta imagen:

Extraído de: Visualización por computadora, Trazado de rayos, Videojuegos, Reemplazo de cajas delimitadoras

Este hermoso pato amarillo es la malla que se mostrará. En lugar de probar las colisiones contra cada una de sus caras, podemos intentar insertarlo en la mejor geometría de delimitación. En este caso, una caja parece una mejor opción que una esfera para actuar como impostor de malla. Pero la elección realmente depende de la propia malla..

Regresemos a la escena Espilit y mostremos el elemento delimitador invisible en un color rojo semitransparente:

Ahora puedes entender por qué no puedes moverte por el lado derecho del escritorio. Es porque estás chocando (bueno, la cámara Babylon.js está chocando) con esta caja. Si desea hacerlo, simplemente cambie su tamaño reduciendo el ancho para que se ajuste perfectamente al ancho del escritorio.

Nota: si desea comenzar a aprender Babylon.js, puede seguir el curso de capacitación gratuito en Microsoft Virtual Academy (MVA). Por ejemplo, puede saltar directamente a Introducción a WebGL 3D con HTML5 y Babylon.js: usando Babylon.js para principiantes, donde cubrimos esta parte de colisión de Babylon.js. También puede consultar el código dentro de nuestra herramienta de juegos interactivos, Babylon.js playground: muestra de colisiones.

Según la complejidad de la colisión o el motor de física, hay otros tipos de colectores disponibles: el cápsula y el malla, por ejemplo.

Extraído de: Introducción a Unity - Coleccionistas y UnityScript

Cápsula es útil para humanos o humanoides, ya que se ajusta mejor a nuestro cuerpo que una caja o una esfera. Malla casi nunca es la malla completa en sí misma, sino que es una versión simplificada de la malla original a la que te diriges, pero aún es mucho más precisa que una caja, una esfera o una cápsula.

2. Cargando la escena inicial

Para cargar nuestra escena Espilit, tienes varias opciones:

Opción 1: Descárguelo desde nuestro repositorio GitHub y luego siga la Introducción a WebGL 3D con HTML5 y Babylon.js: Módulo de carga de activos de nuestro curso MVA para aprender cómo cargar una escena .babylon. Básicamente, debe alojar los activos y el motor Babylon.js en un servidor web y configurar los tipos MIME adecuados para la extensión .babylon.

opcion 2: Descargue esta solución de Visual Studio premade (archivo .zip).  

Nota: Si no está familiarizado con Visual Studio, eche un vistazo a este artículo: desarrolladores web, Visual Studio podría ser una gran herramienta gratuita para desarrollar con ... Tenga en cuenta también que la versión Pro ahora es gratuita para muchos escenarios diferentes. Se llama Visual Studio 2013 Community Edition..

Por supuesto, aún puedes seguir este tutorial si no quieres usar Visual Studio. Aquí está el código para cargar nuestra escena. Recuerde que la mayoría de los navegadores son compatibles con WebGL ahora, recuerde probar para Internet Explorer incluso en su Mac.

///  motor var lienzo var; var escena; document.addEventListener ("DOMContentLoaded", startGame, false); function startGame () if (BABYLON.Engine.isSupported ()) canvas = document.getElementById ("renderCanvas"); engine = new BABYLON.Engine (canvas, true); BABYLON.SceneLoader.Load ("Espilit /", "Espilit.babylon", motor, función (loadedScene) scene = loadedScene; // Espere a que las texturas y los sombreadores estén listos scene.executeWhenReady (function () // Attach camera a las entradas de lienzo scene.activeCamera.attachControl (canvas); // Una vez que se haya cargado la escena, simplemente registre un bucle de render para renderizar engine.runRenderLoop (function () scene.render ();););, función (progreso) // Para: dar retroalimentación de progreso al usuario);  

Usando este material, solo se beneficiará del motor de colisión incorporado de Babylon.js. De hecho, estamos haciendo una diferencia entre nuestro motor de colisión y un motor de física.. 

El motor de colisión está dedicado principalmente a la cámara que interactúa con la escena. Puede activar o no la gravedad en la cámara, y puede activar la checkCollision Opción en la cámara y en las distintas mallas.. 

El motor de colisión también puede ayudarlo a saber si dos mallas están chocando. Pero eso es todo (¡esto ya es mucho, de hecho!). El motor de colisión no generará acciones, fuerza o impulso después de que dos objetos Babylon.js estén colisionando. Necesitas un motor de física para dar vida a los objetos..

La forma en que hemos estado integrando la física en Babylon.js es a través de un mecanismo de complemento. Puede leer más sobre eso aquí: Agregar su propio complemento de motor de física a Babylon.js. Apoyamos dos motores de física de código abierto: Cannon.js y Oimo.js. Oimo es ahora el motor de física predeterminado preferido.

Si ha elegido la Opción 1 para cargar la escena, debe descargar Oimo.js desde nuestro GitHub. Es una versión ligeramente actualizada que hemos hecho para brindar un mejor soporte a Babylon.js. Si ha elegido la Opción 2, ya está referenciada y disponible en la solución VS bajo el guiones carpeta.

3. Habilitando el soporte de física en la escena y transformando colisionadores en impostores de física

Lo primero que hay que hacer es habilitar la física en la escena. Para eso, por favor agregue estas líneas de código:

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

Estás configurando el nivel de gravedad (-10 en el eje Y en este código de ejemplo, que es más o menos parecido a lo que tenemos en la Tierra) y el motor de física que le gustaría usar. Usaremos Oimo.js, pero la línea comentada muestra cómo usar Cannon.js.

Ahora, debemos recorrer todos los colisionadores no visibles que utiliza el motor de colisión y activar las propiedades físicas en él. Para eso, simplemente necesitas encontrar todas las mallas donde checkCollisions se establece en cierto pero no visible en la escena:

para (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]);  

Por favor declare el meshesColliderList además:

var meshesColliderList = [];

¡Y hemos terminado! Estamos listos para lanzar algunos objetos en nuestra escena y poner mucho desorden en este museo hermoso pero demasiado tranquilo..

4. Creando esferas y cajas con estados de física

Ahora vamos a agregar algunas esferas (con una textura Amiga) y algunas cajas (con una textura de madera) a la escena.. 

Estas mallas tendrán estado físico establecido. Por ejemplo, esto significa que rebotarán en el suelo si los lanzas al aire, rebotan entre ellos después de que se detecte una colisión, y así sucesivamente. El motor de física necesita saber qué tipo de impostor le gustaría usar para la malla (plano, esfera o caja hoy), así como las propiedades de masa y fricción.

Si ha elegido la Opción 1, puede descargar las dos texturas aquí.

Agrega este código a tu proyecto:

function CreateMaterials () materialAmiga = new BABYLON.StandardMaterial ("amiga", escena); materialAmiga.diffuseTexture = new BABYLON.Texture ("asset / amiga.jpg", escena); materialAmiga.emissiveColor = new BABYLON.Color3 (0.5, 0.5, 0.5); materialAmiga.diffuseTexture.uScale = 5; materialAmiga.diffuseTexture.vScale = 5; materialWood = new BABYLON.StandardMaterial ("wood", escena); materialWood.diffuseTexture = new BABYLON.Texture ("asset / wood.jpg", escena); materialWood.emissiveColor = new BABYLON.Color3 (0.5, 0.5, 0.5);  function addListeners () window.addEventListener ("keydown", function (evt) // s para sphere if (evt.keyCode == 83) for (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 );   ); 

Puedes ver que las cajas son más pesadas que las esferas por un factor de 4.

Nota: si necesita comprender cómo funciona el material en Babylon.js, vea el módulo Introducción a WebGL 3D con HTML5 y Babylon.js: Entender los materiales e insumos, o juegue con nuestra muestra dedicada de Playground, Babylon.js Playground: muestra de materiales.

Agregue estas dos líneas de código después de la scene.enablePhysics línea:

CreateMaterials (); addListeners ();

Y lanzar el proyecto web. Navega hasta el centro del museo y pulsa el botón s o segundo llaves. Obtendrás este divertido resultado:

5. Agregando Picking Support para hacer clic en las mallas

Agreguemos otra característica interesante: la capacidad de hacer clic en uno de los objetos para desecharlo. Para eso, necesita enviar un rayo desde las coordenadas 2D del mouse dentro de la escena 3D, verificar si este rayo toca una de las mallas interesantes, y si es así, aplique una fuerza de impulso para tratar de moverlo.

Nota: para comprender cómo funciona el picking, vea el módulo MVA Introducción a WebGL 3D con HTML5 y Babylon.js: Características avanzadas. O juegue con nuestra muestra en línea, Babylon.js Playground: Picking sample.

Agregue este código en el addListeners () función:

canvas.addEventListener ("mousedown", function (evt) var pickResult = scene.pick (evt.clientX, evt.clientY, function (mesh) if (mesh.name.indexOf ("Sphere0")! == -1 || mesh.name.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););

Inicie su código en su navegador favorito. Ahora puedes hacer clic en tus mallas físicas para jugar con ellas..

6. Visualización de los cuadros delimitadores para comprender mejor la historia completa

Finalmente, vamos a crear una escena de depuración para permitirle mostrar / ocultar los colectores y activar / desactivar las propiedades físicas en ellos.

Vamos a inyectar la interfaz de usuario en este div:

Y usaremos esta función para manejar la interfaz de usuario:

function CreateCollidersHTMLList () var listColliders = document.getElementById (“listColliders”); para (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);   

Lo sé, genera una IU muy fea, pero era demasiado perezosa para dedicarle más tiempo. Siéntete libre de mejorarlo.!

Llama a esta nueva función y lanza el proyecto web. Ahora, por ejemplo, muestra los colisionadores 12 y 17:

También puede, con la segunda casilla de verificación, habilitar / deshabilitar las propiedades físicas. Por ejemplo, si desactivas las propiedades físicas en el colisionador 12 y lanzas las esferas, ¡ahora atravesarán este muro! Esto se muestra en la siguiente captura de pantalla como la esfera rodeada por el cuadrado rojo:

Puedes jugar con esta muestra de depuración directamente en tu navegador aquí: Babylon.js Espilit Physicsdebug demo.

Por favor, también eche un vistazo a esta impresionante demostración construida por Samuel Girardin que también utiliza Oimo.js en algunos personajes divertidos:

Espero que hayas disfrutado este tutorial! Siéntase libre de enviarme un mensaje de Twitter para comentar al respecto, o use el campo de comentarios a continuación..

Este artículo es parte de la serie web dev tech de Microsoft. Estamos muy contentos de compartir Microsoft Edge y lo nuevo Motor de renderizado EdgeHTML con usted. Obtenga máquinas virtuales gratuitas o realice pruebas a distancia en su dispositivo Mac, iOS, Android o Windows @ http://dev.modern.ie/.