Babylon JS Day 20

Today is the final day of my A Month of Babylon JS education project and the last of the “Project Fridays”. I set out to build a simple golf demo for WebXR. I didn’t complete a full demo but I did get a few things done and I learned a lot about working with physics in Babylon JS.

I already had a golf club attached to one of the VR controllers, so I moved on to working on the ball. I created a prototype ball and positioned it where I could see it.

    var = globalBall = BABYLON.Mesh.CreateSphere("sphere1", 16, 2, scene);
    globalBall.position = new BABYLON.Vector3(-1, 0.2, 3);
    globalBall.scaling = new BABYLON.Vector3(0.05, 0.05, 0.05);

Then it was time to add some basic physics to the ball. I read though much of the documentation and found a couple of playgrounds to reference. I added physics at the scene level by defining gravity and selecting one of the available plugins.

    var scene = new BABYLON.Scene(engine);
    const gravityVector = new BABYLON.Vector3(0, -9.8, 0);
    const physicsPlugin = new BABYLON.CannonJSPlugin();
    scene.enablePhysics(gravityVector, physicsPlugin);

Then I activated physics on the ball by setting up a PhysicsImpostor. This seems similar to a rigid body in Unity. There are several shapes available and lots of options to customize.

 globalBall.physicsImpostor = new BABYLON.PhysicsImpostor(
      globalBall,
      BABYLON.PhysicsImpostor.SphereImpostor,
      { mass: 0.1, friction: 10, restitution: 0.5 },
      scene
    );

Just to have some fun, I decided to clone the ball in a loop and scatter the clones around the scene.

var y = 0;
    for (var index = 0; index < 20; index++) {
      var sphere = globalBall.clone("ball" + y);
      sphere.position = new BABYLON.Vector3(Math.random() * 20 - 10, 0.1, Math.random() * 10 - 5 + 5);
      y += 2;
    }

At this point I had a scene full of balls that could collide with each other, but I still couldn’t hit them with the club. My first attempt was adding a physics to the club mesh, but no matter what I tried I could not get it working. I also tried adding a simple box to the bottom of the club and adding physics to the box. That also failed and caused some weird issues with the position of the club on the controller. (I have no idea why a child object would affect the position of a parent object like this…)

My really bad workaround for today was to add physics to the motion controller itself, then modify the size and shape of the collider. You can see the dimensions of the collider in the imposterSize object below.

    // enable physics for the XR controllers
    const xrPhysics = xr.baseExperience.featuresManager.enableFeature(
      BABYLON.WebXRFeatureName.PHYSICS_CONTROLLERS,
      "latest",
      {
        xrInput: xr.input,
        physicsProperties: {
          restitution: 1,
          friction: 100,
          useControllerMesh: false,
          impostorSize: {
            height: 0.1,
            width: 0.05,
            depth: 1.6
          },
          impostorType: BABYLON.PhysicsImpostor.BoxImpostor
        },
        enableHeadsetImpostor: false
      }
    );

At this point I could finally move the balls with the club (actually, with the physics body on the controller… the club is just for show).

It may not look like much, but it took most of the day. While I can certainly move the balls with the club now, it is far from something that feels natural, or even just fun. I think in the future I’ll remove the physics from the controller and find another way to apply force to the ball from the club. I think I can do something with mesh intersection and the velocity of the club, but that is for another day.

Next week I’ll write a recap post reviewing what I’ve learned this month. I’m far from being an expert at Babylon JS, but I’m getting comfortable working with it and I’m happy to add it to the set of tools with which I build applications and sites.