Skeleton Dynamics API Reference¶
This page covers the generic skeleton dynamics interfaces in render-core. Data conversion happens at the
model construction stage; at runtime, instances are controlled by IK chain name. Algorithms and ownership are documented in the concept document.
The underlying world, forces, collision, active ragdoll, and Minecraft integration are covered in Physics API;
format manifest/profile are covered in MMD/glTF configuration.
Types and Packages¶
| Type | Full package name | Purpose |
|---|---|---|
Skeleton, SkeletonDynamics |
lib.kasuga.rendering.models.uml.structure.skeleton |
Bones and shared dynamics definitions |
SkeletonDynamics.* |
same as above; nested types of SkeletonDynamics |
Physics, IK, and closure data |
SkeletonDynamicsBuilder, SkeletonDynamicsReader<T>, SkeletonBuilder |
lib.kasuga.rendering.models.uml.loaders |
Construction, validation, and external format extension |
SkeletonInstance, ModelInstance |
lib.kasuga.rendering.models.uml.dynamic |
Per-instance control and pose evaluation |
CalikoIkSolver |
lib.kasuga.rendering.models.uml.dynamic.ik |
Solver adaptation and diagnostic results |
IkTargetModule |
lib.kasuga.rendering.models.uml.dynamic.tick_loop.handler |
Per-tick external IK targets |
MmdSkeletonDynamicsReader |
lib.kasuga.rendering.models.uml.typo.miku_miku_dance |
PMX/converted PMD data conversion |
GltfSkeletonDynamicsReader |
lib.kasuga.rendering.models.uml.typo.gltf |
glTF node physics candidate conversion |
Unless declared standalone, the code blocks on this page use the following imports; model denotes an already loaded Model:
import lib.kasuga.rendering.models.uml.dynamic.ModelInstance;
import lib.kasuga.rendering.models.uml.loaders.SkeletonDynamicsBuilder;
import lib.kasuga.rendering.models.uml.loaders.SkeletonDynamicsReader;
import lib.kasuga.rendering.models.uml.structure.skeleton.Skeleton;
import lib.kasuga.rendering.models.uml.structure.skeleton.SkeletonDynamics;
import lib.kasuga.rendering.models.uml.structure.skeleton.SkeletonDynamics.*;
import org.joml.Vector3f;
import java.util.List;
Lifecycle and Units¶
- Load the Model; the
configureSkeleton(Skeleton)hook of format metadata runs during Model construction. - Create a dynamics Builder from the Skeleton, append or override definitions, then
attach(). - Create a ModelInstance; set targets, tick loop modules, and physics.
- Evaluate through the instance's pose pipeline; on disposal, close the ModelInstance or detach physics.
Dynamics configuration should be completed before creating instances. The collections in shared definitions are immutable, and both vector constructor arguments and vector accessor results are copied,
but Bone is a structural reference, and its definition transform cannot be modified as an instance pose. Multiple instances each keep their own targets and solver corrections.
| Data | Unit/coordinates |
|---|---|
RigidBody.position, Joint.position, shape sizes, and translation ranges |
definition coordinates; the physics adaptation multiplies by Physics.unitScale |
RigidBody.rotation, Joint.rotation, and rotation ranges |
XYZ Euler, radians |
IK angles, maxRotationStep, Rotor, Hinge |
radians |
IK tolerance |
distance units in the current evaluation space; import/root scaling affects the actual corresponding scale |
Targets of setIkTarget, setFrameIkTarget, IkTargetModule |
world coordinates, Vector3f; with floating origin enabled, the double world anchor is subtracted at evaluation time |
SkeletonRagdoll.Body.position() and ordinary physics queries |
simulation-local coordinates; use the worldPosition/*World interfaces to obtain or supply world coordinates |
A float external target is already precision-limited by itself; floating origin does not restore world-coordinate fractions lost when the Vector3f was constructed.
Skeleton and SkeletonDynamics¶
SkeletonDynamics Skeleton.getDynamics();
void Skeleton.setDynamics(SkeletonDynamics dynamics);
new SkeletonDynamics(Physics physics, List<IkChain> ikChains,
List<DiamondConstraint> diamonds);
new SkeletonDynamics(Physics physics, List<IkChain> ikChains,
List<DiamondConstraint> diamonds, List<BonePoseConstraint> poseConstraints);
Skeleton uses SkeletonDynamics.EMPTY by default. It is usually mounted through a Builder after validation; direct construction and the setter
do not perform all bone ownership, chain hierarchy, joint reference, and closure validation.
| Accessor | Returns |
|---|---|
physics() |
the shared physics definition |
poseConstraints() |
unmodifiable map from target Bone to inheritance/fixed-axis constraints; empty by default with the three-argument constructor |
ikChains() |
IK chain list preserving definition order |
diamonds() |
diamond closure constraint list |
chainsByName() |
read-only Map<String, IkChain>; chain names must be unique |
ikChainsByBone() |
read-only Map<Bone, List<IkChain>>; reverse mapping from a driver bone to all chains that control it |
SkeletonDynamicsBuilder¶
new SkeletonDynamicsBuilder(Skeleton skeleton);
Construction copies the definitions already mounted on the Skeleton into the Builder; it does not automatically clear the original rig.
| Full method | Behavior |
|---|---|
Skeleton skeleton() |
current target skeleton |
Bone bone(String name) |
resolves a structural reference by bone name; unknown names throw IllegalArgumentException |
<T> SkeletonDynamicsBuilder read(T source, SkeletonDynamicsReader<? super T> reader) |
runs the Reader synchronously, returns this Builder |
SkeletonDynamicsBuilder physics(Physics definition) |
replaces the whole physics definition, preserving IK/closure |
SkeletonDynamicsBuilder physics(List<RigidBody> bodies, List<Joint> joints) |
replaces bodies/joints; unit scaling, no required profile, affine writeback, radius scale 1, no bind-pose followers |
SkeletonDynamicsBuilder ik(IkChain chain) |
adds a chain; the same chain name replaces the existing chain |
SkeletonDynamicsBuilder diamond(DiamondConstraint diamond) |
adds a constraint; the same constraint name replaces the existing constraint |
SkeletonDynamicsBuilder pose(BonePoseConstraint constraint) |
adds a bone pose constraint; the same target Bone replaces the existing constraint |
SkeletonDynamics build() |
validates and returns the definition; does not mount, create a solver, or create a native world |
SkeletonDynamics attach() |
calls build() first, then writes into the Skeleton and returns the mounted definition |
The structural validation performed by build()/attach() includes:
- Non-null body bones, bind-pose followers, and IK controller/effector/link all belong to the target Skeleton.
- A pose constraint's target and inheritance source both belong to this Skeleton; self-references and inheritance cycles are rejected.
- A joint's two rigid body indices are valid and different; the indices refer to
Physics.bodies(), notBone.index. - The IK chain is non-empty, driver bones do not repeat, and each subsequent link/effector must be a descendant of the previous link; intermediate bones may be skipped.
- A diamond closure references two existing POSITION chains; the same chain cannot belong to multiple closures.
- Closure branches do not share driver bones, their endpoints differ, the bind positions of the branch bases are no farther apart than the closure tolerance, and one branch's driver bone cannot be an ancestor of the other base.
Illegal structures throw IllegalArgumentException. Null required arguments usually throw NullPointerException.
Reader and Existing SkeletonBuilder¶
@FunctionalInterface
public interface SkeletonDynamicsReader<T> {
void read(T source, SkeletonDynamicsBuilder builder);
}
The Reader only fills generic definitions into the Builder; it does not attach() by itself. External formats may use any source type:
Skeleton skeleton = model.getSkeleton();
SkeletonDynamicsReader<String> reader = (chainName, builder) -> builder.ik(
new IkChain(chainName, builder.bone("hand-target"), builder.bone("hand"),
List.of(new IkLink(builder.bone("upper-arm")),
new IkLink(builder.bone("forearm")))));
new SkeletonDynamicsBuilder(skeleton).read("left-arm", reader).attach();
The existing SkeletonBuilder provides:
SkeletonBuilder dynamics(Consumer<SkeletonDynamicsBuilder> configure);
The callback runs after the skeleton's build(...) completes Bone/Anchor/Vertex binding, and automatically validates and mounts.
Repeated calls to dynamics(...) replace the configuration callback; clear() removes it as well. A custom ModelData may override
void configureSkeleton(Skeleton skeleton), hooking up a Reader during Model construction.
The Model construction hook of format metadata runs after the SkeletonBuilder callback and may override the physics table or same-named chains;
configuration that needs to override format defaults should go after Model loading and before ModelInstance creation.
Generic Bone Pose Constraints¶
new TransformInheritance(Bone source, float weight, boolean translation, boolean rotation);
new BonePoseConstraint(Bone bone, TransformInheritance inheritance, Vector3f fixedAxis);
Both are public records under SkeletonDynamics; they do not require a BoneData type.
The inheritance weight must be finite and may be negative; at least one of translation or rotation must be enabled. The inheritance source provides the currently evaluated local pose delta,
translation is multiplied by weight, and rotation is slerped from the identity quaternion by weight; it does not inherit the source's bind pose or world position.
The target bone's original local pose applies inheritance first, then extracts the twist along fixedAxis, and then applies IK and physics overrides.
The fixed axis is in the target bone's local coordinates; the input vector is copied and normalized, and is rejected when its squared length is less than 1e-8.
The physics override takes the final simulated pose as authoritative; this axis constraint does not replace physics joint limits.
inheritance or fixedAxis may be null, but not both.
fixedAxis() returns a copy; hasFixedAxis() queries whether an axis is defined, and fixedAxis(Vector3f destination)
copies into the caller's scratch when an axis is defined. The Builder validates skeleton ownership and inheritance cycles by bone reference.
Instances are evaluated in dependency order; cross-branch inheritance does not depend on hierarchy traversal order, and the update range is widened to cover affected vertices.
PMX/PMD bone inheritance and fixed axes are converted in MmdSkeletonDynamicsReader.read; when reading a PMX bone table alone,
you can also call MmdSkeletonDynamicsReader.readBoneConstraints(builder) and readIk(builder).
Index references of format files exist only in the Reader layer; MC or external formats just fill these definitions through the same Builder.
Physics Data¶
Physics¶
new Physics(List<RigidBody> bodies, List<Joint> joints, Vector3f unitScale,
boolean profileRequired, boolean affineWriteback,
float profileRadiusScale, Set<Bone> bindPoseFollowers);
| Parameter | Contract |
|---|---|
bodies, joints |
copied definition lists; profile/joints reference the list indices of bodies |
unitScale |
three finite positive components; used for rigid body position/size and joint translation |
profileRequired |
when true, this table cannot be enabled directly without a profile; used for candidate tables |
affineWriteback |
when true, computes the local physics transform inversely within the full affine parent hierarchy, preserving scale/shear |
profileRadiusScale |
finite positive number; radius scale of generated profile capsules |
bindPoseFollowers |
follower bones without a direct physics body; they can follow the bind-to-current affine delta of the nearest physics ancestor |
Physics.EMPTY: empty tables, unitScale=(1,1,1), profileRequired=false,
affineWriteback=true, profileRadiusScale=1, empty follower set.
RigidBody¶
new RigidBody(String name, String alias, Bone bone, int collisionGroup,
int nonCollisionMask, int shape, Vector3f size, Vector3f position,
Vector3f rotation, float mass, float linearDamping,
float angularDamping, float restitution, float friction, int mode);
| Parameter | Contract |
|---|---|
name, alias |
non-null display/auxiliary names; they are not required to be bone names; alias may be an empty string |
bone |
may be null, meaning a body not bound to a bone; when non-null it must belong to the Skeleton |
collisionGroup |
integer 0..63 |
nonCollisionMask |
integer filter mask; the physics adaptation preserves exclusion layer semantics |
shape |
SPHERE=0, BOX=1, CAPSULE=2 |
size |
finite non-negative vector; spheres use the x radius, boxes use xyz half-extents, capsules use x radius / full height of the y cylinder segment |
position, rotation |
body position in definition coordinates and XYZ Euler orientation; both finite |
mass |
finite non-negative mass; 0 produces no dynamic inverse mass |
linearDamping, angularDamping |
finite non-negative damping |
restitution, friction |
finite non-negative material parameters |
mode |
the motion/writeback mode in the table below |
| Constant | Value | Runtime behavior |
|---|---|---|
KINEMATIC |
0 | rigid body driven by animation targets |
DYNAMIC |
1 | physics writes back the full pose |
DYNAMIC_ROTATION |
2 | dynamic body; writes back only the bone rotation, preserving animation translation |
Definition construction allows non-negative sizes; when collision shapes are actually created, sphere/capsule radii and all three box half-extents must be positive. Creating physics bodies may therefore reject degenerate shapes further.
Joint¶
new Joint(String name, String alias, int rigidBodyA, int rigidBodyB,
Vector3f position, Vector3f rotation, Vector3f positionMin,
Vector3f positionMax, Vector3f rotationMin, Vector3f rotationMax,
Vector3f positionSpring, Vector3f rotationSpring);
name/alias are non-null, and all vectors are finite and copied. rigidBodyA/B must be valid and different during Builder validation.
position/rotation is the shared joint frame, *Min/*Max are the author limits, and *Spring are the author spring parameters.
The current model adapter maps this set of six-axis author parameters to a Box3D spherical cone/twist; translation is tightened to a fixed anchor.
Other native joints are created through the Physics API and are not selected by this record's type field.
Physics Example Without Format Metadata¶
var builder = new SkeletonDynamicsBuilder(model.getSkeleton());
var body = new RigidBody("torso-body", "", builder.bone("torso"),
0, 0, RigidBody.BOX, new Vector3f(0.2f, 0.3f, 0.1f),
new Vector3f(0, 1, 0), new Vector3f(),
2f, 0.05f, 0.1f, 0f, 0.6f, RigidBody.DYNAMIC);
builder.physics(List.of(body), List.of()).attach();
var instance = new ModelInstance(model, null, null, null, null, null);
var ragdoll = instance.enablePhysics();
if (ragdoll != null) {
ragdoll.setGravity(new Vector3f(0, -9.80665f, 0));
// Called once per frame by the host; instances already wired into the Minecraft runtime are advanced by that runtime.
instance.evaluatePhysicsFrame(0f, 1f / 60f);
}
// On lifecycle end: instance.detachPhysics() or instance.close().
The high-level enablePhysics returns null when the native library is unavailable; it throws IllegalArgumentException when the library is available but bodies are empty,
or when profileRequired=true and no profile is passed.
Body.source() returns this generic RigidBody, and Joint.source() returns this generic Joint.
IK Data and Limits¶
IkLink, RotationLimit, and IkJoint¶
new IkLink(Bone bone);
new IkLink(Bone bone, RotationLimit limit);
new IkLink(Bone bone, RotationLimit limit, IkJoint joint);
new RotationLimit(Vector3f minimum, Vector3f maximum);
new Rotor(float angle);
new Hinge(Vector3f axis, Vector3f reference, float minimum, float maximum);
| Type | Parameters and behavior |
|---|---|
IkLink |
bone required; limit/joint may be null; the omitted fields of the two simplified constructors are null |
RotationLimit |
finite XYZ Euler lower/upper bounds, per-axis minimum ≤ maximum; applies to the IK local correction |
IkJoint |
sealed interface, permits Rotor and Hinge |
Rotor |
finite angle 0..π; the first segment revolves around the uncorrected pose direction, later segments are relative to the previous segment's direction |
Hinge |
axis/reference are in the driver's uncorrected local frame; non-zero, automatically normalized, orthogonality error ≤ 1e-4; angle in [-π,π] and minimum ≤ maximum |
Rotor/Hinge constrain position solving in Caliko; RotationLimit projects onto the local correction. When both are given, both restrictions participate, but Euler box projection does not guarantee global convergence for complex constraints. Chains that have already reached the target do not choose another solution.
IkChain¶
new IkChain(String name, Bone controller, Bone effector, List<IkLink> links);
new IkChain(String name, Bone controller, Bone effector, List<IkLink> links,
int iterations, float tolerance, float maxRotationStep,
boolean replaceAuthoredRotation, TargetMode targetMode);
| Parameter | Simplified-construct default | Contract |
|---|---|---|
name |
required | non-blank chain name; control and diagnostics address it by this name, and it is not required to equal the controller bone name |
controller |
required | default target source bone |
effector |
required | final effector bone |
links |
required | non-empty, from base to tip; the final link points to the effector |
iterations |
32 | 1..256; caps the adaptation iterations and the library's attempt count |
tolerance |
1e-4f |
finite positive distance |
maxRotationStep |
π | finite non-negative value, the maximum angle of each direction-alignment increment; 0 limits that increment to zero, and subsequent Euler projection can still adjust the correction |
replaceAuthoredRotation |
false | true takes over the chain bones' authored local pose; the current implementation starts from the identity local transform and skips even authored translation/scale, while morph/grant/fixed-axis still participate afterwards |
targetMode |
POSITION |
non-null; modes below |
POSITION uses the controller's current absolute position as the default target.
DIRECTION determines orientation from the bind bone-segment direction and the controller's rotation difference when there is no external target, ignoring its pure translation.
When a persistent or single-tick external target exists, it switches to position blending; this mode does not interpret the external Vector3f as a direction vector.
var builder = new SkeletonDynamicsBuilder(model.getSkeleton());
var elbow = new Hinge(new Vector3f(0, 0, 1), new Vector3f(1, 0, 0),
-(float) Math.PI / 2f, 0f);
builder.ik(new IkChain("left-arm", builder.bone("hand-target"), builder.bone("hand"),
List.of(new IkLink(builder.bone("upper-arm")),
new IkLink(builder.bone("forearm"), null, elbow)))).attach();
This hinge example assumes the forearm's bind direction is local +X and the bend axis is +Z; real assets need to fill in their own bone frame.
Diamond Closure¶
new DiamondConstraint(String name, String firstChain, String secondChain);
new DiamondConstraint(String name, String firstChain, String secondChain,
int iterations, float tolerance);
The simplified constructor uses iterations=32 and tolerance=1e-4f. The name is non-blank, the two chain names are required and different,
iterations is 1..256, and tolerance is a finite positive number. Branch requirements are validated by the Builder, see its structural validation list.
var builder = new SkeletonDynamicsBuilder(model.getSkeleton());
var left = new IkChain("left-linkage", builder.bone("closure-target"), builder.bone("left-tip"),
List.of(new IkLink(builder.bone("left-base")), new IkLink(builder.bone("left-mid"))));
var right = new IkChain("right-linkage", builder.bone("closure-target"), builder.bone("right-tip"),
List.of(new IkLink(builder.bone("right-base")), new IkLink(builder.bone("right-mid"))));
builder.ik(left).ik(right)
.diamond(new DiamondConstraint("linkage", left.name(), right.name()))
.attach();
The two bases should coincide at the bind pose position and drive separate hierarchies; the two endpoints represent the same closure point. The two controllers may be the same bone or have separate targets; solving starts from the midpoint of the two targets. Disabling either chain pauses the closure; when branches belong to a closure they are not first solved as independent chains. The constraint only guarantees position closure; it does not guarantee equal endpoint orientation, equal side lengths, or native mechanical feedback.
SkeletonInstance Runtime Control¶
var skeleton = instance.getSkeletonInstance();
In the table below, name always denotes an IK chain name. The existing parameter names boneName/controllerBone are historical.
| Method signature | Returns/Behavior |
|---|---|
boolean setIkEnabled(String name, boolean enabled) |
returns false for an undefined chain; on success requires re-evaluation |
boolean isIkEnabled(String name) |
reads the toggle, default true; not an existence check, unknown chains also return true |
void resetIkEnabled() |
clears overrides, restoring the default true |
boolean clearIkEnabled(String name) |
clears an individual chain's explicit toggle; returns true when state was removed |
boolean setIkTarget(String name, Vector3f worldTarget, float weight) |
persistent target; false for an undefined chain; copies the target and requires an update |
boolean clearIkTarget(String name) |
clears the persistent target; returns false when there is no target |
void clearIkTargets() |
clears all persistent targets |
boolean setFrameIkTarget(String name, Vector3f worldTarget, float weight) |
transient target for the current pose pipeline cycle; false for an undefined chain |
void clearFrameIkTargets() |
clears transient targets; ModelTickLoop calls it automatically at the start of a cycle |
void updateTransform() |
evaluates hierarchy, IK, and final hierarchy; manual hosts call it according to their own evaluation order |
void updateTransformAfterPhysics() |
rebuilds the hierarchy after writeback, preserving solved IK corrections without solving IK again |
Map<String, CalikoIkSolver.SolveResult> ikSolveResults() |
read-only diagnostic view of the most recent IK solve |
Targets must be non-null and finite, and weight must be finite and within [0,1]; otherwise the corresponding argument exception is thrown.
Blending runs from the controller's current position to the external position; weight is not "the strength of enabling IK".
Transient targets take precedence over persistent targets; unknown chains return false before the target value is validated.
Setting a target only marks the input as changed; it does not solve immediately. Afterwards run the instance's normal evaluation entry point.
var skeleton = instance.getSkeletonInstance();
boolean accepted = skeleton.setIkTarget("left-arm", new Vector3f(1, 2, 0), 1f);
instance.updateImmediate();
var result = skeleton.ikSolveResults().get("left-arm");
The accessors of SolveResult(float residual, boolean satisfied) are residual() and satisfied().
For an ordinary chain, residual is the distance from the actual endpoint to this target; for a closure, it is the larger of the two endpoint distance and the two base distance.
Closure branch results correspond to the most recent shared target and do not mean that the branch's original controller target was necessarily reached.
satisfied only expresses that the corresponding position residual is within tolerance; it is not a complete angular/dynamics acceptance.
Disabled or unrun chains have no result for that solve; the Map is a live read-only view that is cleared and updated on the next solve; copy it yourself if you need to keep a snapshot.
Per-Tick Targets: IkTargetModule¶
new IkTargetModule(String name, Vector3f worldTarget);
new IkTargetModule(String name, Vector3f worldTarget, float weight);
The two-argument constructor uses weight 1 and initial enabled true.
Accessors: controllerBone() (chain name), target() (copied vector), weight(), enabled().
Control methods: void setTarget(Vector3f), void setTarget(Vector3f,float), void setEnabled(boolean).
Setting the target preserves the enabled state; the one-argument setter preserves the current weight.
var target = new lib.kasuga.rendering.models.uml.dynamic.tick_loop.handler.IkTargetModule(
"left-arm", new Vector3f(1, 2, 0));
instance.getTickLoop().addPreIk("hand-target-input", target);
target.setTarget(new Vector3f(1.2f, 2, 0), 0.6f);
target.setEnabled(false);
The constructor only validates that the name is non-blank and the target values; it does not verify that the chain exists. Chain names are resolved only when the module is published to an instance at runtime.
addPreIk places the module before IK and after the default apply; transient targets are consumed by both IK and physics within the same cycle.
When you need to write pending transforms for the default apply to consume, use the tick pipeline's addBefore(SLOT_APPLY, ...).
Actual Default Behavior of Format Readers¶
| Reader | Read interface | Default mapping |
|---|---|---|
MmdSkeletonDynamicsReader |
void read(MmdModelData, SkeletonDynamicsBuilder) |
authored rigid body order, direct Bone references, valid joints, imported unitScale; no required profile, rigid writeback, profile radius scale 1 |
| same as above | static void readIk(SkeletonDynamicsBuilder) |
converts only PMX IK already attached to bones; usable for skeletons without a full tail |
| same as above | static void readBoneConstraints(SkeletonDynamicsBuilder) |
converts PMX inheritance/fixed axes into generic constraints; the full read calls it automatically |
GltfSkeletonDynamicsReader |
void read(GltfModelData, SkeletonDynamicsBuilder) |
generates candidates in node order; requires an explicit profile, affine writeback, skin bone bind followers; does not guess/create IK automatically |
MMD uses the controller bone name as the chain name, and reverses chains from the file's tip-to-base to base-to-tip; positive iteration counts
are capped at 256, tolerance is 1e-4f, the step angle takes the absolute value of the original limit, and authored local pose takeover is enabled.
Expressible single-axis Euler limits are converted to Hinge; other box limits keep RotationLimit.
DIRECTION is used when there is a single link, the controller/effector bind positions coincide, and the controller has a vector tail.
Chains without a valid effector/link or with a non-positive iteration count do not enter the definition. Invalid or self-connected PMX joints do not enter the simulatable table.
The external indices of glTF profiles continue to correspond to node order; MMD profiles correspond to the original rigid body order.
Both sources complete conversion at the Reader boundary, so at runtime Body.source().bone() directly yields a generic bone reference.
Solver Adaptation for Custom Hosts¶
CalikoIkSolver(Skeleton skeleton, PoseAccess pose) provides void solve() and
Map<String, SolveResult> results(). It is usually managed by SkeletonInstance; when used directly, the host implements:
| PoseAccess method | Host responsibility |
|---|---|
Transform absolute(Bone bone) |
the evaluated absolute pose |
Transform correction(Bone bone) |
mutable per-instance local IK correction |
Vector3f target(IkChain chain) |
returns a new vector for this target; closures modify the returned value to solve for the shared target |
boolean enabled(String chain) |
chain toggle |
void refresh(Bone driver, Bone endpoint) |
after correction, synchronously rebuild the affected hierarchy; subsequent reads must see the latest pose |
The host is responsible for animation/physics evaluation order, correction cleanup, and thread ownership. The solver has mutable state and cannot solve the same instance concurrently.
The current library is the official Caliko 1.3.8 core; dependency notes and licenses are included under modules/render-core/libs.
Source Entry Points¶
The classes for this page are all in the render-core module; see the "Types and Packages" table for package paths:
SkeletonDynamicsSkeletonDynamicsBuilderSkeletonDynamicsReaderSkeletonInstanceCalikoIkSolver