retargetClip static method

dynamic retargetClip(
  1. dynamic target,
  2. dynamic source,
  3. dynamic clip, [
  4. dynamic options,
])

Implementation

static retargetClip(target, source, clip, [options]) {
  options = options ?? {};

  options.useFirstFramePosition = options.useFirstFramePosition ?? false;
  options.fps = options.fps ?? 30;
  options.names = options.names ?? [];

  if (!source.isObject3D) {
    source = getHelperFromSkeleton(source);
  }

  var numFrames = Math.round(clip.duration * (options.fps / 1000) * 1000),
      delta = 1 / options.fps,
      convertedTracks = <KeyframeTrack>[],
      mixer = AnimationMixer(source),
      bones = getBones(target.skeleton),
      boneDatas = [];
  var positionOffset, bone, boneTo, boneData, name;

  mixer.clipAction(clip)?.play();
  mixer.update(0);

  source.updateMatrixWorld();

  for (var i = 0; i < numFrames; ++i) {
    var time = i * delta;

    retarget(target, source, options);

    for (var j = 0; j < bones.length; ++j) {
      name = options.names[bones[j].name] || bones[j].name;

      boneTo = getBoneByName(name, source.skeleton);

      if (boneTo) {
        bone = bones[j];
        boneData = boneDatas[j] = boneDatas[j] ?? {"bone": bone};

        if (options.hip == name) {
          if (!boneData.pos) {
            boneData.pos = {"times": Float32Array(numFrames), "values": Float32Array(numFrames * 3)};
          }

          if (options.useFirstFramePosition) {
            if (i == 0) {
              positionOffset = bone.position.clone();
            }

            bone.position.sub(positionOffset);
          }

          boneData.pos.times[i] = time;

          bone.position.toArray(boneData.pos.values, i * 3);
        }

        if (!boneData.quat) {
          boneData.quat = {"times": Float32Array(numFrames), "values": Float32Array(numFrames * 4)};
        }

        boneData.quat.times[i] = time;

        bone.quaternion.toArray(boneData.quat.values, i * 4);
      }
    }

    mixer.update(delta);

    source.updateMatrixWorld();
  }

  for (var i = 0; i < boneDatas.length; ++i) {
    boneData = boneDatas[i];

    if (boneData) {
      if (boneData.pos) {
        convertedTracks.add(VectorKeyframeTrack(
            '.bones[${boneData.bone.name}].position', boneData.pos.times, boneData.pos.values, null));
      }

      convertedTracks.add(QuaternionKeyframeTrack(
          '.bones[${boneData.bone.name}].quaternion', boneData.quat.times, boneData.quat.values, null));
    }
  }

  mixer.uncacheAction(clip);

  return AnimationClip(clip.name, -1, convertedTracks);
}