retarget static method

void retarget(
  1. Object3D target,
  2. dynamic source, [
  3. SkeletonUtilsOptions? options
])

Implementation

static void retarget(Object3D target, source, [SkeletonUtilsOptions? options]) {
  final quat = Quaternion(),
      scale = Vector3(),
      relativeMatrix = Matrix4(),
      globalMatrix = Matrix4();

  options ??= SkeletonUtilsOptions();

  List<Bone> sourceBones = source is Object3D ? (source.skeleton?.bones ?? []) : getBones(source);
  List<Bone> bones = target.skeleton?.bones ?? [];
  Bone bone;
  String? name;
  Bone? boneTo;
  List<Vector3> bonesPosition = [];

  // reset bones

  // if (target is Object3D) {
    target.skeleton?.pose();
  // }
  // else {
  //   options.useTargetMatrix = true;
  //   options.preserveMatrix = false;
  // }

  if ( options.preserveBonePositions ) {
    bonesPosition = [];

    for (int i = 0; i < bones.length; i ++ ) {
      bonesPosition.add( bones[ i ].position.clone() );
    }
  }

  if ( options.preserveBoneMatrix ) {
    target.updateMatrixWorld();
    target.matrixWorld.identity();

    for (int i = 0; i < target.children.length; ++ i ) {
      target.children[ i ].updateMatrixWorld( true );
    }
  }

  for (int i = 0; i < bones.length; ++ i ) {
    bone = bones[ i ];
    name = getBoneName( bone, options );

    boneTo = getBoneByNameList( name!, sourceBones );

    globalMatrix.setFrom( bone.matrixWorld );

    if ( boneTo != null) {
      boneTo.updateMatrixWorld();

      if ( options.useTargetMatrix ) {
        relativeMatrix.setFrom( boneTo.matrixWorld );
      }
      else {
        relativeMatrix.setFrom( target.matrixWorld ).invert();
        relativeMatrix.multiply( boneTo.matrixWorld );
      }

      // ignore scale to extract rotation

      scale.setFromMatrixScale( relativeMatrix );
      relativeMatrix.scaleByVector( scale.setValues( 1 / scale.x, 1 / scale.y, 1 / scale.z ) );

      // apply to global matrix

      globalMatrix.makeRotationFromQuaternion( quat.setFromRotationMatrix( relativeMatrix ) );

      //if ( target is Object3D ) {
        if ( options.localOffsets != null) {
          if ( options.localOffsets![ bone.name ] ) {
            globalMatrix.multiply( options.localOffsets![ bone.name ] );
          }
        }
      //}

      globalMatrix.copyPosition( relativeMatrix );
    }

    if ( name == options.hip ) {
      globalMatrix.storage[ 12 ] *= options.scale * options.hipInfluence.x;
      globalMatrix.storage[ 13 ] *= options.scale * options.hipInfluence.y;
      globalMatrix.storage[ 14 ] *= options.scale * options.hipInfluence.z;

      if ( options.hipPosition != null ) {
        globalMatrix.storage[ 12 ] += options.hipPosition!.x * options.scale;
        globalMatrix.storage[ 13 ] += options.hipPosition!.y * options.scale;
        globalMatrix.storage[ 14 ] += options.hipPosition!.z * options.scale;
      }
    }

    if ( bone.parent != null) {
      bone.matrix.setFrom( bone.parent!.matrixWorld ).invert();
      bone.matrix.multiply( globalMatrix );
    } else {
      bone.matrix.setFrom( globalMatrix );
    }

    bone.matrix.decompose( bone.position, bone.quaternion, bone.scale );

    bone.updateMatrixWorld();
  }

  if ( options.preserveBonePositions ) {
    for (int i = 0; i < bones.length; ++ i ) {
      bone = bones[ i ];
      name = getBoneName( bone, options ) ?? bone.name;

      if ( name != options.hip ) {
        bone.position.setFrom( bonesPosition[ i ] );
      }
    }
  }

  if ( options.preserveBoneMatrix ) {
    target.updateMatrixWorld( true );
  }
}