DampingJob.cs 6.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147
  1. // Copyright Unity Technologies 2019 // https://github.com/Unity-Technologies/animation-jobs-samples //
  2. // The original file can be downloaded from https://github.com/Unity-Technologies/animation-jobs-samples/blob/master/Assets/animation-jobs-samples/Runtime/AnimationJobs/DampingJob.cs
  3. // This file has been modified:
  4. // - Moved into the Animancer.Examples.Jobs namespace.
  5. // - Removed the contents of ProcessRootMotion since it is unnecessary.
  6. #pragma warning disable IDE0054 // Use compound assignment
  7. using Unity.Collections;
  8. using UnityEngine;
  9. using UnityEngine.Animations;
  10. namespace Animancer.Examples.Jobs
  11. {
  12. /// <example><see href="https://kybernetik.com.au/animancer/docs/examples/jobs/damping">Damping</see></example>
  13. /// https://kybernetik.com.au/animancer/api/Animancer.Examples.Jobs/DampingJob
  14. ///
  15. public struct DampingJob : IAnimationJob
  16. {
  17. public TransformStreamHandle rootHandle;
  18. public NativeArray<TransformStreamHandle> jointHandles;
  19. public NativeArray<Vector3> localPositions;
  20. public NativeArray<Quaternion> localRotations;
  21. public NativeArray<Vector3> positions;
  22. public NativeArray<Vector3> velocities;
  23. /// <summary>
  24. /// Transfer the root position and rotation through the graph.
  25. /// </summary>
  26. /// <param name="stream">The animation stream</param>
  27. public void ProcessRootMotion(AnimationStream stream)
  28. {
  29. // This was in the original sample, but it causes problems if the character is a child of a moving object.
  30. // There is no need for this method to do anything in order to support root motion.
  31. //// Get root position and rotation.
  32. //var rootPosition = rootHandle.GetPosition(stream);
  33. //var rootRotation = rootHandle.GetRotation(stream);
  34. //// The root always follow the given position and rotation.
  35. //rootHandle.SetPosition(stream, rootPosition);
  36. //rootHandle.SetRotation(stream, rootRotation);
  37. }
  38. /// <summary>
  39. /// Procedurally generate the joints rotation.
  40. /// </summary>
  41. /// <param name="stream">The animation stream</param>
  42. public void ProcessAnimation(AnimationStream stream)
  43. {
  44. if (jointHandles.Length < 2)
  45. return;
  46. ComputeDampedPositions(stream);
  47. ComputeJointLocalRotations(stream);
  48. }
  49. /// <summary>
  50. /// Compute the new global positions of the joints.
  51. ///
  52. /// The position of the first joint is driven by the root's position, and
  53. /// then the other joints positions are recomputed in order to follow their
  54. /// initial local positions, smoothly.
  55. ///
  56. /// Algorithm breakdown:
  57. /// 1. Compute the target position;
  58. /// 2. Damp this target position based on the current position;
  59. /// 3. Constrain the damped position to the joint initial length;
  60. /// 4. Iterate on the next joint.
  61. /// </summary>
  62. /// <param name="stream">The animation stream</param>
  63. private void ComputeDampedPositions(AnimationStream stream)
  64. {
  65. // Get root position and rotation.
  66. var rootPosition = rootHandle.GetPosition(stream);
  67. var rootRotation = rootHandle.GetRotation(stream);
  68. // The first non-root joint follows the root position,
  69. // but its rotation is damped (see ComputeJointLocalRotations).
  70. var parentPosition = rootPosition + rootRotation * localPositions[0];
  71. var parentRotation = rootRotation * localRotations[0];
  72. positions[0] = parentPosition;
  73. for (var i = 1; i < jointHandles.Length; ++i)
  74. {
  75. // The target position is the global position, without damping.
  76. var newPosition = parentPosition + (parentRotation * localPositions[i]);
  77. // Apply damping on this target.
  78. var velocity = velocities[i];
  79. newPosition = Vector3.SmoothDamp(positions[i], newPosition, ref velocity, 0.15f, Mathf.Infinity, stream.deltaTime);
  80. // Apply constraint: keep original length between joints.
  81. newPosition = parentPosition + (newPosition - parentPosition).normalized * localPositions[i].magnitude;
  82. // Save new velocity and position for next frame.
  83. velocities[i] = velocity;
  84. positions[i] = newPosition;
  85. // Current joint is now the parent of the next joint.
  86. parentPosition = newPosition;
  87. parentRotation = parentRotation * localRotations[i];
  88. }
  89. }
  90. /// <summary>
  91. /// Compute the new local rotations of the joints.
  92. ///
  93. /// Based on the global positions computed in ComputeDampedPositions,
  94. /// recompute the local rotation of each joint.
  95. ///
  96. /// Algorithm breakdown:
  97. /// 1. Compute the rotation between the current and new directions of the joint;
  98. /// 2. Apply this rotation on the current joint rotation;
  99. /// 3. Compute the local rotation and set it in the stream;
  100. /// 4. Iterate on the next joint.
  101. /// </summary>
  102. /// <param name="stream">The animation stream</param>
  103. private void ComputeJointLocalRotations(AnimationStream stream)
  104. {
  105. var parentRotation = rootHandle.GetRotation(stream);
  106. for (var i = 0; i < jointHandles.Length - 1; ++i)
  107. {
  108. // Get the current joint rotation.
  109. var rotation = parentRotation * localRotations[i];
  110. // Get the current joint direction.
  111. var direction = (rotation * localPositions[i + 1]).normalized;
  112. // Get the wanted joint direction.
  113. var newDirection = (positions[i + 1] - positions[i]).normalized;
  114. // Compute the rotation from the current direction to the new direction.
  115. var currentToNewRotation = Quaternion.FromToRotation(direction, newDirection);
  116. // Pre-rotate the current rotation, to get the new global rotation.
  117. rotation = currentToNewRotation * rotation;
  118. // Set the new local rotation.
  119. var newLocalRotation = Quaternion.Inverse(parentRotation) * rotation;
  120. jointHandles[i].SetLocalRotation(stream, newLocalRotation);
  121. // Set the new parent for the next joint.
  122. parentRotation = rotation;
  123. }
  124. }
  125. }
  126. }