Fisica WebGL e rilevamento delle collisioni utilizzando Babylon.js e Oimo.js

Oggi vorrei condividere con voi le basi delle collisioni, della fisica e dei riquadri di delimitazione giocando con il motore WebGL Babylon.js e un compagno del motore fisico denominato Oimo.js.

Ecco la demo che costruiremo insieme: demo di Babylon.js Espilit Physics con Oimo.js.

È possibile avviarlo in un browser compatibile con WebGL, ad esempio IE11, Firefox, Chrome, Opera, Safari 8 o Microsoft Edge in Windows 10 Technical Preview, per poi spostarsi all'interno della scena come in un gioco FPS. premi il S chiave per lanciare alcune sfere / sfere e il B chiave per lanciare alcune scatole. Usando il tuo mouse, puoi anche cliccare su una delle sfere o caselle per applicare una forza d'impulso su di essa.

1. Capire le collisioni

Guardando la definizione di rilevamento delle collisioni di Wikipedia, possiamo leggere che: 

Rilevamento delle collisioni in genere si riferisce al problema computazionale di rilevamento dell'intersezione di due o più oggetti. Mentre l'argomento è più spesso associato al suo utilizzo in videogiochi e altro simulazioni fisiche, ha anche applicazioni in robotica. Oltre a determinare se due oggetti sono entrati in collisione, i sistemi di rilevamento delle collisioni possono anche calcolare il tempo di impatto (TOI) e segnalare un collettore di contatti (l'insieme di punti intersecanti).Risposta alla collisione si occupa di simulare ciò che accade quando viene rilevata una collisione (vedi motore fisico, fisica ragdoll). Risolvere i problemi di rilevamento delle collisioni richiede un ampio uso dei concetti di algebra lineare e geometria computazionale.

Disimballiamo ora quella definizione in una fantastica scena 3D che fungerà da base di partenza per questo tutorial.

Puoi muoverti in questo grande museo come faresti nel mondo reale. Non cadrai attraverso il pavimento, camminerai attraverso i muri o volerai. Stiamo simulando la gravità. Tutto ciò sembra abbastanza ovvio, ma richiede una serie di calcoli per simularlo in un mondo virtuale in 3D. 

La prima domanda che dobbiamo risolvere quando pensiamo al rilevamento delle collisioni è quanto dovrebbe essere complessa. In effetti, testare se due mesh complesse sono in collisione potrebbe costare un sacco di CPU, ancora di più con un motore JavaScript dove è complesso scaricarlo su qualcosa di diverso dal thread dell'interfaccia utente.

Per capire meglio come gestiamo questa complessità, naviga nel museo Espilit vicino a questo banco:

Sei bloccato dal tavolo anche se sembra esserci dello spazio disponibile sulla destra. È un bug nel nostro algoritmo di collisione? No, non lo è (Babylon.js è privo di bug!). È perché Michel Rousseau, l'artista 3D che ha costruito questa scena, lo ha fatto per scelta. Per semplificare il rilevamento delle collisioni, ha utilizzato un collisore specifico.

Cos'è un Collider?

Anziché testare le collisioni con le mesh dettagliate complete, puoi inserirle in semplici geometrie invisibili. Questi collider fungeranno da rappresentazione mesh e saranno invece utilizzati dal motore di collisione. La maggior parte delle volte non vedrai le differenze ma ci permetterà di usare molto meno CPU, dato che la matematica dietro è molto più semplice da calcolare.

Ogni motore supporta almeno due tipi di collisori: il rettangolo di selezione e il sfera di delimitazione. Farai meglio a capire guardando questa immagine:

Estratto da: Visualizzazione di computer, Ray Tracing, Videogiochi, Sostituzione di scatole di delimitazione

Questa bella anatra gialla è la maglia da visualizzare. Anziché testare le collisioni su ciascuna delle sue facce, possiamo provare ad inserirla nella migliore geometria di delimitazione. In questo caso, una scatola sembra una scelta migliore di una sfera per agire come l'impostore della mesh. Ma la scelta dipende molto dalla mesh stessa.

Torniamo alla scena Espilit e visualizziamo l'elemento di contorno invisibile in un colore rosso semitrasparente:

Ora puoi capire perché non puoi spostarti dal lato destro della scrivania. È perché ti stai scontrando (beh, la telecamera Babylon.js è in collisione) con questa scatola. Se vuoi farlo, modifica semplicemente la sua dimensione abbassando la larghezza per adattarla perfettamente alla larghezza della scrivania.

Nota: se desideri iniziare a imparare Babylon.js, puoi seguire il corso di formazione gratuito presso Microsoft Virtual Academy (MVA). Ad esempio, puoi passare direttamente a Introduzione a WebGL 3D con HTML5 e Babylon.js: Uso di Babylon.js per principianti in cui trattiamo questa parte di collisione di Babylon.js. Puoi anche dare un'occhiata al codice all'interno del nostro strumento di giochi interattivi, il playground Babylon.js: campione di collisioni.

In base alla complessità del motore di collisione o di fisica, sono disponibili altri tipi di collider: il capsula e il maglia, per esempio.

Estratto da: Introduzione a Unity - Collider & UnityScript

Capsula è utile per gli umani o umanoidi poiché si adatta meglio al nostro corpo di una scatola o di una sfera. Maglia non è quasi mai la mesh completa in se stessa, ma piuttosto una versione semplificata della mesh originale a cui miri, ma è ancora molto più precisa di una scatola, una sfera o una capsula.

2. Caricamento della scena iniziale

Per caricare la nostra scena Espilit, hai varie opzioni:

opzione 1: Scaricalo dal nostro repository GitHub, quindi segui l'Introduzione a WebGL 3D con HTML5 e Babylon.js: carica il modulo Risorse del nostro corso MVA per imparare come caricare una scena .babylon. Fondamentalmente, è necessario ospitare le risorse e il motore Babylon.js in un server Web e impostare i tipi MIME appropriati per l'estensione .babylon.

opzione 2: Scarica questa soluzione di Visual Studio in anteprima (file .zip).  

Nota: se non hai familiarità con Visual Studio, dai un'occhiata a questo articolo: Sviluppatori web, Visual Studio potrebbe essere un ottimo strumento gratuito da sviluppare con ... Si noti inoltre che la versione Pro è ora gratuita per molti scenari diversi. Si chiama Visual Studio 2013 Community Edition.

Naturalmente, puoi continuare a seguire questo tutorial se non vuoi utilizzare Visual Studio. Ecco il codice per caricare la nostra scena. Ricorda che la maggior parte dei browser supporta ora WebGL, ricorda di provare per Internet Explorer anche sul tuo Mac.

///  motore var; tela var; scena var; 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", engine, function (loadedScene) scene = loadedScene; // Attendi che textures e shader siano pronti scene.executeWhenReady (function () // Allega camera input di canvas scene.activeCamera.attachControl (canvas); // Una volta caricata la scena, registra un loop di rendering per renderlo engine.runRenderLoop (function () scene.render ();););, function (progress) // To do: dare un feedback di progresso all'utente);  

Usando questo materiale, beneficerai solo del motore di collisione incorporato di Babylon.js. In effetti, stiamo facendo la differenza tra il nostro motore di collisione e un motore fisico. 

Il motore di collisione è principalmente dedicato alla fotocamera che interagisce con la scena. È possibile abilitare la gravità o meno sulla fotocamera e abilitare il checkCollision opzione sulla fotocamera e sulle varie maglie. 

Il motore di collisione può anche aiutarti a sapere se due maglie si scontrano. Ma questo è tutto (questo è già molto, infatti!). Il motore di collisione non genererà azioni, forza o impulso dopo che due oggetti Babylon.js si sono scontrati. Hai bisogno di un motore fisico per far vivere gli oggetti.

Il modo in cui abbiamo integrato la fisica in Babylon.js è tramite un meccanismo di plugin. Puoi leggere ulteriori informazioni al riguardo qui: Aggiunta del tuo plugin per il motore fisico a Babylon.js. Supportiamo due motori fisici open source: Cannon.js e Oimo.js. Oimo è ora il motore fisico predefinito preferito.

Se hai scelto l'Opzione 1 per caricare la scena, devi scaricare Oimo.js dal nostro GitHub. È una versione leggermente aggiornata che abbiamo sviluppato per supportare meglio Babylon.js. Se hai scelto l'Opzione 2, è già referenziato e disponibile nella soluzione VS sotto script cartella.

3. Abilitazione del supporto fisico nella scena e trasformazione dei collider in impostori di fisica

La prima cosa da fare è abilitare la fisica sulla scena. Per questo, per favore aggiungi queste righe di codice:

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

Stai impostando il livello di gravità (-10 sull'asse Y in questo codice di esempio, che è più o meno come quello che abbiamo sulla Terra) e il motore fisico che vorresti usare. Useremo Oimo.js, ma la linea commentata mostra come usare Cannon.js.

Ora, abbiamo bisogno di scorrere tutti i collisori non visibili usati dal motore di collisione e attivare le proprietà fisiche su di esso. Per questo, devi semplicemente trovare tutte le maglie dove checkCollisions è impostato per vero ma non visibile nella scena:

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

Si prega di dichiarare il meshesColliderList anche:

var meshesColliderList = [];

E abbiamo finito! Siamo pronti a gettare alcuni oggetti nella nostra scena e mettere un sacco di confusione in questo bellissimo museo, ma troppo tranquillo.

4. Creazione di sfere e scatole con stati fisici

Ora aggiungeremo alcune sfere (con una trama Amiga) e alcune caselle (con una trama di legno) alla scena. 

Queste mesh avranno lo stato fisico impostato. Ad esempio, questo significa che rimbalzeranno sul pavimento se li lanci in aria, rimbalzando tra di loro dopo che una collisione è stata rilevata, e così via. Il motore fisico deve sapere quale tipo di impostore ti piacerebbe utilizzare per la mesh (piano, sfera o riquadro oggi), così come le proprietà di massa e di attrito.

Se hai scelto l'Opzione 1, puoi scaricare qui le due trame.

Aggiungi questo codice al tuo progetto:

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

Puoi vedere che le scatole sono più pesanti delle sfere di un fattore di 4.

Nota: se hai bisogno di capire come funziona il materiale in Babylon.js, guarda il modulo Introduzione a WebGL 3D con HTML5 e Babylon.js: Comprensione di materiali e input, o gioca con il nostro campione di Playground dedicato, Babylon.js Playground: Materiali campione.

Aggiungi queste due righe di codice dopo il scene.enablePhysics linea:

CreateMaterials (); addListeners ();

E lancia il progetto web. Passare al centro del museo e premere il S o B chiavi. Otterrai questo risultato divertente:

5. Aggiunta di Picking Support a Fare clic su Mesh

Aggiungiamo un'altra funzione interessante: la possibilità di fare clic su uno degli oggetti per buttarlo via. Per questo, è necessario inviare un raggio dalle coordinate 2D del mouse all'interno della scena 3D, verificare se questo raggio tocca una delle maglie interessanti e, in tal caso, applicare una forza di impulso su di esso per provare a spostarlo.

Nota: per capire come funziona il picking, si prega di visualizzare il modulo MVA Introduzione a WebGL 3D con HTML5 e Babylon.js: Funzioni avanzate. Oppure gioca con il nostro campione online, Babylon.js Playground: Picking sample.

Aggiungi questo codice nel addListeners () funzione:

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););

Avvia il tuo codice nel tuo browser preferito. Ora puoi fare clic sulle tue mesh fisiche per giocare con loro.

6. Visualizzazione delle caselle di delimitazione per comprendere meglio l'intera storia

Infine, creeremo una scena di debug per consentire di mostrare / nascondere i collisori e attivare / disattivare le proprietà fisiche su di essi.

Inseriremo l'interfaccia utente in questo div:

E useremo questa funzione per gestire l'interfaccia utente:

function CreateCollidersHTMLList () var listColliders = document.getElementById ("listColliders"); per (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 so, genera un'interfaccia utente molto brutta, ma ero troppo pigro per dedicare più tempo a questo. Sentiti libero di migliorarlo!

Chiama questa nuova funzione e avvia il progetto web. Ora, ad esempio, visualizza i collisori 12 e 17:

È anche possibile, con la seconda casella di controllo, abilitare / disabilitare le proprietà fisiche. Ad esempio, se disabiliti le proprietà fisiche sul collider 12 e lanci le sfere, ora attraverseranno questo muro! Questo è mostrato nello screenshot seguente come la sfera circondata dal quadrato rosso:

Puoi giocare con questo esempio di debug direttamente nel tuo browser qui: Demo di Babylon.js Espilit Physicsdebug.

Dai anche un'occhiata a questa fantastica demo realizzata da Samuel Girardin che usa anche Oimo.js su alcuni personaggi divertenti:

Spero ti sia piaciuto questo tutorial! Sentiti libero di mandarmi un ping su Twitter per commentare, o usa il campo dei commenti qui sotto.

Questo articolo fa parte della serie di web dev tech di Microsoft. Siamo entusiasti di condividere Microsoft Edge e il nuovo Motore di rendering EdgeHTML con te. Ottieni macchine virtuali gratuite o test in remoto sul tuo dispositivo Mac, iOS, Android o Windows @ http://dev.modern.ie/.