WebGL Fysikk og Kollisjonsdetektering ved hjelp av Babylon.js og Oimo.js

I dag vil jeg gjerne dele med deg grunnleggende om kollisjoner, fysikk og avgrensningsbokser ved å leke med WebGL Babylon.js-motoren og en fysikkmotorkompani som heter Oimo.js.

Her er den demo vi skal bygge sammen: Babylon.js Espilit Physics demo med Oimo.js.

Du kan starte den i en WebGL-kompatibel nettleser, for eksempel IE11, Firefox, Chrome, Opera, Safari 8 eller Microsoft Edge i Windows 10 Technical Preview, og deretter flytte deg inn i scenen som i et FPS-spill. trykk s nøkkel til å starte noen sfærer / baller og b nøkkelen til å starte noen bokser. Ved å bruke musen, kan du også klikke på en av kulene eller boksene for å bruke litt impulskraft på den.

1. Forstå kollisjoner

Ser på Wikipedia-kollisjonssensjonsdefinisjonen, kan vi lese det: 

Kollisjonsdeteksjon refererer typisk til det beregningsmessige problemet med å oppdage krysset mellom to eller flere objekter. Mens emnet er oftest forbundet med bruk i videospill og annen fysiske simuleringer, det har også applikasjoner i robotikk. I tillegg til å avgjøre om to objekter har kollidert, kan kollisjonsdeteksjonssystemer også beregne tidspunktet for støt (TOI) og rapportere en kontakt manifold (settet av skjæringspunkter).Kollisionsrespons omhandler simulering av hva som skjer når en kollisjon oppdages (se fysikk motor, ragdoll fysikk). Å løse kollisjonssensorproblemer krever omfattende bruk av konsepter fra lineær algebra og beregnings geometri.

La oss nå pakke ut den definisjonen til en kul 3D-scene som vil fungere som vår utgangspunkt for denne opplæringen.

Du kan flytte i dette flotte museet som du ville i den virkelige verden. Du vil ikke falle gjennom gulvet, gå gjennom vegger eller fly. Vi simulerer tyngdekraften. Alt dette virker ganske åpenbart, men det krever en haug med beregning for å simulere det i en 3D-virtuell verden. 

Det første spørsmålet vi må løse når vi tenker på kollisjonsdeteksjon, er hvor komplisert det burde være. Faktisk, å teste om to komplekse masker kolliderer, kan koste mye CPU, enda mer med en JavaScript-motor der det er komplisert å avlaste det på noe annet enn brukergrensesnittet.

For bedre å forstå hvordan vi håndterer denne kompleksiteten, naviger inn på Espilit-museet nær dette skrivebordet:

Du er blokkert ved bordet selv om det ser ut til å være ledig plass til høyre. Er det en feil i vår kollisjonalgoritme? Nei, det er ikke (Babylon.js er fri for feil!). Det er fordi Michel Rousseau, 3D-kunstneren som bygget denne scenen, har gjort dette ved valg. For å forenkle kollisjonsdeteksjonen har han brukt en bestemt collider.

Hva er en Collider?

I stedet for å teste sammenstøtene mot de fullstendige detaljerte maskene, kan du sette dem inn i enkle usynlige geometrier. Disse colliders vil fungere som maskerepresentasjon og vil bli brukt av kollisionsmotoren i stedet. Mesteparten av tiden, vil du ikke se forskjellene, men det vil tillate oss å bruke mye mindre CPU, da matematikken bak det er mye enklere å beregne.

Hver motor støtter minst to typer colliders: the avgrensningsboks og begrensende sfære. Du forstår bedre ved å se på dette bildet:

Utvunnet fra: Datamaskinvisualisering, Ray Tracing, Videospill, Bytte av Bounding Boxes

Denne vakre gule anda er nettverket som skal vises. I stedet for å teste sammenstøtene mot hverandres ansikter, kan vi prøve å sette den inn i den beste begrensende geometrien. I dette tilfellet virker en boks et bedre valg enn en sfære for å fungere som maskerimatøren. Men valget avhenger egentlig av selve nettverket.

La oss gå tilbake til Espilit-scenen og vise det usynlige grenseelementet i en halvtransparent rød farge:

Du kan nå forstå hvorfor du ikke kan bevege seg ved høyre side av pulten. Det er fordi du kolliderer (vel, Babylon.js kameraet kolliderer) med denne boksen. Hvis du vil gjøre det, endrer du bare størrelsen ved å senke bredden slik at den passer perfekt til skrivebordets bredde.

Merk: Hvis du vil begynne å lære Babylon.js, kan du følge gratis kurs på Microsoft Virtual Academy (MVA). For eksempel kan du hoppe direkte til Introduksjon til WebGL 3D med HTML5 og Babylon.js: Bruke Babylon.js for Beginners hvor vi dekker denne kollisjonen delen av Babylon.js. Du kan også se koden i vårt interaktive lekeapparat, Babylon.js lekeplass: Kollisjonssampling.

Basert på kompleksiteten til kollisjons- eller fysikkmotoren finnes det andre typer kollider: kapsel og maske, for eksempel.

Utdrag fra: Komme i gang med Unity - Colliders & UnityScript

kapsel er nyttig for mennesker eller humanoider som det passer bedre til kroppen vår enn en boks eller et kule. mesh er nesten aldri hele nettverket selv, men det er en forenklet versjon av det opprinnelige nettverket du målretter mot, men det er fortsatt mye mer presis enn en boks, en kule eller en kapsel.

2. Lasting av startscenen

For å laste inn vår Espilit-scene har du ulike alternativer:

valg 1: Last ned den fra vårt GitHub-lager, og følg deretter introduksjonen til WebGL 3D med HTML5 og Babylon.js: Laster aktivitetsmodul i vårt MVA-kurs for å lære å laste en .babylon-scene. I utgangspunktet må du være vert for eiendelene og Babylon.js-motoren i en webserver og angi de riktige MIME-typene for .babylon-utvidelsen.

Alternativ 2: Last ned denne forhåndsgjorte Visual Studio-løsningen (.zip-fil).  

Merk: Hvis du ikke er kjent med Visual Studio, ta en titt på denne artikkelen: Webutviklere, Visual Studio kan være et flott gratis verktøy for å utvikle seg med ... Vær også oppmerksom på at Pro-versjonen nå er gratis for mange forskjellige scenarier. Den heter Visual Studio 2013 Community Edition.

Selvfølgelig kan du fortsatt følge denne opplæringen hvis du ikke vil bruke Visual Studio. Her er koden for å laste inn vår scene. Husk at de fleste nettlesere støtter WebGL nå - husk å teste for Internet Explorer, selv på din Mac.

///  var motor; var lerret; var scene; document.addEventListener ("DOMContentLoaded", startGame, feil); funksjon startGame () hvis (BABYLON.Engine.isSupported ()) canvas = document.getElementById ("renderCanvas"); motor = ny BABYLON.Engine (lerret, sant); BABYLON.SceneLoader.Load ("Espilit /", "Espilit.babylon", motor, funksjon (loadedScene) scene = loadedScene; // Vent på teksturer og shaders for å være klar scene.executeWhenReady (funksjon () // Fest kamera til lerretinnganger scene.activeCamera.attachControl (lerret); // Når scenen er lastet, bare registrer en gjengeløkke for å gjøre det motor.runRenderLoop (funksjon () scene.render ();););, funksjon (fremgang) // Å gjøre: Gi tilbakemeldinger til brukeren);  

Ved hjelp av dette materialet vil du bare ha nytte av den innebygde kollisionsmotoren til Babylon.js. Faktisk gjør vi en forskjell mellom vår kollisionsmotor og en fysikkmotor. 

Kollisjonsmotoren er hovedsakelig dedikert til kameraet som interagerer med scenen. Du kan aktivere tyngdekraft eller ikke på kameraet, og du kan aktivere checkCollision alternativ på kameraet og på de forskjellige maskene. 

Kollisjonsmotoren kan også hjelpe deg å vite om to masker kolliderer. Men det er alt (dette er allerede mye, faktisk!). Kollisjonsmotoren vil ikke generere handlinger, kraft eller impuls etter at to Babylon.js-objekter kolliderer. Du trenger en fysikkmotor for det å bringe livet til objektene.

Måten vi har integrert fysikk i Babylon.js er via en plugin-mekanisme. Du kan lese mer om det her: Legge til din egen fysikkmotor plugin til Babylon.js. Vi støtter to open-source fysikk motorer: Cannon.js og Oimo.js. Oimo er nå den foretrukne standardfysikkmotoren.

Hvis du har valgt alternativ 1 for å laste inn scenen, må du laste ned Oimo.js fra vår GitHub. Det er en litt oppdatert versjon vi har laget for å bedre støtte Babylon.js. Hvis du har valgt alternativ 2, er den allerede referert og tilgjengelig i VS-løsningen under skript mappe.

3. Aktivering av fysikkstøtte i scenen og omforming av collider til fysikforfølgere

Det første du må gjøre er å aktivere fysikk på scenen. For det, vennligst legg til disse kodelinjene:

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

Du setter opp gravitasjonsnivået (-10 på Y-aksen i denne prøvekoden, som er mer eller mindre som det vi har på Jorden) og fysikkmotoren du vil bruke. Vi bruker Oimo.js, men kommentert linje viser hvordan du bruker Cannon.js.

Nå må vi iterere gjennom alle ikke-synlige kollider som brukes av kollisionsmotoren og aktivere fysikkegenskaper på den. For det trenger du bare å finne alle masker hvor checkCollisions er satt til ekte men ikke synlig i scenen:

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

Vennligst erklære meshesColliderList også:

var meshesColliderList = [];

Og vi er ferdige! Vi er klare til å kaste noen objekter i vår scene og sette mye rot i dette vakre, men altfor rolige museet.

4. Opprette sfærer og bokser med fysikkstatene

Vi skal nå legge til noen sfærer (med Amiga-tekstur) og noen bokser (med en trestruktur) til scenen. 

Disse maskene vil ha fysikkstatus sett. For eksempel betyr dette at de vil sprette på gulvet hvis du starter dem i luften, spretter mellom dem etter at en kollisjon har blitt oppdaget, og så videre. Fysikkmotoren trenger å vite hvilken slags bedrager du vil bruke til masken (fly, sfære eller boks i dag), samt masse- og friksjonsegenskapene.

Hvis du har valgt alternativ 1, kan du laste ned de to teksturene her.

Legg til denne koden til prosjektet ditt:

funksjon CreateMaterials () materialAmiga = new BABYLON.StandardMaterial ("amiga", scene); materialAmiga.diffuseTexture = ny BABYLON.Texture ("assets / amiga.jpg", scene); materialAmiga.emissiveColor = ny BABYLON.Color3 (0,5, 0,5, 0,5); materialAmiga.diffuseTexture.uScale = 5; materialAmiga.diffuseTexture.vScale = 5; materialWood = nytt BABYLON.StandardMaterial ("wood", scene); materialWood.diffuseTexture = ny BABYLON.Texture ("assets / wood.jpg", scene); materialWood.emissiveColor = nytt BABYLON.Color3 (0,5, 0,5, 0,5);  funksjon addListeners () window.addEventListener ("keydown", funksjon (evt) // s for sfære hvis (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 );   ); 

Du kan se at boksene er tyngre enn kulene med en faktor 4.

Merk: Hvis du trenger å forstå hvordan materialet fungerer i Babylon.js, se modulen Introduksjon til WebGL 3D med HTML5 og Babylon.js: Forstå materialer og innganger, eller lek med vår dedikerte Lekeplass, Babylon.js Lekeplass: Materialeprøve.

Legg til disse to kodelinjene etter scene.enablePhysics linje:

CreateMaterials (); addListeners ();

Og lansere webprosjektet. Naviger til sentrum av museet og trykk på s eller b nøkler. Du får dette morsomme resultatet:

5. Legge til plukkingstøtte for å klikke på masker

La oss legge til en annen kul funksjon: muligheten til å klikke på en av objektene for å kaste den bort. For det må du sende en stråle fra 2D-koordinatene til musen inne i 3D-scenen, kontroller om denne strålen berører et av de interessante masker, og hvis så, bruk en impulskraft på den for å prøve å flytte den.

Merk: For å forstå hvordan plukkingen fungerer, vennligst se MVA-modulen Introduksjon til WebGL 3D med HTML5 og Babylon.js: Avanserte funksjoner. Eller spill med vår online prøve, Babylon.js Lekeplass: Plukke prøve.

Legg til denne koden i addListeners () funksjon:

lerret || mesh.name.indexOf ("Box0")! == -1) return true; return false;), hvis (pickResult.hit) var dir = pickResult.pickedPoint.subtract (scene.activeCamera.position ); dir.normalize (); pickResult.pickedMesh.applyImpulse (dir.scale (1), pickResult.pickedPoint););

Start koden din i din favoritt nettleser. Du kan nå klikke på dine fysiske masker for å leke med dem.

6. Vise Bounding Boxes å bedre forstå hele historien

Til slutt skal vi lage en feilsøkingsscene slik at du kan vise / skjule colliders og aktivere / deaktivere fysikkegenskapene på dem.

Vi skal injisere brukergrensesnittet i denne diven:

Og vi bruker denne funksjonen til å håndtere brukergrensesnittet:

funksjon CreateCollidersHTMLList () var listColliders = document.getElementById ("listColliders"); for (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);   

Jeg vet, det genererer et veldig stygg brukergrensesnitt, men jeg var for lat til å bruke mer tid på det. Du er velkommen til å forbedre den!

Ring denne nye funksjonen og lansere webprosjektet. Nå viser du for eksempel kolliderne 12 og 17:

Du kan også, med den andre boksen, aktivere / deaktivere fysikkegenskapene. For eksempel, hvis du deaktiverer fysikkegenskapene på kollider 12 og starter sfærene, vil de nå gå gjennom denne veggen! Dette vises i følgende skjermbilde som sfæren omgitt av den røde firkanten:

Du kan spille med denne debugging-prøven direkte i nettleseren din her: Babylon.js Espilit Physicsdebug demo.

Ta også en titt på denne fantastiske demoen, bygget av Samuel Girardin, som også bruker Oimo.js på noen morsomme tegn:

Jeg håper du har hatt denne opplæringen! Ta gjerne på meg på Twitter for å kommentere det, eller bruk kommentarfeltet nedenfor.

Denne artikkelen er en del av web dev-teknologiserien fra Microsoft. Vi er glade for å dele Microsoft Edge og den nye EdgeHTML rendering motor med deg. Få gratis virtuelle maskiner eller test eksternt på Mac, IOS, Android eller Windows-enheten @ http://dev.modern.ie/.