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 override IEnumerable <EditorCurveBinding> GetConstrainedCurveBindings(RigBuilder rigBuilder, TwistChainConstraint constraint) { var bindings = new List <EditorCurveBinding>(); // Retrieve chain in-between root and tip transforms. Transform[] chain = ConstraintsUtils.ExtractChain(constraint.data.root, constraint.data.tip); for (int i = 0; i < chain.Length; ++i) { EditorCurveBindingUtils.CollectRotationBindings(rigBuilder.transform, chain[i], bindings); } return(bindings); }
public void TwistChainConstraint_TransferMotionToConstraint() { var data = TwistChainConstraintTests.SetupConstraintRig(); var constraint = data.constraint; var rootGO = data.rigData.rootGO; var rigBuilder = rootGO.GetComponent <RigBuilder>(); var tip = constraint.data.tip; var root = constraint.data.root; var clip = new AnimationClip(); // Add keyframes for root and tips. Transform[] chain = ConstraintsUtils.ExtractChain(root, tip); var rootPath = AnimationUtility.CalculateTransformPath(root, rootGO.transform); AnimationUtility.SetEditorCurve(clip, EditorCurveBinding.FloatCurve(rootPath, typeof(Transform), "localEulerAnglesRaw.x"), AnimationCurve.Constant(0f, 1f, 0f)); AnimationUtility.SetEditorCurve(clip, EditorCurveBinding.FloatCurve(rootPath, typeof(Transform), "localEulerAnglesRaw.y"), AnimationCurve.Constant(0f, 1f, 0f)); AnimationUtility.SetEditorCurve(clip, EditorCurveBinding.FloatCurve(rootPath, typeof(Transform), "localEulerAnglesRaw.z"), AnimationCurve.Linear(0f, 0f, 1f, -50f)); var tipPath = AnimationUtility.CalculateTransformPath(tip, rootGO.transform); AnimationUtility.SetEditorCurve(clip, EditorCurveBinding.FloatCurve(tipPath, typeof(Transform), "localEulerAnglesRaw.x"), AnimationCurve.Constant(0f, 1f, 0f)); AnimationUtility.SetEditorCurve(clip, EditorCurveBinding.FloatCurve(tipPath, typeof(Transform), "localEulerAnglesRaw.y"), AnimationCurve.Constant(0f, 1f, 0f)); AnimationUtility.SetEditorCurve(clip, EditorCurveBinding.FloatCurve(tipPath, typeof(Transform), "localEulerAnglesRaw.z"), AnimationCurve.Linear(0f, 0f, 1f, 50f)); // Also keyframe inbetween keys for (int i = 1; i < chain.Length - 1; ++i) { var path = AnimationUtility.CalculateTransformPath(chain[i], rootGO.transform); AnimationUtility.SetEditorCurve(clip, EditorCurveBinding.FloatCurve(path, typeof(Transform), "localEulerAnglesRaw.x"), AnimationCurve.Constant(0f, 1f, 0f)); AnimationUtility.SetEditorCurve(clip, EditorCurveBinding.FloatCurve(path, typeof(Transform), "localEulerAnglesRaw.y"), AnimationCurve.Constant(0f, 1f, 0f)); AnimationUtility.SetEditorCurve(clip, EditorCurveBinding.FloatCurve(path, typeof(Transform), "localEulerAnglesRaw.z"), AnimationCurve.Constant(0f, 1f, 0f)); } RuntimeRiggingEditorTestFixture.TestTransferMotionToConstraint(constraint, rigBuilder, clip, new Transform[] { root, tip }, CompareFlags.Rotation); }
public void TwistChainConstraint_TransferMotionToSkeleton() { var data = TwistChainConstraintTests.SetupConstraintRig(); var constraint = data.constraint; var rootGO = data.rigData.rootGO; var rigBuilder = rootGO.GetComponent <RigBuilder>(); var tip = constraint.data.tip; var root = constraint.data.root; var tipTarget = constraint.data.tipTarget; var rootTarget = constraint.data.rootTarget; var clip = new AnimationClip(); var tipTargetPath = AnimationUtility.CalculateTransformPath(tipTarget, rootGO.transform); var rootTargetPath = AnimationUtility.CalculateTransformPath(rootTarget, rootGO.transform); // Add keyframes for twist chain constraint. AnimationUtility.SetEditorCurve(clip, EditorCurveBinding.FloatCurve(rootTargetPath, typeof(Transform), "localEulerAnglesRaw.x"), AnimationCurve.Constant(0f, 1f, 0f)); AnimationUtility.SetEditorCurve(clip, EditorCurveBinding.FloatCurve(rootTargetPath, typeof(Transform), "localEulerAnglesRaw.y"), AnimationCurve.Constant(0f, 1f, 0f)); AnimationUtility.SetEditorCurve(clip, EditorCurveBinding.FloatCurve(rootTargetPath, typeof(Transform), "localEulerAnglesRaw.z"), AnimationCurve.Linear(0f, 0f, 1f, -50f)); AnimationUtility.SetEditorCurve(clip, EditorCurveBinding.FloatCurve(tipTargetPath, typeof(Transform), "localEulerAnglesRaw.x"), AnimationCurve.Constant(0f, 1f, 0f)); AnimationUtility.SetEditorCurve(clip, EditorCurveBinding.FloatCurve(tipTargetPath, typeof(Transform), "localEulerAnglesRaw.y"), AnimationCurve.Constant(0f, 1f, 0f)); AnimationUtility.SetEditorCurve(clip, EditorCurveBinding.FloatCurve(tipTargetPath, typeof(Transform), "localEulerAnglesRaw.z"), AnimationCurve.Linear(0f, 0f, 1f, 50f)); RuntimeRiggingEditorTestFixture.TestTransferMotionToSkeleton(constraint, rigBuilder, clip, ConstraintsUtils.ExtractChain(root, tip), CompareFlags.TR); }