3D Physics Engine Pt. 3

Hi folks, it’s me again, with a progress report on elm-physics. You can read the first part here and the second part here.

A lot happened since the previous post: performance improvements, simpler API and more features!

20

Performance

The current performance seems to have plateaued at 64 boxes running at 60 FPS on my MacBook Pro, which is 3 times more boxes than before! Below are some tricks that helped with improvements.

While elm-explorations/benchmark is nice for micro-benchmarks, it doesn’t work for macro benchmarks. It was more helpful to set up the Boxes example, then look at FPS and profile JavaScript in Chrome (although profiling is not easy, because most functions are listed as anonymous).

  1. The slowest code isn’t calculating collisions, it is the solver of physical equations (highlighted on the screenshot), a part that is responsible for calculating the final velocities. This means that focusing on improving collisions using spacial indexing would not help much in the current situation.
  2. The solver needs to go over a list of equations and update a pair of related bodies. While equations are simply iterated over, bodies need to be updated for each equation. Switching from Dict to Array for bodies have improved performance quite a bit, but Array.set still took more than 15% of the total time! This is where I realized I could group equations by a pair of bodies, because this is how they are created initially (each collision point generates three equations). This let me Array.get and Array.set only twice per equation group and reduce the Array usage a little bit, although it is still the bottleneck. The Elm compiler was really helpful in this restructuring.
  3. I did a lot of micro optimizations too: started using record based linear-algebra, inlined vector operations, replaced record update syntax with a new record creation, used a - b > 0 instead of a > b, expanded folds of records into tail optimized recursions, got rid of Array in the ConvexPolyhedron type, replaced functions that work on Maybe with pattern matching. Please let know in comments if anything needs further explanation or you have more ideas!

API

The main problem of the old API was the necessity of keeping and passing around BodyId. This made elm-physics responsible for generating unique ids: World.addBody returned a tuple of a new world and the id of an added body, so it could not be simply chained. I addressed this by allowing to store user-defined data type inside each Body data: now simple examples can store a WebGL Mesh inside a body, while more complex examples can tag each body with a custom user-defined id.

For simplicity, I provided basic constructors for bodies with a single shape. For advanced usage I implemented a function to create a compound body from a list of shapes. As a result, the Physics.Shape module is not even required for simple cases.

There have been a lot of smaller improvements here and there. I am really grateful to Ian Mackenzie and Matthew Griffith for helping me!

You can check the new API here. Make sure to start with Physics.World and Physics.Body. By the way, it would be nice if the order of exposed modules from elm.json was preserved on the package website. Not sure what is the best practice here, maybe I need to add my own table of contents.

New Features

The way I went about adding new features is through evolving the examples.

  1. When I initially built the Dominoes example, the dominoes were not sliding along each other, so I had to introduce materials to control friction and bounciness.
  2. I really wanted to interact with objects, so I figured out that I needed to add raycast support to be able to pick them. And then I added a point to point constraint to connect a mouse body with the selected body in the Drag example.
  3. Having added basic support for constraints, I wanted to see what else can be done with them. Using the hinge constraint the Car example has been built.

car

You can find the examples code in the elm-physics repository. Everything that is related to rendering has been extracted into common modules, so that the main modules are really focused on showing the API of elm-physics.

Future

I want to add API for applying forces to bodies, to e.g. allow controlling the car with a keyboard. I also want to improve the stability, because right now everything is being constantly recalculated and scenes with many touching bodies don’t calm down. Adding support for more shapes would be nice and some shapes would be quite simple, because a box is already implemented using a generic convex polyhedron. Collision events are still missing too.

Currently I’m preparing for Elm Europe, so please don’t expect new features soon. However I’m open to questions and suggestions. Please let me know if you want to contribute to the project or use elm-physics to build something cool!

33 Likes

Impressive work! Thanks for sharing!

1 Like

Extreme awesomeness!

1 Like

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