#Character movement animation

1 messages · Page 1 of 1 (latest)

shadow bear
#

Your animation contains root motion. You can see if you stop moving your character programmatically, just playing the animation will already move the character (although it pops back to the original position once the clips loops).

You can now either use a different animation without root motion (i.e. if you're using Mixamo animations you can export the animations with the "in place" checkbox selected), or you modify the animations in Blender so that the character always runs in place, or you extract the root motion from the clip programmatically.

The following snippet will extract the root motion from the clip. You might need to find the name of the root motion track in your animation clip (look for the vector track that moves the furthest over its lifetime)

#
function extractRootMotionPosition(rootNode: Object3D, targetClip: AnimationClip, readOnly?: boolean, trackName?: string): RootMotionTranslationData {

  if (trackName == undefined) {
    const rootBone = getRootBone(rootNode);
    trackName = (rootBone.name || rootBone.uuid) + '.position';
  }

  const track = targetClip.tracks.find((track) => track.name === trackName);
  if (track == undefined) {
    throw new Error(`THREE.SkeletonUtils: Track ${trackName} not found.`);
  }


  const startTime = track.times[0];
  const endTime = track.times[track.times.length - 1];
  const duration = endTime - startTime;
  const values = new BufferAttribute(track.values, 3);

  const itemsPerKeyframe = track.getValueSize() / 3; // 1 (value), or 3 (inTan,value,outTan)
  const itemOffset = (itemsPerKeyframe === 3) ? 1 : 0;

  const startPosition = new Vector3().fromBufferAttribute(values, itemOffset);
  const endPositionIndex = values.count - itemsPerKeyframe + itemOffset;
  const endPosition = new Vector3().fromBufferAttribute(values, endPositionIndex);

  const averageVelocity = new Vector3();

  averageVelocity
    .copy(endPosition)
    .sub(startPosition)
    .divideScalar(duration);

  const position = new Vector3();

  for (let i = 0, il = track.times.length; i < il; i++) {
    const dt = track.times[i] - startTime;

    position.fromBufferAttribute(values, i + itemOffset);

    position.x -= averageVelocity.x * dt;
    position.y -= averageVelocity.y * dt;
    position.z -= averageVelocity.z * dt;

    values.setX(i + itemOffset, position.x);
    values.setY(i + itemOffset, position.y);
    values.setZ(i + itemOffset, position.z);
  }

  const resultObject = {
    startPosition,
    endPosition,
    totalDistance: startPosition.distanceTo(endPosition),
    averageVelocity,
    averageSpeed: averageVelocity.length()
  }

  return resultObject;
}