Help With Walk Animation using IK Solver

Trying to get a walk cycle working in Threejs using the CCDIkSolver. I’ve been using the MMD loader as an example and trying to use that as a guide for the syntax and structure needed for the CCD Solver to work, but I’m still running into issues.

Right now this is the output that I have:

And this is a preview of what the animation should look like.

Right now my general issue that the target bone seems to get pretty far away from the effector, and rather than the desired effect of having the knee bend to follow the target, the leg with bend out in weird areas. The live version of the page is here: Shenmoo and the repository is here: DashGL / Shenmoo · GitLab.

Edit:

I might as well post my notes here in case it helps for context.

Skeleton

In terms of bones, the model has 38 bones numbered 0-37 that form the skeleton of the model. There are four IK targets that for the right foot, left foot, right hand, left hand. There are numbered 38, 39, 40, 41, bringing the total to 42 bones.

In terms of timing, all of the bones need to be created in an array to create the skeleton to bind to the skinned mesh. After the mesh has been created, the IK targets have no parent, and the mesh need to be set as the parent for these to work.

CCDIKSolver

The arguments for the CCDIKSolver are the skinned mesh, and an iks array. We can grab an example iks array from the MMD loader.

[
  {
    "target": 89,
    "effector": 42,
    "iteration": 40,
    "maxAngle": 2,
    "links": [
      {
        "index": 41,
        "enabled": true,
        "limitation": {
          "x": 1, "y": 0, "z": 0
        }
      },
      {
        "index": 40,
        "enabled": true
      }
    ]
  },
  ...
] 

Which is an example for one of the legs. The target is the index of the ik target bone, which is included in the list of bones for the skeleton, but the parent is set as the mesh directly. The effector is the bone that will attempt to follow the target, 42 is labeled as “左足首”/“left ankle”.

The links are the chain that will be solved in order to affect the parent bones. The in this case it seems to go in order from child to parent (which is contrary to what the documentation says). Bone 41is “左ひざ”/“left knee”, and bone 40 is “左足”/“left leg”.

Okay, solved!

So the issue with the CCD solver is that it doesn’t like when bones have pre-rotation. In this case the bone structure uses rotation and position to dictate where the skeleton should be.

if (!parentBone) {

    bone.position.x = this.bone.position.x;
    bone.position.y = this.bone.position.y;
    bone.position.z = this.bone.position.z;
    bone.updateMatrix();
    bone.updateMatrixWorld();

} else {
    parentBone.add(this.bone);
    let p = this.bones[parentBone.userData.id];
    p.add(bone);
    this.bone.updateMatrix();
    this.bone.updateMatrixWorld();

    const pb = new THREE.Vector3();
    const cb = new THREE.Vector3();

    pb.applyMatrix4(parentBone.matrixWorld)
    cb.applyMatrix4(this.bone.matrixWorld)

    bone.position.x = cb.x - pb.x;
    bone.position.y = cb.y - pb.y;
    bone.position.z = cb.z - pb.z;

    bone.updateMatrix();
    bone.updateMatrixWorld();
}

So what I ended up doing is taking the world position from the bones to create a separate skeleton with only the position set with no rotation to pass into the IK solver, and that seems to be producing the correct results.