three-ik

repository·master·Indexed 20 days ago

https://github.com/jsantell/three.ik

An Inverse Kinematics library for Three.js (v0.1.0) that enables the creation of articulated bone chains that automatically follow target objects. It provides a FABRIK-based solver via the IK class, supporting IKChain and IKJoint configurations, rotational limits through IKBallConstraint, and a dedicated IKHelper for scene visualization.

Tokens
3.7K
Snippets
13
Records
15
Agent score
69%

What's inside three-ik

  1. Use three.ik via global THREE namespace

    master
    If you are including the library via a <script> tag in an environment where THREE is already defined globally, three.ik will automatically attach its exports to the THREE object. This allows you to access the IK tools via THREE.IK, THREE.IKChain, etc.
  2. Configure IKChain iterations and tolerance

    master

    The IKChain class maintains internal properties to control the FABRIK solver's precision and performance:

    • iterations: The maximum number of solver iterations (default: 100). Increasing this improves accuracy at the cost of performance.
    • tolerance: The distance threshold to stop iterating (default: 0.01).
  3. Configure IKHelper visualization options

    master

    When instantiating IKHelper, you can pass a configuration object to customize the visual representation of the IK system.

    Constructor Options:

    • color (THREE.Color): The color of the bones. Defaults to 0xff0077.
    • showBones (boolean): Whether to render the bone meshes. Defaults to true.
    • showAxes (boolean): Whether to render the AxesHelper for each joint. Defaults to true.
    • wireframe (boolean): Whether to render bones as wireframes. Defaults to true.
    • boneSize (number): The thickness/size of the bone mesh. Defaults to 0.1.
    • axesSize (number): The size of the axes helper. Defaults to 0.2.

    Dynamic Properties: You can update these properties on an existing IKHelper instance at runtime to toggle visibility or change appearance without re-instantiating.

    // Example of updating properties dynamically
    helper.showBones = false;
    helper.showAxes = true;
    helper.wireframe = false;
    helper.color = new THREE.Color(0xff0000);
  4. Implement Inverse Kinematics with THREE.IK

    master

    To implement Inverse Kinematics (IK) in a Three.js scene, you must set up a THREE.IK system, define an IKChain consisting of IKJoint objects, and call ik.solve() within your animation loop.

    Key steps include:

    1. Initialize the IK system: Create an instance of THREE.IK.
    2. Define a chain: Create a THREE.IKChain and populate it with THREE.IKJoint instances. Each joint wraps a THREE.Bone.
    3. Set constraints: Pass an array of constraints (e.g., THREE.IKBallConstraint) to the IKJoint constructor to limit bone movement.
    4. Define the end effector: The final joint in the chain must be assigned a target (typically a THREE.Object3D or THREE.Mesh) via the options object in chain.add().
    5. Register the chain: Add the chain to the IK system using ik.add(chain).
    6. Scene Integration: Add the root bone (retrieved via ik.getRootBone()) and an THREE.IKHelper(ik) to the scene for visualization.
    7. Solve: Call ik.solve() inside the requestAnimationFrame loop to update bone positions based on the target's movement.
    // 1. Setup IK system
    const ik = new THREE.IK();
    const chain = new THREE.IKChain();
    const constraints = [new THREE.IKBallConstraint(90)];
    const bones = [];
    
    // 2. Create a target for the end effector
    const movingTarget = new THREE.Mesh(new THREE.SphereGeometry(0.1), new THREE.MeshBasicMaterial({ color: 0xff0000 }));
    movingTarget.position.z = 2;
    scene.add(movingTarget);
    
    // 3. Build the bone chain
    for (let i = 0; i < 10; i++) {
      const bone = new THREE.Bone();
      bone.position.y = i === 0 ? 0 : 0.5;
      if (bones[i - 1]) { bones[i - 1].add(bone); }
      bones.push(bone);
    
      // The last joint must have the target assigned
      const target = i === 9 ? movingTarget : null;
      chain.add(new THREE.IKJoint(bone, { constraints }), { target });
    }
    
    // 4. Add chain to system and scene
    ik.add(chain);
    scene.add(ik.getRootBone());
    
    // 5. Add visualization helper
    const helper = new THREE.IKHelper(ik);
    scene.add(helper);
    
    // 6. Animation loop
    function animate() {
      // Move target or pivot...
      ik.solve();
      renderer.render(scene, camera);
      requestAnimationFrame(animate);
    }
    
    animate();
  5. Initialize an IKJoint with a bone and constraints

    master

    The IKJoint class represents a single joint within an Inverse Kinematics (IK) chain. It wraps a THREE.Bone and manages its world position, direction, and constraints.

    To create an IKJoint, pass a THREE.Bone instance and an optional configuration object. The configuration object can include a constraints array containing objects that implement an _apply(joint) method (such as IKBallConstraint).

    import IKJoint from './IKJoint.js';
    
    // Assuming 'bone' is an existing THREE.Bone instance
    const joint = new IKJoint(bone, {
      constraints: [/* array of IKConstraint objects */]
    });
  6. Connect multiple IKChains

    master

    You can link multiple IKChain instances together using the .connect(chain) method. This is used to create complex hierarchical structures where one chain's movement influences another.

    Requirements for connection:

    • The chain being connected must be an instance of IKChain.
    • The base joint of the new chain must already be a member of the parent chain.
    • You cannot append a new chain to the end joint of a parent chain if that parent chain already has an end effector.
    • When connected, the base joint of the child chain is marked as a sub-base within the parent chain.
    // Assuming 'parentChain' and 'childChain' are already created
    // and childChain.base is a joint already inside parentChain
    parentChain.connect(childChain);
  7. Import the three.ik public API

    master

    The three.ik package provides Inverse Kinematics (IK) capabilities for Three.js. You can import the core classes using ES modules:

    • IK: The main IK solver engine.
    • IKChain: Represents a chain of joints for IK solving.
    • IKJoint: Represents an individual joint within a chain.
    • IKBallConstraint: Defines rotational constraints for a joint.
    • IKHelper: A utility for visualizing the IK setup in a Three.js scene.
    import { IK, IKChain, IKJoint, IKBallConstraint, IKHelper } from 'three-ik';
  8. Update IKHelper position in the scene

    master

    The IKHelper synchronizes its internal meshes with the world matrices of the joints in the IK system. To ensure the visual helper matches the current state of the IK simulation, you should call updateMatrixWorld() on the helper (or ensure your animation loop calls it) so that it copies the matrixWorld from each joint's bone to the corresponding helper mesh.

    // In your animation loop
    function animate() {
      requestAnimationFrame(animate);
      
      // ... update your IK logic ...
      
      // Synchronize the helper with the updated joint matrices
      helper.updateMatrixWorld();
      
      renderer.render(scene, camera);
    }
  9. Manage multiple IK chains with the IK class

    master

    The IK class serves as the central controller for managing one or more IKChain instances. It handles the hierarchical ordering of chains (ensuring subchains are processed in the correct depth order) and executes the global solve() method to update all bone positions within the system.

    To use the IK system, instantiate IK, add your IKChain objects using the add() method, and call solve() to perform the Inverse Kinematics calculations.

    import IK from './IK.js';
    import IKChain from './IKChain.js';
    
    const ikSystem = new IK();
    
    // Assuming 'myChain' is a valid instance of IKChain
    ikSystem.add(myChain);
    
    // Perform the IK solution and update bones
    ikSystem.solve();
  10. Create an IKChain and add joints

    master

    An IKChain represents a kinematic chain composed of multiple IKJoint objects or THREE.Bone objects. You build a chain by calling .add(joint, config) sequentially. The first joint added becomes the base of the chain. If you provide a target in the config of a joint, that joint becomes the effector of the chain.

    Constraints:

    • You cannot add more joints to a chain once an end effector has been defined.
    • Joints must be instances of IKJoint or THREE.Bone.
    • Adjacent joints cannot have a distance of 0 between them.
    import IKChain from 'three-ik/IKChain';
    import IKJoint from 'three-ik/IKJoint';
    // ... setup three.js scene/bones ...
    
    const chain = new IKChain();
    
    // Add the first joint (the base)
    chain.add(new IKJoint(bone1));
    
    // Add subsequent joints
    chain.add(new IKJoint(bone2));
    
    // Add the final joint and define it as the effector with a target
    chain.add(new IKJoint(bone3), { target: targetObject });
  11. Visualize an IK system with IKHelper

    master

    The IKHelper class is a THREE.Object3D used to visually debug and represent Inverse Kinematics (IK) chains and bones in a Three.js scene. It automatically creates meshes and axes helpers for each joint in the provided IK instance.

    To use it, pass an existing IK instance and an optional configuration object to the constructor. The helper must be added to your Three.js scene to be visible.

    import IKHelper from 'three-ik/IKHelper'; // Adjust path based on your installation
    
    // Assuming 'ik' is an existing IK instance
    const helper = new IKHelper(ik, {
      color: 0x00ff00,
      showBones: true,
      showAxes: true,
      wireframe: true,
      boneSize: 0.1,
      axesSize: 0.2
    });
    
    scene.add(helper);
  12. Solve the IK system with solve()

    master

    The solve() method performs the Inverse Kinematics solution across all registered chains. It automatically handles the depth-sorting of chains to ensure that subchains are updated relative to their parents correctly.

    When solve() is called, it:

    1. Generates a depth-sorted array of chains if it hasn't been done yet.
    2. Iterates through the chains to update joint world positions.
    3. Runs the forward and backward steps of the IK algorithm for each chain to minimize the distance to targets.
    /**
     * Performs the IK solution and updates bones.
     */
    solve() {
      // ... implementation details ...
    }