retarget static method
dynamic
retarget(
- dynamic target,
- dynamic source, [
- dynamic options
Implementation
static retarget(target, source, [options]) {
var pos = Vector3(),
quat = Quaternion(),
scale = Vector3(),
bindBoneMatrix = Matrix4(),
relativeMatrix = Matrix4(),
globalMatrix = Matrix4();
options = options ?? {};
options.preserveMatrix = options.preserveMatrix ?? true;
options.preservePosition = options.preservePosition ?? true;
options.preserveHipPosition = options.preserveHipPosition ?? false;
options.useTargetMatrix = options.useTargetMatrix ?? false;
options.hip = options.hip ?? 'hip';
options.names = options.names ?? {};
var sourceBones = source.isObject3D ? source.skeleton.bones : getBones(source),
bones = target.isObject3D ? target.skeleton.bones : getBones(target);
var bindBones, bone, name, boneTo, bonesPosition;
// reset bones
if (target.isObject3D) {
target.skeleton.pose();
} else {
options.useTargetMatrix = true;
options.preserveMatrix = false;
}
if (options.preservePosition) {
bonesPosition = [];
for (var i = 0; i < bones.length; i++) {
bonesPosition.push(bones[i].position.clone());
}
}
if (options.preserveMatrix) {
// reset matrix
target.updateMatrixWorld();
target.matrixWorld.identity();
// reset children matrix
for (var i = 0; i < target.children.length; ++i) {
target.children[i].updateMatrixWorld(true);
}
}
if (options.offsets) {
bindBones = [];
for (var i = 0; i < bones.length; ++i) {
bone = bones[i];
name = options.names[bone.name] || bone.name;
if (options.offsets && options.offsets[name]) {
bone.matrix.multiply(options.offsets[name]);
bone.matrix.decompose(bone.position, bone.quaternion, bone.scale);
bone.updateMatrixWorld();
}
bindBones.push(bone.matrixWorld.clone());
}
}
for (var i = 0; i < bones.length; ++i) {
bone = bones[i];
name = options.names[bone.name] || bone.name;
boneTo = getBoneByName(name, sourceBones);
globalMatrix.copy(bone.matrixWorld);
if (boneTo) {
boneTo.updateMatrixWorld();
if (options.useTargetMatrix) {
relativeMatrix.copy(boneTo.matrixWorld);
} else {
relativeMatrix.copy(target.matrixWorld).invert();
relativeMatrix.multiply(boneTo.matrixWorld);
}
// ignore scale to extract rotation
scale.setFromMatrixScale(relativeMatrix);
relativeMatrix.scale(scale.set(1 / scale.x, 1 / scale.y, 1 / scale.z));
// apply to global matrix
globalMatrix.makeRotationFromQuaternion(quat.setFromRotationMatrix(relativeMatrix));
if (target.isObject3D) {
var boneIndex = bones.indexOf(bone),
wBindMatrix = bindBones
? bindBones[boneIndex]
: bindBoneMatrix.copy(target.skeleton.boneInverses[boneIndex]).invert();
globalMatrix.multiply(wBindMatrix);
}
globalMatrix.copyPosition(relativeMatrix);
}
if (bone.parent && bone.parent.isBone) {
bone.matrix.copy(bone.parent.matrixWorld).invert();
bone.matrix.multiply(globalMatrix);
} else {
bone.matrix.copy(globalMatrix);
}
if (options.preserveHipPosition && name == options.hip) {
bone.matrix.setPosition(pos.set(0, bone.position.y, 0));
}
bone.matrix.decompose(bone.position, bone.quaternion, bone.scale);
bone.updateMatrixWorld();
}
if (options.preservePosition) {
for (var i = 0; i < bones.length; ++i) {
bone = bones[i];
name = options.names[bone.name] || bone.name;
if (name != options.hip) {
bone.position.copy(bonesPosition[i]);
}
}
}
if (options.preserveMatrix) {
// restore matrix
target.updateMatrixWorld(true);
}
}