public IEnumerator TwistCorrection_ApplyWeight() { var data = SetupConstraintRig(); var constraint = data.constraint; var sourceObject = constraint.data.sourceObject; var twistNodes = constraint.data.twistNodes; var floatComparer = new RuntimeRiggingTestFixture.FloatEqualityComparer(k_Epsilon); // Apply rotation to source object sourceObject.localRotation = sourceObject.localRotation * Quaternion.AngleAxis(90, Vector3.left); twistNodes.SetWeight(0, 1f); constraint.data.twistNodes = twistNodes; for (int i = 0; i <= 5; ++i) { float w = i / 5.0f; data.constraint.weight = w; yield return(null); var weightedRot = Quaternion.Lerp(data.restLocalRotation, sourceObject.localRotation, w); Assert.That(twistNodes[0].transform.localRotation.x, Is.EqualTo(weightedRot.x).Using(floatComparer)); Assert.That(twistNodes[0].transform.localRotation.w, Is.EqualTo(weightedRot.w).Using(floatComparer)); } }
public IEnumerator TwistChainConstraint_ApplyWeight() { var data = SetupConstraintRig(); var constraint = data.constraint; Transform[] chain = ConstraintsUtils.ExtractChain(constraint.data.root, constraint.data.tip); // Chain with no constraint. Vector3[] bindPoseChain = chain.Select(transform => transform.position).ToArray(); var tipTarget = constraint.data.tipTarget; var rootTarget = constraint.data.rootTarget; rootTarget.rotation = Quaternion.Euler(0, 0, 0); tipTarget.rotation = Quaternion.Euler(0, 0, 50); yield return(null); // Chain with TwistChain constraint. Vector3[] weightedChain = chain.Select(transform => transform.position).ToArray(); // In-between chains. var inBetweenChains = new List <Vector3[]>(); for (int i = 0; i <= 5; ++i) { float w = i / 5.0f; data.constraint.weight = w; yield return(null); inBetweenChains.Add(chain.Select(transform => transform.position).ToArray()); } var floatComparer = new RuntimeRiggingTestFixture.FloatEqualityComparer(k_Epsilon); for (int i = 0; i <= 5; ++i) { Vector3[] prevChain = (i > 0) ? inBetweenChains[i - 1] : bindPoseChain; Vector3[] currentChain = inBetweenChains[i]; Vector3[] nextChain = (i < 5) ? inBetweenChains[i + 1] : weightedChain; for (int j = 0; j < bindPoseChain.Length - 1; ++j) { Vector2 dir1 = prevChain[j + 1] - prevChain[j]; Vector2 dir2 = currentChain[j + 1] - currentChain[j]; Vector2 dir3 = nextChain[j + 1] - nextChain[j]; float maxAngle = Vector2.Angle(dir1, dir3); float angle = Vector2.Angle(dir1, dir2); Assert.That(angle, Is.GreaterThanOrEqualTo(0f).Using(floatComparer)); Assert.That(angle, Is.LessThanOrEqualTo(maxAngle).Using(floatComparer)); } } }
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 TwoBoneIKConstraint_UsesHint() { var data = SetupConstraintRig(); var constraint = data.constraint; var target = constraint.data.target; var hint = constraint.data.hint; var mid = constraint.data.mid; var floatComparer = new RuntimeRiggingTestFixture.FloatEqualityComparer(k_Epsilon); Vector3 midPos1 = mid.position; // Make left arm flex. target.position += new Vector3(0.2f, 0.0f, 0f); hint.position = mid.position + new Vector3(0f, 1f, 0f); yield return(RuntimeRiggingTestFixture.YieldTwoFrames()); Vector3 midPos2 = mid.position; Assert.That(midPos2.y, Is.GreaterThan(midPos1.y).Using(floatComparer), String.Format("Expected mid2.y to be greater than mid1.y")); Assert.That(midPos1.z, Is.EqualTo(midPos2.z).Using(floatComparer), String.Format("Expected mid2.z to be {0}, but was {1}", midPos1.z, midPos2.z)); hint.position = mid.position + new Vector3(0f, -1f, 0f); yield return(RuntimeRiggingTestFixture.YieldTwoFrames()); midPos2 = mid.position; Assert.That(midPos2.y, Is.LessThan(midPos1.y).Using(floatComparer), String.Format("Expected mid2.y to be lower than mid1.y")); Assert.That(midPos1.z, Is.EqualTo(midPos2.z).Using(floatComparer), String.Format("Expected mid2.z to be {0}, but was {1}", midPos1.z, midPos2.z)); hint.position = mid.position + new Vector3(0f, 0f, 1f); yield return(RuntimeRiggingTestFixture.YieldTwoFrames()); midPos2 = mid.position; Assert.That(midPos1.y, Is.EqualTo(midPos2.y).Using(floatComparer), String.Format("Expected mid2.y to be {0}, but was {1}", midPos1.y, midPos2.y)); Assert.That(midPos2.z, Is.GreaterThan(midPos1.z).Using(floatComparer), String.Format("Expected mid2.y to be greater than mid1.y")); hint.position = mid.position + new Vector3(0f, 0f, -1f); yield return(RuntimeRiggingTestFixture.YieldTwoFrames()); midPos2 = mid.position; Assert.That(midPos1.y, Is.EqualTo(midPos2.y).Using(floatComparer), String.Format("Expected mid2.y to be {0}, but was {1}", midPos1.y, midPos2.y)); Assert.That(midPos2.z, Is.LessThan(midPos1.z).Using(floatComparer), String.Format("Expected mid2.y to be greater than mid1.y")); }
public IEnumerator DampedTransform_FollowsSource() { var data = SetupConstraintRig(); var constraint = data.constraint; var constrainedTransform = constraint.data.constrainedObject; var sourceTransform = constraint.data.sourceObject; Vector3 constrainedPos1 = constrainedTransform.position; Vector3 offset = new Vector3(0f, 0.5f, 0f); sourceTransform.localPosition += offset; Vector3 constrainedPos2 = constrainedPos1 + offset; const int kMaxIter = 15; List <Vector3> positions = new List <Vector3>(kMaxIter); for (int i = 0; i < kMaxIter; ++i) { yield return(null); positions.Add(constrainedTransform.position); } float[] distances = positions.Select((pos) => (pos - constrainedPos1).magnitude).ToArray(); var floatComparer = new RuntimeRiggingTestFixture.FloatEqualityComparer(k_Epsilon); for (int i = 0; i < kMaxIter - 1; ++i) { Vector3 dir = positions[i + 1] - positions[i]; Assert.That(Vector3.Angle(dir, offset), Is.EqualTo(0f).Using(floatComparer), String.Format("Offset direction mismatch at index {0}", i)); Assert.That(distances[i + 1], Is.GreaterThanOrEqualTo(distances[i]).Using(floatComparer)); Assert.That(distances[i], Is.LessThanOrEqualTo(0.5f).Using(floatComparer)); } }
public IEnumerator MultiAimConstraint_ApplyWeight() { var data = SetupConstraintRig(); var constraint = data.constraint; var constrainedObject = constraint.data.constrainedObject; var sources = constraint.data.sourceObjects; var floatComparer = new RuntimeRiggingTestFixture.FloatEqualityComparer(k_Epsilon); Assert.Zero(sources[0].weight); Assert.Zero(sources[1].weight); sources[0].transform.position += Vector3.left; sources.SetWeight(0, 1f); constraint.data.sourceObjects = sources; var src0Pos = sources[0].transform.position; var angle = 180f; for (int i = 0; i <= 5; ++i) { float w = i / 5.0f; data.constraint.weight = w; yield return(null); var currAim = constrainedObject.rotation * Vector3.forward; var src0Dir = (src0Pos - constrainedObject.position).normalized; var angleTest = Vector3.Angle(currAim, src0Dir); Assert.That(angleTest, Is.LessThan(angle).Using(floatComparer), "Angle between currAim and src0Dir should be smaller than last frame since constraint weight is greater."); angle = angleTest; } }