/// <summary> /// Convert the target to a QuaternionInterpolationTarget for QuaternionHelper functions /// </summary> /// <param name="normalizedWeight"> /// A <see cref="System.Single"/> /// </param> /// <returns> /// A <see cref="QuaternionInterpolationTarget"/> /// </returns> public QuaternionInterpolationTarget ToQuatInterpTarget(float normalizedWeight) { QuaternionInterpolationTarget t = new QuaternionInterpolationTarget(); t.quaternion = target.rotation; t.weight = normalizedWeight; return t; }
/// <summary> /// Convert the target to a QuaternionInterpolationTarget for QuaternionHelper functions /// </summary> /// <param name="normalizedWeight"> /// A <see cref="System.Single"/> /// </param> /// <returns> /// A <see cref="QuaternionInterpolationTarget"/> /// </returns> public QuaternionInterpolationTarget ToQuatInterpTarget(float normalizedWeight) { QuaternionInterpolationTarget t = new QuaternionInterpolationTarget(); t.quaternion = target.rotation; t.weight = normalizedWeight; return(t); }
/// <summary> /// Compute the mean of an array of quaternions /// </summary> /// <param name="targets"> /// A <see cref="QuaternionInterpolationTarget[]"/> /// </param> /// <returns> /// A <see cref="Quaternion"/> /// </returns> public static Quaternion Mean(QuaternionInterpolationTarget[] targets) { Quaternion[] samples = new Quaternion[targets.Length]; for (int i=0; i<targets.Length; i++) samples[i] = targets[i].quaternion; return Mean (samples); }
public static Quaternion InterpolateSlime(QuaternionInterpolationTarget[] normalizedTargets, float oneOverListLength) { // get the reference quaternion Quaternion reference = Mean(normalizedTargets); // sum the logs of each quaternion in the space of the reference Vector4 sumOfWeightedQuaternions = Vector4.zero; for (int i=0; i<normalizedTargets.Length; i++) sumOfWeightedQuaternions += normalizedTargets[i].weight*Log(Quaternion.Inverse(reference)*normalizedTargets[i].quaternion); // multiply the reference quaternion by the result return reference * Exp(sumOfWeightedQuaternions); }
/// <summary> /// Perform Slime interpolation across the targets /// Formula: reference*e^(sum(weight*ln(reference.conjugate*target.rotation))) /// See p.130, 136: http://alumni.media.mit.edu/~aries/papers/johnson_phd.pdf /// </summary> /// <param name="targets"> /// A <see cref="QuaternionInterpolationTarget[]"/> /// </param> /// <returns> /// A <see cref="Quaternion"/> /// </returns> public static Quaternion InterpolateSlime(QuaternionInterpolationTarget[] targets) { // call other version of method return InterpolateSlime(NormalizeTargetWeights(targets), 1f/targets.Length); }
/// <summary> /// A multiple interpolation algorithm that simply does a sequential nlerp /// </summary> /// <param name="normalizedTargets"> /// A <see cref="QuaternionInterpolationTarget[]"/> /// </param> /// <returns> /// A <see cref="Quaternion"/> /// </returns> public static Quaternion InterpolateAverage(QuaternionInterpolationTarget[] normalizedTargets) { // the candidate return value Quaternion q = normalizedTargets[0].quaternion; for (int i=1; i<normalizedTargets.Length; i++) q = Quaternion.Lerp(q, normalizedTargets[i].quaternion, normalizedTargets[i].weight); return q; }
/// <summary> /// Perform a sequential slerp ala Maya's orientConstraint node /// </summary> /// <param name="normalizedTargets"> /// A <see cref="QuaternionInterpolationTarget[]"/> /// </param> /// <param name="isShortPath"> /// A <see cref="System.Boolean"/> /// </param> /// <param name="cache"> /// A <see cref="Quaternion[]"/> /// </param> /// <returns> /// A <see cref="Quaternion"/> /// </returns> public static Quaternion SequentialSlerp(QuaternionInterpolationTarget[] normalizedTargets, bool isShortPath, ref Quaternion[] cache) { // the candidate return value Quaternion q = normalizedTargets[0].quaternion; for (int i=1; i<normalizedTargets.Length; i++) { if (isShortPath) q = Quaternion.Slerp(q, normalizedTargets[i].quaternion, normalizedTargets[i].weight); else q = SlerpLong(q, normalizedTargets[i].quaternion, normalizedTargets[i].weight); } // TODO: if using a caching mode, then do a neighborhood test // shift the cache and add the new result to the end of it for (int i=1; i<cache.Length; i++) cache[i-1] = cache[i]; cache[cache.Length-1] = q; // return the result return q; }
public static Quaternion Interpolate(QuaternionInterpolationTarget[] normalizedTargets, QuaternionInterpolationMode interpType, ref Quaternion[] cache, float oneOverListLength) { switch (interpType) { case QuaternionInterpolationMode.Average: return InterpolateAverage(normalizedTargets); case QuaternionInterpolationMode.Slime: return InterpolateSlime(normalizedTargets); case QuaternionInterpolationMode.Longest: return SequentialSlerp(normalizedTargets, false, ref cache); default: return SequentialSlerp(normalizedTargets, true, ref cache); } }
/// <summary> /// Do an interpolation using the specified mode /// </summary> /// <param name="normalizedTargets"> /// A <see cref="QuaternionInterpolationTarget[]"/> /// </param> /// <param name="interpType"> /// A <see cref="QuaternionInterpolationMode"/> /// </param> /// <param name="cache"> /// A <see cref="Quaternion[]"/> /// </param> /// <returns> /// A <see cref="Quaternion"/> /// </returns> public static Quaternion Interpolate(QuaternionInterpolationTarget[] normalizedTargets, QuaternionInterpolationMode interpType, ref Quaternion[] cache) { // pass in denominator return Interpolate(normalizedTargets, interpType, ref cache, 1f/normalizedTargets.Length); }
/// <summary> /// Normalize the weights of an array of interpolation targets to 1.0 /// </summary> /// <param name="targets"> /// A <see cref="QuaternionInterpolationTarget[]"/> /// </param> /// <returns> /// A <see cref="QuaternionInterpolationTarget[]"/> /// </returns> public static QuaternionInterpolationTarget[] NormalizeTargetWeights(QuaternionInterpolationTarget[] targets) { float sumOfAllWeights = 0f; for (int i=0; i<targets.Length; i++) sumOfAllWeights += targets[i].weight; float oneOverSum = 1f/sumOfAllWeights; for (int i=0; i<targets.Length; i++) targets[i].weight *= oneOverSum; return targets; }