public IEnumerator TwistChainConstraint_FollowsTargets() { var data = SetupConstraintRig(); var constraint = data.constraint; var tipTarget = constraint.data.tipTarget; var rootTarget = constraint.data.rootTarget; var tip = constraint.data.tip; var root = constraint.data.root; var quaternionComparer = new RuntimeRiggingTestFixture.QuaternionEqualityComparer(k_Epsilon); for (int i = 0; i < 5; ++i) { tipTarget.rotation = tipTarget.rotation * Quaternion.Euler(0, 0, 10); yield return(RuntimeRiggingTestFixture.YieldTwoFrames()); Assert.That(tip.rotation, Is.EqualTo(tipTarget.rotation).Using(quaternionComparer)); Assert.That(root.rotation, Is.EqualTo(rootTarget.rotation).Using(quaternionComparer)); } for (int i = 0; i < 5; ++i) { rootTarget.rotation = rootTarget.rotation * Quaternion.Euler(0, 0, -10); yield return(RuntimeRiggingTestFixture.YieldTwoFrames()); Assert.That(root.rotation, Is.EqualTo(rootTarget.rotation).Using(quaternionComparer)); Assert.That(tip.rotation, Is.EqualTo(tipTarget.rotation).Using(quaternionComparer)); } }
public IEnumerator MultiRotationConstraint_ApplyWeight() { var data = SetupConstraintRig(); var constraint = data.constraint; var constrainedObject = constraint.data.constrainedObject; var sources = constraint.data.sourceObjects; var rotationComparer = new RuntimeRiggingTestFixture.QuaternionEqualityComparer(k_Epsilon); sources[0].transform.rotation *= Quaternion.AngleAxis(90, Vector3.up); sources[0] = new WeightedTransform(sources[0].transform, 1f); constraint.data.sourceObjects = sources; for (int i = 0; i <= 5; ++i) { float w = i / 5.0f; data.constraint.weight = w; yield return(null); Quaternion weightedRot = Quaternion.Lerp(data.constrainedObjectRestRotation, sources[0].transform.rotation, w); Assert.That( constrainedObject.rotation, Is.EqualTo(weightedRot).Using(rotationComparer), String.Format("Expected constrainedObject rotation to be {0} for a weight of {1}, but was {2}", weightedRot, w, constrainedObject.rotation) ); } }
public IEnumerator BlendConstraint_ApplyWeight() { var data = SetupConstraintRig(); var constraint = data.constraint; var srcObjB = constraint.data.sourceObjectB; var constrainedObj = constraint.data.constrainedObject; var positionComparer = new RuntimeRiggingTestFixture.Vector3EqualityComparer(k_Epsilon); var rotationComparer = new RuntimeRiggingTestFixture.QuaternionEqualityComparer(k_Epsilon); // SourceB has full influence constraint.data.positionWeight = 1f; constraint.data.rotationWeight = 1f; srcObjB.rotation *= Quaternion.AngleAxis(90, Vector3.right); yield return(null); for (int i = 0; i <= 5; ++i) { float w = i / 5.0f; data.constraint.weight = w; yield return(null); var weightedPos = Vector3.Lerp(data.restPose.translation, srcObjB.position, w); var weightedRot = Quaternion.Lerp(data.restPose.rotation, srcObjB.rotation, w); Assert.That(constrainedObj.position, Is.EqualTo(weightedPos).Using(positionComparer)); Assert.That(constrainedObj.rotation, Is.EqualTo(weightedRot).Using(rotationComparer)); } }
public IEnumerator MultiReferentialConstraint_ApplyWeight() { var data = SetupConstraintRig(); var constraint = data.constraint; var sources = constraint.data.sourceObjects; constraint.data.driver = 1; constraint.weight = 0f; yield return(null); sources[1].position += Vector3.right; sources[1].rotation *= Quaternion.AngleAxis(-90, Vector3.up); var positionComparer = new RuntimeRiggingTestFixture.Vector3EqualityComparer(k_Epsilon); var rotationComparer = new RuntimeRiggingTestFixture.QuaternionEqualityComparer(k_Epsilon); for (int i = 0; i <= 5; ++i) { float w = i / 5.0f; constraint.weight = w; yield return(null); var weightedPos = Vector3.Lerp(data.restPose.translation, sources[1].position, w); Assert.That( sources[0].position, Is.EqualTo(weightedPos).Using(positionComparer), String.Format("Expected Source0 to be at {0} for a weight of {1}, but was {2}", weightedPos, w, sources[0].position) ); Assert.That( sources[2].position, Is.EqualTo(weightedPos).Using(positionComparer), String.Format("Expected Source2 to be at {0} for a weight of {1}, but was {2}", weightedPos, w, sources[2].position) ); var weightedRot = Quaternion.Lerp(data.restPose.rotation, sources[1].rotation, w); Assert.That( sources[0].rotation, Is.EqualTo(weightedRot).Using(rotationComparer), String.Format("Expected rotations to be equal for a weight of {0}", w) ); Assert.That( sources[2].rotation, Is.EqualTo(weightedRot).Using(rotationComparer), String.Format("Expected rotations to be equal for a weight of {0}", w) ); // Since we have no animation in the stream the new rest pose // should be the last evaluated one. data.restPose.translation = sources[0].position; data.restPose.rotation = sources[0].rotation; } }
public IEnumerator TwistCorrection_FollowsSourceObject() { var data = SetupConstraintRig(); var constraint = data.constraint; var sourceObject = constraint.data.sourceObject; var twistNodes = constraint.data.twistNodes; var rotationComparer = new RuntimeRiggingTestFixture.QuaternionEqualityComparer(k_Epsilon); var floatComparer = new RuntimeRiggingTestFixture.FloatEqualityComparer(k_Epsilon); // Apply rotation to source object sourceObject.localRotation = sourceObject.localRotation * Quaternion.AngleAxis(90, Vector3.left); // twistNode0.w = 0.0f, twistNode1.w = 0.0f [does not influence twist nodes] Assert.AreEqual(twistNodes[0].weight, 0.0f); Assert.AreEqual(twistNodes[1].weight, 0.0f); yield return(RuntimeRiggingTestFixture.YieldTwoFrames()); Assert.That(sourceObject.localRotation, Is.Not.EqualTo(data.restLocalRotation).Using(rotationComparer)); Assert.That(twistNodes[0].transform.localRotation, Is.EqualTo(Quaternion.identity).Using(rotationComparer)); Assert.That(twistNodes[1].transform.localRotation, Is.EqualTo(Quaternion.identity).Using(rotationComparer)); // twistNode0.w = 1f, twistNode1.w = 1f [twist nodes should be equal to source] twistNodes.SetWeight(0, 1f); twistNodes.SetWeight(1, 1f); constraint.data.twistNodes = twistNodes; yield return(RuntimeRiggingTestFixture.YieldTwoFrames()); // Verify twist on X axis Assert.That(twistNodes[0].transform.localRotation.x, Is.EqualTo(sourceObject.localRotation.x).Using(floatComparer)); Assert.That(twistNodes[0].transform.localRotation.w, Is.EqualTo(sourceObject.localRotation.w).Using(floatComparer)); Assert.That(twistNodes[1].transform.localRotation.x, Is.EqualTo(sourceObject.localRotation.x).Using(floatComparer)); Assert.That(twistNodes[1].transform.localRotation.w, Is.EqualTo(sourceObject.localRotation.w).Using(floatComparer)); // twistNode0.w = -1f, twistNode1.w = -1f [twist nodes should be inverse to source] twistNodes.SetWeight(0, -1f); twistNodes.SetWeight(1, -1f); constraint.data.twistNodes = twistNodes; yield return(RuntimeRiggingTestFixture.YieldTwoFrames()); var invTwist = Quaternion.Inverse(sourceObject.localRotation); // Verify twist on X axis Assert.That(twistNodes[0].transform.localRotation.x, Is.EqualTo(invTwist.x).Using(floatComparer)); Assert.That(twistNodes[0].transform.localRotation.w, Is.EqualTo(invTwist.w).Using(floatComparer)); Assert.That(twistNodes[1].transform.localRotation.x, Is.EqualTo(invTwist.x).Using(floatComparer)); Assert.That(twistNodes[1].transform.localRotation.w, Is.EqualTo(invTwist.w).Using(floatComparer)); }
public IEnumerator MultiAimConstraint_FollowSourceObjects() { var data = SetupConstraintRig(); var constraint = data.constraint; var constrainedObject = constraint.data.constrainedObject; var sources = constraint.data.sourceObjects; var positionComparer = new RuntimeRiggingTestFixture.Vector3EqualityComparer(k_Epsilon); var rotationComparer = new RuntimeRiggingTestFixture.QuaternionEqualityComparer(k_Epsilon); var floatComparer = new RuntimeRiggingTestFixture.FloatEqualityComparer(k_Epsilon); // Add displacement to source objects sources[0].transform.position += Vector3.left; sources[1].transform.position += Vector3.right; // src0.w = 0, src1.w = 0 Assert.Zero(sources[0].weight); Assert.Zero(sources[1].weight); yield return(RuntimeRiggingTestFixture.YieldTwoFrames()); Assert.That(constrainedObject.position, Is.EqualTo(data.constrainedObjectRestTx.translation).Using(positionComparer)); Assert.That(constrainedObject.rotation, Is.EqualTo(data.constrainedObjectRestTx.rotation).Using(rotationComparer)); // src0.w = 1, src1.w = 0 sources.SetWeight(0, 1f); constraint.data.sourceObjects = sources; yield return(RuntimeRiggingTestFixture.YieldTwoFrames()); Vector3 currAim = constrainedObject.rotation * Vector3.forward; Vector3 src0Dir = (sources[0].transform.position - constrainedObject.position).normalized; Vector3 src1Dir = (sources[1].transform.position - constrainedObject.position).normalized; Assert.That(Vector3.Angle(currAim, src0Dir), Is.EqualTo(0f).Using(floatComparer)); Assert.That(Vector3.Angle(currAim, src1Dir), Is.Not.EqualTo(0f).Using(floatComparer)); // src0.w = 0, src1.w = 1 sources.SetWeight(0, 0f); sources.SetWeight(1, 1f); constraint.data.sourceObjects = sources; yield return(RuntimeRiggingTestFixture.YieldTwoFrames()); currAim = constrainedObject.rotation * Vector3.forward; src0Dir = (sources[0].transform.position - constrainedObject.position).normalized; src1Dir = (sources[1].transform.position - constrainedObject.position).normalized; Assert.That(Vector3.Angle(currAim, src0Dir), Is.Not.EqualTo(0f).Using(floatComparer)); Assert.That(Vector3.Angle(currAim, src1Dir), Is.EqualTo(0f).Using(floatComparer)); }
public IEnumerator MultiReferentialConstraint_FollowSourceObjects() { var data = SetupConstraintRig(); var constraint = data.constraint; var positionComparer = new RuntimeRiggingTestFixture.Vector3EqualityComparer(k_Epsilon); var rotationComparer = new RuntimeRiggingTestFixture.QuaternionEqualityComparer(k_Epsilon); var sources = constraint.data.sourceObjects; constraint.data.driver = 0; var driver = sources[0]; driver.position += Vector3.forward; driver.rotation *= Quaternion.AngleAxis(90, Vector3.up); yield return(RuntimeRiggingTestFixture.YieldTwoFrames()); Assert.That(driver.position, Is.EqualTo(sources[1].position).Using(positionComparer)); Assert.That(driver.rotation, Is.EqualTo(sources[1].rotation).Using(rotationComparer)); Assert.That(driver.position, Is.EqualTo(sources[2].position).Using(positionComparer)); Assert.That(driver.rotation, Is.EqualTo(sources[2].rotation).Using(rotationComparer)); constraint.data.driver = 1; driver = sources[1]; driver.position += Vector3.back; driver.rotation *= Quaternion.AngleAxis(-90, Vector3.up); yield return(RuntimeRiggingTestFixture.YieldTwoFrames()); Assert.That(driver.position, Is.EqualTo(sources[0].position).Using(positionComparer)); Assert.That(driver.rotation, Is.EqualTo(sources[0].rotation).Using(rotationComparer)); Assert.That(driver.position, Is.EqualTo(sources[2].position).Using(positionComparer)); Assert.That(driver.rotation, Is.EqualTo(sources[2].rotation).Using(rotationComparer)); constraint.data.driver = 2; driver = sources[2]; driver.position += Vector3.up; driver.rotation *= Quaternion.AngleAxis(90, Vector3.left); yield return(RuntimeRiggingTestFixture.YieldTwoFrames()); Assert.That(driver.position, Is.EqualTo(sources[0].position).Using(positionComparer)); Assert.That(driver.rotation, Is.EqualTo(sources[0].rotation).Using(rotationComparer)); Assert.That(driver.position, Is.EqualTo(sources[1].position).Using(positionComparer)); Assert.That(driver.rotation, Is.EqualTo(sources[1].rotation).Using(rotationComparer)); }
public IEnumerator MultiParentConstraint_FollowSourceObjects() { var data = SetupConstraintRig(); var constraint = data.constraint; var constrainedObject = constraint.data.constrainedObject; var sources = constraint.data.sourceObjects; var positionComparer = new RuntimeRiggingTestFixture.Vector3EqualityComparer(k_Epsilon); var rotationComprarer = new RuntimeRiggingTestFixture.QuaternionEqualityComparer(k_Epsilon); // src0.w = 0, src1.w = 0 Assert.Zero(sources[0].weight); Assert.Zero(sources[1].weight); yield return(RuntimeRiggingTestFixture.YieldTwoFrames()); Assert.That(constrainedObject.position, Is.EqualTo(data.constrainedObjectRestTx.translation).Using(positionComparer)); Assert.That(constrainedObject.rotation, Is.EqualTo(data.constrainedObjectRestTx.rotation).Using(rotationComprarer)); // Add displacement to source objects sources[0].transform.position += Vector3.right; sources[0].transform.rotation *= Quaternion.AngleAxis(-90, Vector3.up); sources[1].transform.position += Vector3.left; sources[1].transform.rotation *= Quaternion.AngleAxis(90, Vector3.up); // src0.w = 1, src1.w = 0 sources.SetWeight(0, 1f); constraint.data.sourceObjects = sources; yield return(RuntimeRiggingTestFixture.YieldTwoFrames()); Assert.That(constrainedObject.position, Is.EqualTo(sources[0].transform.position).Using(positionComparer)); Assert.That(constrainedObject.rotation, Is.EqualTo(sources[0].transform.rotation).Using(rotationComprarer)); // src0.w = 0, src1.w = 1 sources.SetWeight(0, 0f); sources.SetWeight(1, 1f); constraint.data.sourceObjects = sources; yield return(RuntimeRiggingTestFixture.YieldTwoFrames()); Assert.That(constrainedObject.position, Is.EqualTo(sources[1].transform.position).Using(positionComparer)); Assert.That(constrainedObject.rotation, Is.EqualTo(sources[1].transform.rotation).Using(rotationComprarer)); }
public IEnumerator BlendConstraint_FollowsSourceObjects() { var data = SetupConstraintRig(); var constraint = data.constraint; var srcObjA = constraint.data.sourceObjectA; var srcObjB = constraint.data.sourceObjectB; var constrainedObj = constraint.data.constrainedObject; var positionComparer = new RuntimeRiggingTestFixture.Vector3EqualityComparer(k_Epsilon); var rotationComparer = new RuntimeRiggingTestFixture.QuaternionEqualityComparer(k_Epsilon); // Apply rotation on sourceB srcObjB.rotation *= Quaternion.AngleAxis(90, Vector3.right); yield return(null); // SourceA has full influence constraint.data.positionWeight = 0f; constraint.data.rotationWeight = 0f; yield return(null); Assert.That(constrainedObj.position, Is.EqualTo(srcObjA.position).Using(positionComparer)); Assert.That(constrainedObj.rotation, Is.EqualTo(srcObjA.rotation).Using(rotationComparer)); // SourceB has full influence constraint.data.positionWeight = 1f; constraint.data.rotationWeight = 1f; yield return(null); Assert.That(constrainedObj.position, Is.EqualTo(srcObjB.position).Using(positionComparer)); Assert.That(constrainedObj.rotation, Is.EqualTo(srcObjB.rotation).Using(rotationComparer)); // Translation/Rotation blending between sources is disabled constraint.data.blendPosition = false; constraint.data.blendRotation = false; yield return(null); Assert.That(constrainedObj.position, Is.EqualTo(data.restPose.translation).Using(positionComparer)); Assert.That(constrainedObj.rotation, Is.EqualTo(data.restPose.rotation).Using(rotationComparer)); }
public IEnumerator MultiRotationConstraint_FollowSourceObjects() { var data = SetupConstraintRig(); var constraint = data.constraint; var constrainedObject = constraint.data.constrainedObject; var sources = constraint.data.sourceObjects; var rotationComparer = new RuntimeRiggingTestFixture.QuaternionEqualityComparer(k_Epsilon); // src0.w = 0, src1.w = 0 Assert.Zero(sources[0].weight); Assert.Zero(sources[1].weight); yield return(RuntimeRiggingTestFixture.YieldTwoFrames()); Assert.That(constrainedObject.rotation, Is.EqualTo(data.constrainedObjectRestRotation).Using(rotationComparer)); // Add rotation to source objects sources[0].transform.rotation *= Quaternion.AngleAxis(90, Vector3.up); sources[1].transform.rotation *= Quaternion.AngleAxis(-90, Vector3.up); // src0.w = 1, src1.w = 0 sources[0] = new WeightedTransform(sources[0].transform, 1f); constraint.data.sourceObjects = sources; yield return(RuntimeRiggingTestFixture.YieldTwoFrames()); Assert.That(constrainedObject.rotation, Is.EqualTo(sources[0].transform.rotation).Using(rotationComparer)); // src0.w = 0, src1.w = 1 sources[0] = new WeightedTransform(sources[0].transform, 0f); sources[1] = new WeightedTransform(sources[1].transform, 1f); constraint.data.sourceObjects = sources; yield return(RuntimeRiggingTestFixture.YieldTwoFrames()); Assert.That(constrainedObject.rotation, Is.EqualTo(sources[1].transform.rotation).Using(rotationComparer)); }
public static void TestTransferMotionToConstraint <T>(T constraint, RigBuilder rigBuilder, AnimationClip clip, IList <Transform> targetTransforms, CompareFlags flags) where T : MonoBehaviour, IRigConstraint { Animator animator = rigBuilder.GetComponent <Animator>(); int numberOfFrames = 60; float dt = 1f / numberOfFrames; var defaultPoseClip = CreateDefaultPose(rigBuilder.gameObject); #if DEBUG_BAKE_TO_CONSTRAINT AssetDatabase.CreateAsset(clip, "Assets/bakeToConstraintBefore.anim"); clip = UnityEngine.Object.Instantiate(clip) as AnimationClip; #endif // Evaluate clip without constraint and take snapshots. var translationsBeforeBaking = new Vector3[targetTransforms.Count, numberOfFrames + 1]; var rotationsBeforeBaking = new Quaternion[targetTransforms.Count, numberOfFrames + 1]; using (var graph = new EvaluationGraph(rigBuilder.GetComponent <Animator>(), clip)) { graph.Evaluate(0f); for (int transformIndex = 0; transformIndex < targetTransforms.Count; ++transformIndex) { translationsBeforeBaking[transformIndex, 0] = targetTransforms[transformIndex].position; rotationsBeforeBaking[transformIndex, 0] = targetTransforms[transformIndex].rotation; } for (int frame = 1; frame <= numberOfFrames; ++frame) { graph.Evaluate(dt); for (int transformIndex = 0; transformIndex < targetTransforms.Count; ++transformIndex) { translationsBeforeBaking[transformIndex, frame] = targetTransforms[transformIndex].position; rotationsBeforeBaking[transformIndex, frame] = targetTransforms[transformIndex].rotation; } } } RestoreDefaultPose(animator, defaultPoseClip); // Bake and inverse solve to constraint. var bakeParameters = BakeUtils.FindBakeParameters(constraint); Assert.That(bakeParameters, Is.Not.Null); var bindings = bakeParameters.GetSourceCurveBindings(rigBuilder, constraint); AnimationMode.StartAnimationMode(); BakeUtils.BakeToConstraint(constraint, clip, defaultPoseClip, bindings, k_DefaultCurveFilterOptions); AnimationMode.StopAnimationMode(); #if DEBUG_BAKE_TO_CONSTRAINT AssetDatabase.CreateAsset(clip, "Assets/bakeToConstraintAfter.anim"); #endif RestoreDefaultPose(animator, defaultPoseClip); // Evaluate again with constraint active and take snapshots. var translationsAfterBaking = new Vector3[targetTransforms.Count, numberOfFrames + 1]; var rotationsAfterBaking = new Quaternion[targetTransforms.Count, numberOfFrames + 1]; using (var graph = new EvaluationGraph(rigBuilder, clip)) { graph.Evaluate(0f); for (int transformIndex = 0; transformIndex < targetTransforms.Count; ++transformIndex) { translationsAfterBaking[transformIndex, 0] = targetTransforms[transformIndex].position; rotationsAfterBaking[transformIndex, 0] = targetTransforms[transformIndex].rotation; } for (int frame = 1; frame <= numberOfFrames; ++frame) { graph.Evaluate(dt); for (int transformIndex = 0; transformIndex < targetTransforms.Count; ++transformIndex) { translationsAfterBaking[transformIndex, frame] = targetTransforms[transformIndex].position; rotationsAfterBaking[transformIndex, frame] = targetTransforms[transformIndex].rotation; } } } RestoreDefaultPose(animator, defaultPoseClip); if ((flags & CompareFlags.Rotation) != 0) { // Compare rotations var quaternionComparer = new RuntimeRiggingTestFixture.QuaternionEqualityComparer(k_RotationEpsilon); for (int transformIndex = 0; transformIndex < targetTransforms.Count; ++transformIndex) { for (int frame = 0; frame <= numberOfFrames; ++frame) { Assert.That(rotationsAfterBaking[transformIndex, frame], Is.EqualTo(rotationsBeforeBaking[transformIndex, frame]).Using(quaternionComparer), String.Format("Transform '{0}' rotation is set to {1} at frame {2}, but was expected to be {3}", targetTransforms[transformIndex].name, rotationsAfterBaking[transformIndex, frame].eulerAngles, frame, rotationsBeforeBaking[transformIndex, frame].eulerAngles)); } } } if ((flags & CompareFlags.Translation) != 0) { // Compare translations var positionComparer = new RuntimeRiggingTestFixture.Vector3EqualityComparer(k_Epsilon); for (int transformIndex = 0; transformIndex < targetTransforms.Count; ++transformIndex) { for (int frame = 0; frame <= numberOfFrames; ++frame) { Assert.That(translationsAfterBaking[transformIndex, frame], Is.EqualTo(translationsBeforeBaking[transformIndex, frame]).Using(positionComparer), String.Format("Transform '{0}' position is set to {1} at frame {2}, but was expected to be {3}", targetTransforms[transformIndex].name, translationsAfterBaking[transformIndex, frame], frame, translationsBeforeBaking[transformIndex, frame])); } } } }