Try To Implement IPC

Intro: A taste of the Rust programming language

Recently, I tried to get started with Rust and wanted to write some code. I ended up picking up two papers I’ve been studying lately to try reproducing them.

Note: This post only reproduces/discusses the IPC family of algorithms.

Project repo: Github

Implicit Euler

Physical simulation is essentially a numerical integration process.

Explicit integration tends to explode, but implicit integration suffers from a “chicken-and-egg” problem.

What Is It?

Incremental Potential (IP) is a function of the degrees of freedom (DOF) of a scene at time t, IP(t).

Implicit Euler constructs and minimizes the IP to obtain the position at the next timestep.

Deep learning typically uses gradient descent, but in graphics, empirical evidence suggests gradient descent performs poorly. So, we opt for Newton’s method.

Implementation

Following this tutorial, I implemented springs with vertices pinned to a wall.

Contact IP

In short, Contact IP requires that point-edge pairs from two different bodies, which are close enough, are assigned energy based on their distance.

But to prevent interpenetration, there are additional requirements:

Procedure

At each line search step in Newton’s method:

Implementation

Every step involved endless debugging…

Gradient & Hessian:

Note: Later, I built my own SymPy→Rust code generator: Symars

After days of coding and debugging, the demo finally worked:

ABD

TL;DR, ABD Replaces traditional 6-DOF rigid bodies with 12-DOF bodies and heavily penalizes transformation matrices that deviate too far from rotation matrices.

In 2D, an affine body has 6 DOFs: x = A x_0 + b.

ABD uses an orthogonal potential energy to penalize A and keep it close to a rotation matrix.

Implementation

After more endless debugging and parameter tuning, the simulation finally ran:

Final Thoughts

The resulting code is a bona fide spaghetti monster.

Even though I spent a long time thinking about unifying interfaces before coding, the final design is neither OOP nor Rust-like, with inconsistent parameter passing everywhere.

The bright side: