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;
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;
}