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
Robustness
Prevents tunneling and interpenetration even with large time steps.Smoothness
Forces are derived from continuous potentials, making simulations stable.Unified Framework
Handles point-point, point-edge, and edge-face contacts consistently.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.
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")
No comments:
Post a Comment