Trying Out WebGL Physics
If you have ever played a video game you know there’s a subtle wow factor when objects don’t act in a linear fashion. That hang time right before a trap comes swinging back? The effect of sliding across icy terrain? Each of those experiences centers around, and is made far more compelling by the use of physics.
While gaming may be one of the most intuitive use cases for physics, WebGL allows us to render graphics in web browsers, and different plugins exist to help us easily run physics simulations. This allows us to create new and interactive user experiences for websites, other web applications, rendered animations/video, as well as games.
What is WebGL?
While there are many physics properties that can now be simulated in WebGL, for our purposes, we’ll be using these three: friction, gravity, and collisions. As a starting point, we will use Virgil Spruit’s sample WebGL physics game as a template, since it allows us to quickly build a base project that uses websockets so you can utilize your phone as a controller to directly interact with the model.
For the purposes of this demonstration, we will be using Three.js, Physijs, Node.js, and socket.io. Three.js is one popular library for rendering WebGL, but other libraries also provide similar benefits such as PixiJS, Babylon.js, JanusWeb, etc.
The project we are building will have two components. The first one will be the aforementioned physics game from Creative Bloq, which showcases how objects behave when they collide with one another and the board. The second is a play on a classic physics question:
If you have a sphere and a block made of the same material and of equal mass, and you place both on an incline, which will reach the bottom first in an environment with friction? Without friction?
As an aside, friction is the resistance force between objects moving relative to one another, and it varies depending on the objects in question. For example, a hockey puck easily slides across an ice pond (μ = 0.12), but a rubber tire doesn’t slide easily on dry concrete (μs = 1.0). Having the same material pairs between our terrain and our sphere/block should therefore streamline the results of our experiment, right?
If you haven’t guessed, that’s a little bit of a trick question. The answer is that the different shapes will create different results, but only in one of our two scenarios. As a super-simplified explanation, friction is necessary to create a ‘rolling’ motion, so in a true frictionless environment, both objects will reach the bottom at the same time! With friction on the other hand, the sphere rolls, expending some energy in other directions than down the incline.
If our simulation correctly utilizes physics concepts, we should be able to see this visually represented!
Build: Adjust the starting point
First, we’ll be forking this repo to get the base of our project. Because we are looking to ultimately compare the effect of physics on a cube versus a sphere, we will change the initial setup of the field to have both of these items present. Since the only way to truly compare the two would be for them to be the same size and materials, we have to change the hard-coded friction values. For simplicity, we will also change the table’s friction coefficient to match, but for future reference, having different friction coefficients between terrains makes for a richer experience… (think thick grass, sleek tiles, oil slicks, carpet, ice, etc)
This variable will also be helpful when we later play with toggling friction on and off (zero vs non-zero value). We can use a ternary operator to decide whether to use our chosen variable muObject or 0. The boolean frictionMod will also make our friction toggle function much simpler later as well!
The second item to change would be to place a starter cube on the field, alongside the sphere. I also adjusted the sizes of both items so the effects of friction on their movement can be more pronounced when combined with our lengthened plane. We will also need to get rid of the click handler that floods the field with spheres so we don’t overcrowd our space!
The third piece that is important is creating a longer path. For the original repository, the field was a flat plane. We want a longer one so we can see more difference in the ultimate distance each object travels. Right now, the objects can only travel a short distance before plummeting off the edge. We also want to be able to view the effects at different angles. This is wildly important from a conceptual physics standpoint as the angle of a plane naturally changes the friction force. (FYI, simplified, but friction force runs parallel and opposite to the motion of an object.)
Lastly, we need to be able to actually toggle the friction coefficient of our pieces and our field. In the original repo, the spacebar was coded to “slam the table and launch the balls into the air.” We will repurpose this event listener to adjust the friction coefficient.
Build: Some Results, Some Questions
Full transparency- the original project, being from 2018, has some deprecated code! If you discover that the sockets form does not appear, as I did, you can still visualize the effects by adjusting the initial tilt of the table element.
After placing the objects on the field, and letting gravity affect them, initially they both began at rest and then started traveling down the plane. I noticed the ball was rolling, and the cube moved at a slightly separate pace, which was expected. Great!
Then, I hit the spacebar to toggle the friction coefficient. The behavior did not change. The ball appeared to rotate; the cube … caught on the surface of the plane and tumbled? This was not expected.
Just in case the initial setup (frictionMod being true) affected the objects’ behavior, I changed it to false. I double-checked Physijs’s documentation to confirm the range for the friction coefficient was between 0 and 1. Then I hardcoded all the friction coefficients to be 0 and tested. Set the cube to be 1 and the ball to be 0 and tested. In every one of these cases, both objects performed in the same way. The ball appeared to roll straight down the hill. The cube slid straight sometimes, but ultimately diverged from the expected path.
In order to determine whether it was the shape or the coefficient that was driving the behavior, I created another ball and another cube. For each pair of objects, I made one have the maximum friction (1) and the other no friction (0). Then I adjusted their coloration to clearly see whether the objects would roll or slide.
Both balls slid, perhaps because of the frictionless floor, so I adjusted that to be a nonzero value as well.
The final result here was that for the first pass, the two frictionless objects (cube and sphere) performed the same, and the objects with friction varied! Both cubes still exhibit some tumbling and catching(partially elastic collisions ftw), which will take some more digging to figure out exactly why, but overall, a fairly successful experiment!
In conclusion, physics is fascinating, even when unexpected, and being able to truly capture that using webGL makes for a more unique experience in how we interact with rendered graphics elements.
Thank you for reading, and stay curious!