KissingRig.cs 4.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115
  1. using UnityEngine;
  2. using System.Collections;
  3. using RootMotion.FinalIK;
  4. namespace RootMotion.Demos {
  5. /// <summary>
  6. /// FBBIK example rig for a kissing emote.
  7. /// As the IK targets of one FBBIK partner depend on the solved pose of another FBBIK partner and vice versa, the rig will have to be iterated a couple of times to make it work.
  8. /// </summary>
  9. public class KissingRig : MonoBehaviour {
  10. /// <summary>
  11. /// A partner in the emote
  12. /// </summary>
  13. [System.Serializable]
  14. public class Partner {
  15. public FullBodyBipedIK ik; // Reference to the FBBIK component
  16. public Transform mouth; // The mouth bone, should be attached to the head
  17. public Transform mouthTarget; // The target that we want to set the mouth bone to
  18. public Transform touchTargetLeftHand, touchTargetRightHand; // Touch targets for the hands
  19. public float bodyWeightHorizontal = 0.4f; // The body effector horizontal weight
  20. public float bodyWeightVertical = 1f; // The body effector vertical weight
  21. public float neckRotationWeight = 0.3f; // The neck rotation weight
  22. public float headTiltAngle = 10f; // Tilting the head
  23. public Vector3 headTiltAxis; // Head tilt axis
  24. private Quaternion neckRotation;
  25. public void Initiate() {
  26. // Disable the FBBIK component to manage its updating
  27. ik.enabled = false;
  28. }
  29. public void Update(float weight) {
  30. // Set IK position and rotation weights
  31. ik.solver.leftShoulderEffector.positionWeight = weight;
  32. ik.solver.rightShoulderEffector.positionWeight = weight;
  33. ik.solver.leftHandEffector.positionWeight = weight;
  34. ik.solver.rightHandEffector.positionWeight = weight;
  35. ik.solver.leftHandEffector.rotationWeight = weight;
  36. ik.solver.rightHandEffector.rotationWeight = weight;
  37. ik.solver.bodyEffector.positionWeight = weight;
  38. // Inverse transform the shoulder and body effectors to set them relative to the mouth bone's position in the animation
  39. InverseTransformEffector(FullBodyBipedEffector.LeftShoulder, mouth, mouthTarget.position, weight);
  40. InverseTransformEffector(FullBodyBipedEffector.RightShoulder, mouth, mouthTarget.position, weight);
  41. InverseTransformEffector(FullBodyBipedEffector.Body, mouth, mouthTarget.position, weight);
  42. // Positioning the body effector horizontally
  43. ik.solver.bodyEffector.position = Vector3.Lerp(new Vector3(ik.solver.bodyEffector.position.x, ik.solver.bodyEffector.bone.position.y, ik.solver.bodyEffector.position.z), ik.solver.bodyEffector.position, bodyWeightVertical * weight);
  44. // Positioning the body effector vertically
  45. ik.solver.bodyEffector.position = Vector3.Lerp(new Vector3(ik.solver.bodyEffector.bone.position.x, ik.solver.bodyEffector.position.y, ik.solver.bodyEffector.bone.position.z), ik.solver.bodyEffector.position, bodyWeightHorizontal * weight);
  46. // Set hand effector positions to touch targets
  47. ik.solver.leftHandEffector.position = touchTargetLeftHand.position;
  48. ik.solver.rightHandEffector.position = touchTargetRightHand.position;
  49. ik.solver.leftHandEffector.rotation = touchTargetLeftHand.rotation;
  50. ik.solver.rightHandEffector.rotation = touchTargetRightHand.rotation;
  51. // Store the neck rotation so we could slerp back to it after updating FBBIK
  52. neckRotation = neck.rotation;
  53. // Update the FBBIK solver
  54. ik.solver.Update();
  55. // Revert the neck back to its animated rotation
  56. neck.rotation = Quaternion.Slerp(neck.rotation, neckRotation, neckRotationWeight * weight);
  57. // Head tilting
  58. ik.references.head.localRotation = Quaternion.AngleAxis(headTiltAngle * weight, headTiltAxis) * ik.references.head.localRotation;
  59. }
  60. // Get the neck bone
  61. private Transform neck {
  62. get {
  63. return ik.solver.spineMapping.spineBones[ik.solver.spineMapping.spineBones.Length - 1];
  64. }
  65. }
  66. // Placing an effector so that an arbitrary Transform (target) ends up at targetPosition
  67. private void InverseTransformEffector(FullBodyBipedEffector effector, Transform target, Vector3 targetPosition, float weight) {
  68. // Direction from the target to the effector
  69. Vector3 toEffector = ik.solver.GetEffector(effector).bone.position - target.position;
  70. // Positioning the effector
  71. ik.solver.GetEffector(effector).position = Vector3.Lerp(ik.solver.GetEffector(effector).bone.position, targetPosition + toEffector, weight);
  72. }
  73. }
  74. public Partner partner1, partner2; // The partners
  75. public float weight; // The master weight
  76. public int iterations = 3; // The number of iterating this rig.
  77. // As the IK targets of one FBBIK partner depend on the solved pose of another FBBIK partner and vice versa,
  78. // the rig will have to be iterated a couple of times to make it work.
  79. void Start() {
  80. // Initiating the partners
  81. partner1.Initiate();
  82. partner2.Initiate();
  83. }
  84. void LateUpdate() {
  85. // Iterate the rig
  86. for (int i = 0; i < iterations; i++) {
  87. partner1.Update(weight);
  88. partner2.Update(weight);
  89. }
  90. }
  91. }
  92. }