3D Physics Engine Pt. 2


Hi. This is a continuation of the story about elm-physics. You can read the first part here.

The most important thing that happened since the original post, is that the project got a second contributor, Paul, who did a lot of work to add tests and benchmarks, improved the performance and implemented support for spheres!


I focused on improving demos, added simple shadows, the settings menu and most recently—the fps meter. Making it easier to create demos allowed us to identify and fix certain bugs. Like for example a bug when a sphere would circle around the corner, dive inside the box and then jump:


I set up this demo and was able to constantly reproduce the bug. It turned out, we did not continue with collision tests against faces and edges after the first collision with a corner had been detected. A quick solution was to test against faces, edges and corners and find the closest collision point. Paul figured that we could test collisions in the certain order. That really improved the performance, as you can see on this screenshot from the wonderful benchmark:

For the last part, I saved the most interesting finding. I’ve been following Florian’s experiment—a pure Elm implementation of linear-algebra (without any Kernel code to store vectors and matrices as typed JavaScript arrays). The physics engine seems like a perfect case to compare!

So I implemented another pure Elm version of linear-algebra with identical API, that defines vectors and matrices as record types, then ran our existing elm-physics benchmarks and came to the same results as Florian.

I think this happens because browsers can optimize objects that have the same shape and make them really fast, while reading data from an array requires some extra checks, and it is pretty costly to have lots of tiny arrays for Vec3. This JavaScript benchmark simulates a part of Elm’s WebGL, that packs data for an attribute buffer. It shows that objects are faster!

To conclude this, what if we remove linear-algebra, and use Elm records everywhere including for WebGL?

  1. we will remove unnecessary coupling from the Elm compiler, that has linear-algebra types hardcoded for glsl shaders
  2. we won’t have to fix nasty typos in Kernel code, writing Elm is a much better experience
  3. we will enable alternative linear-algebra implementations with a reacher functionality, like ianmackenzie/elm-geometry or already mentioned elm-webgl-math, to easily integrate with WebGL
  4. and most importantly, it will make the code run faster!

In the meantime, we keep working on elm-physics. The current hot topics are: using spatial indexing to avoid O(n^2) collisions and adding features like user interactions and events. If you feel like you can contribute something like this, please get in touch! Also if you would like to use it for something, please let us know about the missing features, so that we can have a more clear prioritization.

WebGL and runtime performance in a functional paradigm
WebGL and runtime performance in a functional paradigm

I’m definitely in favor of moving from the typed array-based types in linear-algebra to plain Elm records. I know there was concern that previous benchmarks may have showed that the typed array approach was faster than using Elm records/JavaScript objects (see e.g. this thread), but it really seems like the opposite is true now - perhaps JavaScript VMs do a better job nowadays of optimizing objects (using hidden classes and the like), or Elm emits better/more easily-optimized JavaScript (or both!). If anyone knows what benchmarks were used when originally deciding to base linear-algebra on typed arrays, then it would be great to run them again with Elm 0.19 and see what the results are now.


Another reason why I think this might be the case, at least for elm-physics, is that the most time is spent working with Vec3. I believe typed arrays are good for storing large amount of data, but when they’re used for tiny things, the overhead is not worth it.


I’m a bit late to this thread (I was on holidays), but I’ll bump this thread anyway.

Writing a physics engine in elm is an amazing project and I’m very impressed with the results so far!

As for the performance improvements from using a pure elm version of linear algebra, it’s great to have a real world benchmark backing up the results I obtained from micro benchmarking.
It really looks like in practice, the pure elm approach is faster.
So I also think it would be best to move to a pure elm implementation for vectors and matrices in WebGL.

I will not update my elm-webgl-math library for elm 0.19, as it uses tuples with up to 4 elements, which is no longer possible. But I think Ian’s elm-geometry is much nicer anyway. It would be super interesting to have a version of the benchmark with Ian’s library as well.


This topic was automatically closed 10 days after the last reply. New replies are no longer allowed.