Advanced Physics Features

The Heightmap

One of the best way of interacting with a ground object is the Heightmap impostor (supported currently only with the CannonJS plugin).

A heightmap is not a mesh impostor. It is possible that objects coming from the side will not collide with it. The heightmap impostor takes the height Y value at a certain point in a mesh and sets a collision point. To understand what a heightmap impostor is, think of a regular house with a triangle roof. If we set the heightmap impostor to the house, the only part that will have collision detection is the roof. Anything below the roof will be ignored, including the walls.

On the positive side, a heightmap can collide with most other objects, as opposed to the mesh impostor which only collides against spheres. Performance is also much better with a heightmap than with a mesh impostor.

There are certain conditions in which a heightmap can be initialized:

  • It must be square (x === z). The most important values are the y values in each point of the heightmap.
  • It cannot contain holes or missing textures
  • It is recommended that the heightmap be generated from a GroundMesh, generated from a heightmap image

To create a ground from an image-based ground mesh:

var ground = BABYLON.Mesh.CreateGroundFromHeightMap("ground", "textures/worldHeightMap.jpg", 200, 200, 50, 0, 30, scene, false, function () {
ground.physicsImpostor = new BABYLON.PhysicsImpostor(ground, BABYLON.PhysicsImpostor.HeightmapImpostor, { mass: 0 });
});

To create a heightmap from a square ribbon:

var exponentialPath = function (p) {
var path = [];
for (var i = -50; i <= 50; i++) {
path.push(new BABYLON.Vector3(p-50, (Math.sin(p / 3) * 10 * Math.exp((i - p) / 100) + i / 3), i));
}
return path;
};
// let's populate arrayOfPaths with all these different paths
var arrayOfPaths = [];
for (var p = 0; p <= 100; p++) {
arrayOfPaths[p] = exponentialPath(p);
}
var mesh = BABYLON.Mesh.CreateRibbon("ribbon", arrayOfPaths, false, false, 0, scene);
mesh.physicsImpostor = new BABYLON.PhysicsImpostor(mesh, BABYLON.PhysicsImpostor.HeightmapImpostor, { mass: 0, friction:1, restitution: 0.5 });

A demo for both of these examples can be found here -

Creating Ground From An Image-Based Ground Mesh Creating A Heightmap From A Square Ribbon

Mesh Impostor

A mesh impostor wraps a complex mesh with a physics body, allowing exact collision detection with the object. As opposed to the heightmap impostor, a mesh impostor has the entire mesh covered.

A mesh impostor is only available with cannon.js, and only collides against spheres.

Regarding performance - you will notice that the mesh impostor doesn't influence performance too much, until an object collides against it. Then the calculations are rather complex and can lower your FPS significantly, depending on the mesh's complexity.

A simple example of the mesh impostor can be found here - Mesh Imposter Example

To generate a mesh impostor, simply set the MeshImpostor type when creating the physics impostor of the mesh:

mesh.physicsImpostor = new BABYLON.PhysicsImpostor(mesh, BABYLON.PhysicsImpostor.MeshImpostor, {mass: 0});

The rest will be done by Babylon and the physics engine.

A wonderful example of the abilities of the mesh impostor can be found here - https://ajna4taiga.tk/PerplexusShadowOpen/Home.html

Motors

Certain joint types like the wheel (hinge) joint have the ability to run a motor that will move the impostor connecting to the joint in the direction set by the user.

Motors can be used to move a wheel of a car, to simulate an elevator or create a gear system. The motor is responsible to enable the circular movement of those simulations.

A simple example can be seen here - Simple Motor Example

Motor.enabled joints are using the IMotorEnabledJoint :

interface IMotorEnabledJoint {
physicsJoint: any; //the native physics joint object. Coming from the selected engine.
setMotor(force?: number, maxForce?: number, motorIndex?: number): void; // provide force to the motor
setLimit(upperLimit: number, lowerLimit?: number, motorIndex?: number): void; // set limits to the motor
}

Setting a motor on a hinge joint (assuming impostors are already set):

var joint1 = new BABYLON.HingeJoint({
mainPivot: new BABYLON.Vector3(0, 0, 0), // Pivot on the main mesh
connectedPivot: new BABYLON.Vector3(0, 0, 0), // pivot (connecting point) on the connected pivot
mainAxis: new BABYLON.Vector3(0, 0, -1), // the hinge will turn on the Z axis
connectedAxis: new BABYLON.Vector3(0, 0, -1) // Same as above - Z axis on the connected mesh
});
holder.physicsImpostor.addJoint(wheel.physicsImpostor, joint1); // attach holder (main) and wheel using the defined hinge joint
joint1.setMotor(3, 20); // start turning!

Compounds and Babylon's parenting system

Babylon.js supports creating physics compounds. A compound is a collection of physics bodies that are connected together to create a single physics body with the joint geometry of all of the meshes connected.

To create a compound, use babylon's parenting system. A single object should be the parent of the rest of the compound shapes:

// Create a 2-sphere compound
var sphere = BABYLON.Mesh.CreateSphere("sphere1", 16, 2, scene);
sphere.position.y = 10;
var sphere2 = BABYLON.Mesh.CreateSphere("sphere2", 16, 2, scene);
sphere2.position.x = 2;
sphere.position.y = 1;
sphere2.parent = sphere;

After creating the meshes, we need to initialize the impostors. It is important to first initialize the child impostors and initialize the parent impostor at the end:

sphere2.physicsImpostor = new BABYLON.PhysicsImpostor(sphere2, BABYLON.PhysicsImpostor.SphereImpostor, {mass: 2, restitution: 0.8});
sphere.physicsImpostor = new BABYLON.PhysicsImpostor(sphere, BABYLON.PhysicsImpostor.SphereImpostor, {mass: 2, restitution: 0.8});

The mass will be accumulated. So this single physics body's mass will be 4. sphere2's physics impostor will be "disabled" and will be joined to sphere's impostor, which is the main impostor. To apply impulses, set the liner velocity etc', use sphere.physicsImpostor.

Advanced Physics Compounds Example 1

An advanced example of compounds can be seen here - Advanced Physics Compounds Example 2. The boxes connected to the disc are connected using Babylon's parenting system.

ignoreParent

You can disable the compound behavior of babylon by setting the ignoreParent flag when creating the impostor. It is important to note that this will only work if your parent has no impostor attached to it. Otherwise the results can vary from weird physics calculations to missing collisions.

To create an impostor for a child mesh using the ignoreParent flag:

sphere2.physicsImpostor = new BABYLON.PhysicsImpostor(sphere2, BABYLON.PhysicsImpostor.SphereImpostor, {ignoreParent: true, mass: 2, restitution: 0.8});

A simple example can be found here - Ignore Parent Example

Substeps

It's possible to run the physics ticks at a different frequency than the framerate while keeping consistent display. This means it's possible to display at 60 frames per seconds while updating the physics 1000 times a second. With substeps, the physics will look like it's running at 60 frames per second but will perform smaller steps. This is useful when the physics update needs more precision. For example, simulating a bullet against a wall or more accurate physics for a car. The substeps can also be used to reduce the physics update. For example, doing an update every 2 frames. In the following example, the physics is computed 10 times a second instead of 60.

var physicsEngine = scene.getPhysicsEngine();
physicsEngine.setSubTimeStep(100);
Substeps Example

Cloth simulation

Raanan Weber wrote an article about cloth simulation in his blog: https://blog.raananweber.com/2016/04/03/cloth-physics-simulation-for-babylon-js/

An Oimo Demo

  • Oimo car demo - Oimo Car Demo

Further reading