Affine Body Spherical Joint
References:
A unified newton barrier method for multibody dynamics
Related: Affine Body (state and Jacobian \(\mathbf{J}\)), Affine Body Fixed Joint (full rigid weld; spherical joint keeps only the translation part of that formulation).
#26 AffineBodySphericalJoint
The Affine Body Spherical Joint (ball-and-socket joint) constrains two affine bodies so that a single anchor point has the same world position on both bodies, while relative rotation is unconstrained. Only three translational degrees of freedom at the anchor are penalized.
State variables
Each body \(k \in \{i,j\}\) carries the affine state \(\mathbf{q}_k \in \mathbb{R}^{12}\) as in Affine Body. World position of a material point with rest local coordinates \(\bar{\mathbf{x}}\) is \(\mathbf{x}_k = \mathbf{J}(\bar{\mathbf{x}})\mathbf{q}_k\).
Rest anchor and local coordinates
At setup, the user specifies an attachment \(\bar{\mathbf{p}}_j\) in body \(j\)'s (the right body's) rest local frame. The corresponding world anchor at rest is:
where \(\mathbf{T}_j\) is that instance's rest transform. The same world point is expressed in each body's local frame:
These fixed \(\bar{\mathbf{c}}_i\), \(\bar{\mathbf{c}}_j\) are stored per joint and used in the constraint below.
Translation constraint
The constraint requires both bodies to map their local anchor to the same world position at all times:
where
and \(\mathbf{J}(\bar{\mathbf{c}}_k)\) is the \(3\times12\) Jacobian in Affine Body. Equivalently,
with
Energy
The joint potential is a quadratic penalty on \(\mathbf{F}_t\):
where \(\|\cdot\|_2\) is the Euclidean vector norm. The stiffness scale is
where \(\gamma\) is the user-defined strength_ratio and \(m_i\), \(m_j\) are the affine bodies' masses.
Unlike the Affine Body Fixed Joint, there is no additional energy on relative orientation, so the two bodies may rotate freely about the anchor.
Parameter range
strength_ratio \(\gamma\) is dimensionless; it scales the penalty with combined mass. Typical values are problem-dependent; the regression test uses \(\gamma = 100\) for a small two-cube scene.
Attributes and geometry
The joint is stored as a 1D simplicial complex (one edge per joint).
On each edge:
geo_ids:Vector2i— scene geometry slot ids \((\text{left},\text{right})\) for bodies \(i\) and \(j\)inst_ids:Vector2i— instance indices within each geometrystrength_ratio: \(\gamma\) in \(K = \gamma(m_i + m_j)\)
On vertices (two per joint, for visualization and initialization):
position/ builtin positions: vertex \(2k\) is body \(i\)'s rest translation (edge endpoint for drawing); vertex \(2k+1\) is the world-space anchor \(\mathbf{c} = \mathbf{T}_j \bar{\mathbf{p}}_j\) at setup. The backend evaluates \(\bar{\mathbf{c}}_i\), \(\bar{\mathbf{c}}_j\) from the anchor vertex and the two rest transforms.
Constitution UID: \(26\) (see Constitutions index).