BabylonJS - Physics Engine



Babylon.js has plugin system for Physics engine which helps to add interactions to the scene.It shows the collision and bouncing between 2 objects and makes it more like real life interaction.The demo will show the balls colliding with each other and moving around with the collision and later resting.We notice the same behavior with games like billiards,where the player hits the ball with the stick and the balls collide with the other balls and so on.Here, the Physics Engine tries to give a realistic view of balls colliding and bouncing when they hit the ground surface. The engine has classes and APIthat help in applying apply impulse, force, changing velocity, callback functions to be called whenever required and also when we need to perform certain actions if the meshes collide against other meshes.

There are 3 Physics plugins that can be used −

  • Cannon.js
  • Oimo.js
  • Energy.js

Demo

<!doctype html>
<html>
   <head>
      <meta charset = "utf-8">
      <title>BabylonJs - Ball/Ground Demo</title>
      <script type = "text/javascript" src="https://cdn.babylonjs.com/Oimo.js"></script>
      <script src = "babylon.js"></script>	
      <style>
         canvas {width: 100%; height: 100%;}
      </style>
   </head>

   <body>
      <canvas id = "renderCanvas"></canvas>
      <script type = "text/javascript">
         var canvas = document.getElementById("renderCanvas");
         var engine = new BABYLON.Engine(canvas, true);
         var v3 = BABYLON.Vector3;
         
         var createScene = function () {	
            // This creates a basic Babylon Scene object (non-mesh)
            var scene = new BABYLON.Scene(engine);

            var camera = new BABYLON.ArcRotateCamera("Camera", 0.86, 1.37, 250, BABYLON.Vector3.Zero(), scene);
            
            camera.attachControl(canvas);
            camera.maxZ = 5000;
            camera.lowerRadiusLimit = 120;
            camera.upperRadiusLimit = 430;
            camera.lowerBetaLimit =0.75;
            camera.upperBetaLimit =1.58 ;

            new BABYLON.HemisphericLight("hemi", new BABYLON.Vector3(0, 1, 0), scene);

            var randomNumber = function (min, max) {
               if (min == max) {
                  return (min);
               }
               var random = Math.random();
               return ((random * (max - min)) + min);
            };

            var mat = new BABYLON.StandardMaterial("ground", scene);
            var t = new BABYLON.Texture("images/gr1.jpg", scene);
            t.uScale = t.vScale = 10;
            mat.diffuseTexture = t;
            mat.specularColor = BABYLON.Color3.Black();
            
            var g = BABYLON.Mesh.CreateBox("ground", 200, scene);
            
            g.position.y = -20;
            g.position.x = 0
            g.scaling.y = 0.01;
            g.material = mat;	
            
            scene.enablePhysics(new BABYLON.Vector3(0, -10, 0), new BABYLON.OimoJSPlugin());
            
            g.physicsImpostor = new BABYLON.PhysicsImpostor(g, BABYLON.PhysicsImpostor.BoxImpostor, { 
               mass: 0, 
               restitution: 0.9 
            }, scene);
            
            var getPosition = function(y) {
               return new v3(randomNumber(-100, 100), y, randomNumber(-100, 100));
            };
            
            var allspheres = [];
            var y = 50;
            var max = 50;
            
            for (var index = 0; index < max; index++) {
               var redSphere = BABYLON.Mesh.CreateSphere("s" + index, 32, 8, scene);
               redSphere.position = getPosition(y);
               redSphere.physicsImpostor = new BABYLON.PhysicsImpostor(redSphere, BABYLON.PhysicsImpostor.SphereImpostor,{
                  mass: 1, restitution:0.9
               }, scene);
               
               redSphere.physicsImpostor.applyImpulse(new BABYLON.Vector3(1, 2, -1), new BABYLON.Vector3(1, 2, 0));
               
               var redMat = new BABYLON.StandardMaterial("ground", scene);
               redMat.diffuseColor = new BABYLON.Color3(0.4, 0.4, 0.4);
               redMat.specularColor = new BABYLON.Color3(0.4, 0.4, 0.4);
               redMat.emissiveColor = BABYLON.Color3.Red();
               redSphere.material = redMat;
               
               // push all spheres in the allspheres variable
               allspheres.push(redSphere);			
               y += 10; // increment height
            }
            scene.registerBeforeRender(function() {
               allspheres.forEach(function(obj) { 
                  // if the sphers falls down its updated again over here
                  // If object falls
                  if (obj.position.y < -100) {
                     obj.position = getPosition(200);				
                  }
               });
            })
            return scene;
         };
         var scene = createScene();
         engine.runRenderLoop(function() {
            scene.render();
         });
      </script>
   </body>
</html>

Output

The above line of code generates the following output −

Physics engine

In this demo, we have used image images/gr1.jpg. The images are stored in images/ folder locally and are also pasted below for reference. You can download any image of your choice and use in the demo link.

images/gr1.jpg

GR1

Explanation

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

The above line enables the Physics plugin. You can use the plugin of your choice. We have used OimoJsplugin().

g.physicsImpostor = newBABYLON.PhysicsImpostor(g, BABYLON.PhysicsImpostor.BoxImpostor, { 
   mass: 0, 
   restitution: 0.9 
}, scene);

For interaction, Physics engine uses impostor. When applied to impostor, the shape of the object cannot be changed. If changed, a new impostor will have to be created.

For the sphere, we will set the imposter and also added impulse to it for a bounce effect as shown −

redSphere.physicsImpostor = new BABYLON.PhysicsImpostor(
   redSphere, BABYLON.PhysicsImpostor.SphereImpostor, { 
      mass: 1, 
      restitution:0.9
   }, scene
);

redSphere.physicsImpostor.applyImpulse(
   new BABYLON.Vector3(1, 2, -1), 
   new BABYLON.Vector3(1, 2, 0)
);

Parameters for physicsImposter

Consider the following parameters for Physics effects −

Object

Here the object is on which you want to apply the interaction. For example, sphere, box, etc.

Type

Type can be one of the following −

  • BABYLON.PhysicsImpostor.SphereImpostor;
  • BABYLON.PhysicsImpostor.BoxImpostor;
  • BABYLON.PhysicsImpostor.PlaneImpostor;
  • BABYLON.PhysicsImpostor.MeshImpostor;
  • BABYLON.PhysicsImpostor.CylinderImpostor;
  • BABYLON.PhysicsImpostor.ParticleImpostor;
  • BABYLON.PhysicsImpostor.HeightmapImpostor;

Mass

The only mandatory parameter is mass, which is the object's mass in kg. A 0 as a value will create a static impostor - good for floors.

Restitution

This is the amount of force the body will "give back" when colliding. A low value will create no bounce and a value of 1 will be a very bouncy interaction.

scene.registerBeforeRender(function() {
   allspheres.forEach(function(obj) { 
      // if the sphers falls down its updated again over here
      // If object falls
      if (obj.position.y < -100) {
         obj.position = getPosition(200);
      }					
   });
})

The above code brings back the fallen spheres on the ground. It keeps updating the ground for any fallen sphere. Try the above demo in the browser to see the Physics effect.

Advertisements