Friday, October 17, 2025

Incremental Potential Contact (IPC): Revolutionizing Penetration-Free Physics Simulations...

Incremental Potential Contact (IPC) is a state-of-the-art method in physically based simulation used to handle collisions and contact between objects. It is especially popular in computer graphics, computational mechanics, and simulation systems where robustness and accuracy are critical.

What is IPC?

IPC is a contact handling framework that enforces non-penetration constraints between objects using a potential-based formulation. Instead of resolving collisions after they occur (as in traditional methods), IPC prevents interpenetration by introducing a barrier energy function that becomes infinitely large as objects approach each other too closely.

This makes IPC fundamentally different from penalty-based or impulse-based methods, which can allow small penetrations or require careful tuning.

Key Idea

At the core of IPC is a barrier potential:

  • When objects are far apart → no force

  • When objects get close → strong repulsive force

  • When objects try to penetrate → energy → ∞ (prevents penetration)

This ensures strict collision avoidance while maintaining smooth dynamics.

Mathematical Insight

IPC defines an energy function of the form:

\( E(d) = -\kappa \log\left(\frac{d}{\hat{d}}\right) \)

Where:

  • ( d ) = distance between primitives (points, edges, faces)

  • $ \hat{d} $= minimum allowed distance

  • $\kappa$ = stiffness parameter

As $(d \to 0)$, the energy blows up, enforcing non-penetration.

Advantages

  1. Robustness
    Prevents tunneling and interpenetration even with large time steps.

  2. Smoothness
    Forces are derived from continuous potentials, making simulations stable.

  3. Unified Framework
    Handles point-point, point-edge, and edge-face contacts consistently.

  4. Works with Implicit Integration
    Ideal for modern solvers like Newton-based optimization.

Applications

  • Cloth simulation (e.g., garments, soft materials)

  • Rigid body contact

  • Fluid-solid interaction (emerging research)

  • Engineering simulations requiring guaranteed collision-free states

Challenges

  • Computationally expensive due to nonlinear optimization

  • Requires careful implementation of distance queries

  • Barrier functions can introduce stiffness

Conclusion

Incremental Potential Contact represents a major advancement in collision handling. By reformulating contact as an energy minimization problem with barrier functions, IPC achieves robust, penetration-free simulation, making it highly suitable for modern physically based systems.


Here's my experimentation of IPC in Python
import numpy as np
import matplotlib.pyplot as plt
from matplotlib.animation import FuncAnimation, PillowWriter

# --- Simulation Parameters ---
dt = 0.001
total_time = 1.0
steps = 300 # reduced for performance

mass = 1.0

# --- Initial Positions ---
V = np.array([
[0.0, 0.0, 0.0],
[0.02, 0.0, 0.0]
], dtype=np.float64)

velocity = np.array([
[1.0, 0.0, 0.0],
[-1.0, 0.0, 0.0]
], dtype=np.float64)

# --- IPC Parameters ---
d_min = 0.01
d_hat = 0.012
kappa = 1e-2 # increased for visible effect

# History
distance_history = []
time_history = []

# --- Figure Setup ---
fig = plt.figure(figsize=(10, 5))

ax1 = fig.add_subplot(121, projection='3d')
ax2 = fig.add_subplot(122)

# 3D view limits
ax1.set_xlim(-0.05, 0.05)
ax1.set_ylim(-0.05, 0.05)
ax1.set_zlim(-0.05, 0.05)
ax1.set_title("Log Barrier IPC")

# Initial scatter (IMPORTANT: not empty)
scatter = ax1.scatter(V[:, 0], V[:, 1], V[:, 2], s=100)

quiver = None

# Distance plot
line, = ax2.plot([], [], lw=2)
ax2.set_xlim(0, total_time)
ax2.set_ylim(0, 0.03)
ax2.set_title("Distance vs Time")
ax2.set_xlabel("Time (s)")
ax2.set_ylabel("Distance (m)")

# --- Log Barrier Force ---
def ipc_log_barrier_force(p0, p1):
diff = p1 - p0
dist = np.linalg.norm(diff)

if dist < 1e-8:
return np.zeros(3), np.zeros(3), dist

direction = diff / dist

if dist < d_hat:
force_mag = kappa * (1.0 / dist)
f0 = -force_mag * direction
f1 = -f0
else:
f0 = np.zeros(3)
f1 = np.zeros(3)

return f0, f1, dist

# --- Init Function ---
def init():
scatter._offsets3d = (V[:, 0], V[:, 1], V[:, 2])
line.set_data([], [])
return scatter, line

# --- Animation Update ---
def update(frame):
global V, velocity, quiver

f0, f1, dist = ipc_log_barrier_force(V[0], V[1])

# Semi-implicit Euler
velocity[0] += dt * f0 / mass
velocity[1] += dt * f1 / mass

V[0] += dt * velocity[0]
V[1] += dt * velocity[1]

# Store history
time = frame * dt
time_history.append(time)
distance_history.append(dist)

# Update scatter
scatter._offsets3d = (V[:, 0], V[:, 1], V[:, 2])

# Remove old force arrows
if quiver:
quiver.remove()

# Draw force vectors
scale = 0.005
quiver = ax1.quiver(
V[:, 0], V[:, 1], V[:, 2],
np.array([f0[0], f1[0]]) * scale,
np.array([f0[1], f1[1]]) * scale,
np.array([f0[2], f1[2]]) * scale,
color='red'
)

# Update graph
line.set_data(time_history, distance_history)

return scatter, line

# --- Create Animation ---
ani = FuncAnimation(
fig,
update,
frames=steps,
init_func=init,
interval=20,
blit=False
)

# --- Show Animation ---
plt.tight_layout()
plt.show()

# --- Save GIF (AFTER show) ---
#ani.save("ipc_log_barrier.gif", writer=PillowWriter(fps=30))

#print(" GIF saved as ipc_log_barrier.gif")
And here's the visualization...



Enjoy... Happy code digging...

Sunday, October 12, 2025

The Father-Son duo's story - the four layered nested vectors...

My school going son, Ridit, had a complain against me...
"Baba, why didn't you teach me about nested vectors earlier? I am stuck in a particle simulation application where i am using Incremental Potential Contact (IPC) for collision detection. And I am trying to decipher the 4 layered nested vectors now."

" Okay... It's a little difficult for new comers. That's why i didn't touch nested vectors when i taught you C++. But here we go..."


1. Vector of Character: The String

"Look at your name: 'R-I-D-I-T'," I said, writing it on a whiteboard. "Each letter is a single character, right? A computer takes those individual characters and lines them up, one after the other, to make a single word."

"That single line of characters? That's what we call a 'vector of character'. It's the simplest type, just like a single word. And you know its called a string... right!!!"

Ridit nodded... Yes...

2. Vector of String: The Family Member List

"Exactly! Now, let's take a step up. You, me, and Mom." I wrote:

  • Ridit

  • Dad

  • Mom

"See? Now we have three separate 'strings'—three names. A computer can take a whole list of these strings and put them together into a bigger list."

"That bigger list—the list of names of all our family members—is a 'vector of string'. It's like a single list where every item is a word or a phrase. It’s a list of words."

3. Vector of Vector of String: The Family Album

"Now, let's think bigger. Imagine your friend Ishan's family. They have their own list of names, right? Ishan, his mom, his dad."

I drew a box around their family's list and another box around Ishan's family's list.

"In our program, we could have one list for The Sharma Family and a second list for The O'Connell Family. We now have a list of lists of names."

"That's a 'vector of vector of string'. It's an organized list where each item is a complete list of names from a different family. It's how we organize data for something like a Family Tree app or a guest list for a big party, where you group guests by family."


4. Vector of Vector of Vector of String: The Global Directory

"Alright, last one, the biggest level. Imagine a program that keeps track of families all over the world. Our set of families is in India." I wrote 'INDIA' above the Sharma and O'Connell families.

"Now, there's another set of families living in Japan , and maybe another set in Brazil."

"We can take the entire collection of Indian families (our previous 'vector of vector of string'), and put it on a larger list next to the collection of Japanese families and the collection of Brazilian families."

"This final, massive list is a 'vector of vector of vector of string'," I finished, pointing to the largest, outermost box. "It's how we group data by a major category, like Nation. It's a huge directory where each entry is a list of all the families in a specific country, and each family is a list of all its members."

Here's a pictorial explaining the above concepts ...


I told my son...Computer Science is like studying different seemingly disconnected subjects together.... but when the convergence happens after years of experience, the bigger picture comes out.

Then I asked my son, could you map this kinds of Data Structure with any of the design patterns you studied?

"Yeah... Composite Design Pattern...", Ridit answered confidently.

"Good... ", i said. " Now finish your particle simulation and contribute to the body learning of the universe. That's our final goal..."