Skip to content

v1.6.0

Latest

Choose a tag to compare

@zfergus zfergus released this 15 Jul 14:55

Highlights

  • LBVH is now the default broad phase, replacing HashGrid. Combined with this release's LBVH optimizations, it is roughly 2× faster than the (now-removed) SimpleBVH and, because HashGrid scales poorly, several-fold faster (≈6–8× on large benchmark scenes) than the previous default (#212).
  • Add analytic plane-vertex collisions (#216).
  • Add anisotropic friction by @antoinebou12 (#210).
  • Add barrier stiffness ($\kappa$) to ipc::BarrierPotential and simplify the tangential API (#215).
  • Add composable collision filters (#235).

Broad Phase

  • Set the default broad phase to ipc::LBVH (#212).

    • LBVH outperforms the previous default (HashGrid) and all other methods across a range of scenes. On the benchmark scenes below it is ~1.5× faster than SimpleBVH (the fastest existing method) at baseline; with this release's pruning and bottom-up-build optimizations that grows to roughly 2× faster than SimpleBVH and ~6–8× faster than HashGrid.


    Total broad-phase performance across methods; LBVH is roughly 1.5× faster than the fastest existing method. Benchmarked on an Apple M2 Max (12 cores).

  • Remove the SimpleBVH dependency and the deprecated BVH broad phase (#213).


    LBVH construction is more than 3× faster than the removed BVH method. Benchmarked on an Apple M2 Max (12 cores).

  • Add rightmost-leaf pruning to LBVH self-collision traversal, skipping subtrees fully left of the query. 39% average speed-up in edge-edge traversal across benchmark scenes (#222).

    • Also fixes three bugs in the OGC edge-edge feasibility check.
  • Optimize LBVH construction with a single bottom-up pass [Apetrei 2014], building the hierarchy and bounding boxes simultaneously instead of the two-pass build of [Karras 2012]. Up to 10% faster to build (#230).


    Bottom-up [Apetrei 2014] vs. two-pass [Karras 2012] LBVH construction, benchmarked on an Apple M3 Pro (11 cores).

  • Refactor the AABB, HashGrid, and LBVH parallel loops to use tbb::parallel_for with index ranges directly (#228).

New Features 🚀

  • 💥 [Breaking] Add barrier stiffness and simplify the tangential API (#215).

    • Add a barrier stiffness $\kappa$ to ipc::BarrierPotential: new constructors, member, and getter/setter, scaling the potential, gradient, and Hessian by $\kappa$.
    • Remove the redundant normal_stiffness parameter from the tangential collision constructors and ipc::TangentialPotential interfaces, updating all call sites and Python bindings.
  • Add analytic plane-vertex collision support (#216).

    • Add ipc::PlaneVertexCandidate and normal and tangential plane-vertex collisions, integrated into the collision builders.
    • Add ipc::CollisionMesh::planes (a list of Eigen::Hyperplane<double, 3>) to represent infinite analytic planes such as a ground plane, with Python bindings.
    • Remove the old implicits module.
  • Add anisotropic friction by @antoinebou12 (#210).

    • Per-contact tangent-space velocity scaling and optional [Erleben et al. 2019] "matchstick" direction-dependent static/kinetic coefficients.
    • Direction-dependent coefficients are lagged: refresh with ipc::TangentialCollisions::update_lagged_anisotropic_friction_coefficients after build and whenever the lagged state changes.
    • Default behavior remains isotropic. The directional model is active only in the 2D tangent space of 3D simulations.
    • Tutorial available here.
  • Implement the Gauss-Newton preconditioner from [Shen et al. 2024] (#221).

    • Add ipc::CollisionStencil distance-vector utilities (compute_distance_vector, compute_distance_vector_jacobian, and diagonal/Jacobian-contraction helpers).
    • Add cumulative ipc::NormalPotential Gauss-Newton routines (diagonal and quadratic form), parallelized with TBB.
    • Exposed in the Python bindings with unit tests.
  • Add the Planar Divide-and-Truncate (Planar-DAT) trust-region filter for OGC [Chen et al. 2026] (#228).

    • ipc::ogc::TrustRegion::planar_filter_step is a direction-aware alternative to isotropic filtering: it computes a division plane per collision pair and truncates only motion toward the opposing primitive, reducing artificial damping and deadlock in dense-contact scenarios.
    • Available in both C++ and Python.
    • Tutorial available here.
  • Add composable collision filters (#235).

    • New ipc::CollisionFilter (C++ and Python) wraps any bool(int, int) callable and composes via | (union), & (intersection), and ! (negation).
    • Factory functions for common cases: make_vertex_patches_filter, make_static_obstacle_filter, make_codim_cross_filter, and make_connected_components_filter.
    • The FAQ is rewritten to document the new system with C++ and Python examples.
  • Add support for nonmanifold smooth edges (#223).

    • Generalize the Edge3 primitive and smooth_edge3_term (and its derivatives) to an arbitrary number of adjacent faces.
    • Change edges_to_faces from a fixed-size matrix to a vector of vectors and increase N_EDGE_NEIGHBORS_3D from 4 to 6.

API Changes 🔧

  • Configurable derivative layout (#217).

    • Add a VERTEX_DERIVATIVE_LAYOUT constant to ipc/config.hpp and parameterize the gradient, sparse-gradient, Hessian-triplet, and Jacobian-triplet assembly helpers with an optional row- or column-major global ordering (defaulting to VERTEX_DERIVATIVE_LAYOUT).
  • 💥 [Breaking] Update the local 3rd-order tensor Jacobian layout (#219).

    • Store 3rd-order tensors as matrices following the convention in "Dynamic Deformables" [Kim and Eberle 2022], easing tensor contractions in the chain rule.
    • Rename the relative-velocity API from *_matrix/*_matrix_jacobian to *_jacobian/*_dx_dbeta across C++, Python, and documentation.
  • 💥 [Breaking] Refactor the nonlinear CCD into a ipc::NonlinearCCD class (#218).

    • Encapsulate the point-point, point-edge, edge-edge, and point-triangle nonlinear CCD methods, replacing the previous free-function API.
    • Update signatures to take Eigen::ConstRef and adjust the conservative-rescaling parameter handling.

Bug Fixes 🐛

  • Use a relative PARALLEL_THRESHOLD in edge_edge_distance_type to correctly classify nearly-collinear coplanar edges, and add defensive guards for mollified collisions at $d=0$; adds a regression test (#225).
  • Fix a 2D GCP bug caused by a trivially loose Edge2 active check by @udaykusupati (#227).
  • Skip the edge-edge planar filter for nearly-parallel edges with negligible approach velocity to avoid spurious truncation (#232).
  • Fix MSVC duplicate-symbol errors for PrimitiveDistance by adding explicit specialization declarations (#237).
  • Fix two bugs in the mollified edge-edge shape derivative (a wrong gradient factor and a missing outer-product term) by @Huangzizhou (#239).

Profiling ⏱️

  • Add fine-grained profiling instrumentation throughout, recording only on the main thread (#233).
  • Add an optional Tracy frame profiler via the IPC_TOOLKIT_WITH_TRACY CMake option (#234).
  • Record profiler data on the TBB arena coordinator thread rather than by main-thread ID (#236).

Python 🐍

  • Allow the thread limit to be set globally via the TBB_NUM_THREADS environment variable, applied on import of ipctk (#242).
  • Add the IPCTK_WITH_SIMD environment variable to disable SIMD in Python builds (#231).

Miscellaneous

  • Replace the maybe_parallel_for wrapper with direct tbb::parallel_for and tbb::enumerable_thread_specific (#214).
  • Clean up the closest-point auto-generated code (#220).
  • Update GitHub Actions to the latest major versions (#224).
  • Disable pedantic and unneeded MSVC compiler warnings.
  • Strip notebook outputs and add an nbstripout pre-commit hook (#240).
  • Updated dependencies:
    • Bump finite-diff from v1.0.3 to v1.0.4.

New Contributors

Full Changelog: v1.5.0...v1.6.0