DampingJob.cs 6.7 KB

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