After working on the Tower game I mentioned in the last post, I wanted to write a physics plugin for three.js to make it very easy to include physics in 3D scenes. While the plugin has been up on github for a while, I now feel it’s ready for an official release.
What is it?
Physijs brings a very easy to use interface to the three.js framework. One of the reasons three.js is so popular is because it is so incredibly easy for graphics newbies to get into 3D programming. Physijs takes that philosophy to heart and makes physics simulations just as easy to run. In fact, there are just five easy steps that must be taken to make a 3D scene come alive.
How does Physijs work?
Physijs is built on top of ammo.js and runs the physics simulation in a separate thread (via web worker) to avoid impacting in your application’s performance and taking up your your 3D rendering time.
A lot of effort has been made to keep the style of code the same when using this plugin. Apart from updating an object’s position, all of the normal three.js conventions remain the same. If you are used to three.js, you already know how to use Physijs.
Who is this for?
You, hopefully. If you are familiar with three.js and want to add physics to your scene, this is the plugin for you. No mucking about with shape definitions, keeping objects in their correct positions, or identifying collisions – simply use a few Physijs objects in place of three.js’s and you’ll automatically have a dynamic environment.
If you need (or want) a feature not already included then add it to the issue tracker or implement it yourself and send over a pull request at the github repo.
Let’s explore the basics of using Ammo.js for physics in a Three.js environment.
For my entry to the Pokki 1UP contest I rushed out a simple physics-based WebGL game. From start to finish I had 9 days left until the game needed to be submitted. I broke that down into one day for the initial setup, a couple days for physics, one day for sound, one day for interface, and the last day for minute touch ups. Turned out to be the perfect timeline. The setup consisted of creating a Three.js environment within the Pokki framework. I also spent that first day hashing out the basic ideas, inspired by a “reverse Tetris” plan.
The second day was my first real attempt at using any physics library. Right now the most popular Javascript physics library is probably Box2D, as long as you don’t need to simulate a full 3D world. My game didn’t need an entire 3D simulation – the player can only move blocks along the X axis and gravity only applies to the Y axis; no simulation was needed across the Z axis. However, the results I got from Box2D were poor. It seemed to detect collisions a bit late and I wasn’t able to coerce any of the boxes to interact in a believable way. I attribute that to my unfamiliarity with the library, but I was on a very tight time table and I had spent a full night failing to achieve decent results.
Next night I found my winner – Ammo.js – which is a direct port from the C++ library Bullet physics. An added benefit is Ammo.js does simulate a full 3D environment, not just 2 dimensions like Box2D; this gave my game more realism as the blocks aren’t constrained to just XY coordinates. I was able to get all of the necessary physics setup in just a few hours – from a static ground plane to placeable blocks and a tipping tower. In this post I am leaving out any of the scene management of creating and adding the 3D objects themselves; if you are not familiar with Three.js I highly suggest doing yourself a favor and learn how to setup a simple scene, and then play with some of the included examples.
Where in the world have I been the past two months?
Late last December Pokki announced their 1UP HTML5 game contest, which ends today. I started working on a World War II themed RTS. As it turns out, making a real time strategy game requires more than 2 months if you’re starting from scratch. So one week before the contest deadline I scrapped that idea and started work on a completely different game.
Fortunately I was able to complete the second concept in time. The game is called Tower and the aim is to build the tallest stack of wooden and stone blocks as you can while racing the clock. For now Tower is only available to Windows users through the Pokki store, but I will put it online for others when the contest is over.
I will put up another post in a week or so detailing how I put Tower together. It was the first time I worked with any of physics libraries (happily decided on ammo.js) but overall everything was straightforward.
A few days ago Evan Wallace released his Constructive solid geometry library for WebGL. This library uses Boolean operations (addition, subtraction, union, intersect) to be applied on 3D geometry such as cubes, spheres, or anything else you can throw at it. I thought this would be a very nice capability to have in Three.js and wrote a wrapper for Evan’s CSG library.
First, an example of what code using just the CSG library looks like:
var cube = new CSG.cube();
var sphere = CSG.sphere({radius: 1.3, stacks: 16});
var geometry = cube.subtract(sphere);
Let’s add in Three.js and my CSG wrapper:
var cube = THREE.CSG.toCSG(new THREE.CubeGeometry( 2, 2, 2 ));
var sphere = THREE.CSG.toCSG(new THREE.SphereGeometry(1.4, 16, 16));
var geometry = THREE.CSG.fromCSG( sphere.subtract(cube) );
var mesh = new THREE.Mesh(geometry, new THREE.MeshNormalMaterial());
It’s that simple. The toCSG function accepts objects of both THREE.Geometry and THREE.Mesh types. Objects can be positioned either by the mesh’s position or by supplying a second parameter to the toCSG function. Both methods are shown below. (rotation can be set from the mesh’s rotation property or through a supplied third parameter)
var cube_mesh = new THREE.Mesh(
new THREE.CubeGeometry( 2, 2, 2 )
);
cube_mesh.position.x = 1;
var cube = THREE.CSG.toCSG(cube_mesh);
var sphere = THREE.CSG.toCSG(new THREE.SphereGeometry(1.4, 16, 16));
var geometry = sphere.subtract(cube);
var mesh = new THREE.Mesh(geometry, new THREE.MeshNormalMaterial());
var cube = THREE.CSG.toCSG(
new THREE.CubeGeometry( 2, 2, 2 ),
new THREE.Vector3(-1, 0, 0)
);
var sphere = THREE.CSG.toCSG(new THREE.SphereGeometry(1.4, 16, 16));
var geometry = THREE.CSG.fromCSG( sphere.subtract(cube) );
var mesh = new THREE.Mesh(geometry, new THREE.MeshNormalMaterial());
In these examples I only used the built in primitive objects but the same functionality should work for any Three.js compatible models. UV coordinates are not generated (all values are set to 0) but everything else related to THREE.Mesh works as you would expect.