AimPoserInspector.cs 6.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190
  1. using UnityEngine;
  2. using UnityEditor;
  3. using System.Collections;
  4. using RootMotion;
  5. namespace RootMotion.FinalIK {
  6. /// <summary>
  7. /// Custom inspector for the Aim Poser for visualizing pose range
  8. /// </summary>
  9. [CustomEditor(typeof(AimPoser))]
  10. public class AimPoserInspector : Editor {
  11. [System.Serializable]
  12. public struct ColorDirection {
  13. public Vector3 direction;
  14. public Vector3 color;
  15. public float dot;
  16. public ColorDirection(Vector3 direction, Vector3 color) {
  17. this.direction = direction.normalized;
  18. this.color = color;
  19. this.dot = 0;
  20. }
  21. }
  22. private AimPoser script { get { return target as AimPoser; }}
  23. private ColorDirection[] colorDirections;
  24. private static Vector3[] poly = new Vector3[36];
  25. void OnSceneGUI() {
  26. for (int i = 0; i < script.poses.Length; i++) {
  27. script.poses[i].yaw = Mathf.Clamp(script.poses[i].yaw, 0, 180);
  28. script.poses[i].pitch = Mathf.Clamp(script.poses[i].pitch, 0, 180);
  29. }
  30. if (colorDirections == null) {
  31. colorDirections = new ColorDirection[6] {
  32. new ColorDirection(Vector3.right, Vector3.right),
  33. new ColorDirection(Vector3.up, Vector3.up),
  34. new ColorDirection(Vector3.forward, Vector3.forward),
  35. new ColorDirection(Vector3.left, new Vector3(0f, 1f, 1f)),
  36. new ColorDirection(Vector3.down, new Vector3(1f, 0f, 1f)),
  37. new ColorDirection(Vector3.back, new Vector3(1f, 1f, 0f))
  38. };
  39. }
  40. for (int i = 0; i < script.poses.Length; i++) {
  41. if (script.poses[i].visualize) {
  42. DrawPose(script.poses[i], script.transform.position, script.transform.rotation, GetDirectionColor(script.poses[i].direction));
  43. }
  44. }
  45. }
  46. private Color GetDirectionColor(Vector3 localDirection) {
  47. localDirection = localDirection.normalized;
  48. // Calculating dot products for all AxisDirections
  49. for (int i = 0; i < colorDirections.Length; i++) {
  50. colorDirections[i].dot = Mathf.Clamp(Vector3.Dot(colorDirections[i].direction, localDirection), 0f, 1f);
  51. }
  52. // Summing up the arm bend axis
  53. Vector3 sum = Vector3.zero;
  54. for (int i = 0; i < colorDirections.Length; i++) {
  55. sum = Vector3.Lerp(sum, colorDirections[i].color, colorDirections[i].dot * colorDirections[i].dot);
  56. }
  57. return new Color(sum.x, sum.y, sum.z);
  58. }
  59. private static void DrawPose(AimPoser.Pose pose, Vector3 position, Quaternion rotation, Color color) {
  60. if (pose.pitch <= 0f || pose.yaw <= 0f) return;
  61. if (pose.direction == Vector3.zero) return;
  62. Handles.color = color;
  63. GUI.color = color;
  64. Vector3 up = rotation * Vector3.up;
  65. Vector3 normalizedPoseDirection = pose.direction.normalized;
  66. Vector3 direction = rotation * normalizedPoseDirection;
  67. // Direction and label
  68. Handles.DrawLine(position, position + direction);
  69. Inspector.ConeCap(0, position + direction, Quaternion.LookRotation(direction), 0.05f);
  70. Handles.Label(position + direction.normalized * 1.1f, pose.name);
  71. if (pose.yaw >= 180f && pose.pitch >= 180f) {
  72. Handles.color = Color.white;
  73. GUI.color = Color.white;
  74. return;
  75. }
  76. Quaternion halfYaw = Quaternion.AngleAxis(pose.yaw, up);
  77. float directionPitch = Vector3.Angle(up, direction);
  78. Vector3 crossRight = halfYaw * Vector3.Cross(up, direction);
  79. Vector3 crossLeft = Quaternion.Inverse(halfYaw) * Vector3.Cross(up, direction);
  80. bool isVertical = normalizedPoseDirection == Vector3.up || normalizedPoseDirection == Vector3.down;
  81. if (isVertical) {
  82. crossRight = halfYaw * Vector3.right;
  83. crossLeft = Quaternion.Inverse(halfYaw) * Vector3.right;
  84. }
  85. float minPitch = Mathf.Clamp(directionPitch - pose.pitch, 0f, 180f);
  86. float maxPitch = Mathf.Clamp(directionPitch + pose.pitch, 0f, 180f);
  87. Quaternion upToCornerUpperRight = Quaternion.AngleAxis(minPitch, crossRight);
  88. Quaternion upToCornerLowerRight = Quaternion.AngleAxis(maxPitch, crossRight);
  89. Quaternion upToCornerUpperLeft = Quaternion.AngleAxis(minPitch, crossLeft);
  90. Quaternion upToCornerLowerLeft = Quaternion.AngleAxis(maxPitch, crossLeft);
  91. Vector3 toCornerUpperRight = upToCornerUpperRight * up;
  92. Vector3 toCornerLowerRight = upToCornerLowerRight * up;
  93. Vector3 toCornerUpperLeft = upToCornerUpperLeft * up;
  94. Vector3 toCornerLowerLeft = upToCornerLowerLeft * up;
  95. if (pose.yaw < 180f) {
  96. Handles.DrawLine(position, position + toCornerUpperRight);
  97. Handles.DrawLine(position, position + toCornerUpperLeft);
  98. Handles.DrawLine(position, position + toCornerLowerRight);
  99. Handles.DrawLine(position, position + toCornerLowerLeft);
  100. }
  101. Vector3 d = direction;
  102. if (isVertical) d = Vector3.forward;
  103. if (pose.pitch < 180f) {
  104. DrawPolyLineOnSphere(position, toCornerUpperLeft, toCornerUpperRight, d, Vector3.up, color);
  105. DrawPolyLineOnSphere(position, toCornerLowerLeft, toCornerLowerRight, d, Vector3.up, color);
  106. }
  107. if (pose.yaw < 180f) {
  108. DrawPolyLineOnSphere(position, toCornerUpperLeft, toCornerLowerLeft, Quaternion.Inverse(halfYaw) * d, crossLeft, color);
  109. DrawPolyLineOnSphere(position, toCornerUpperRight, toCornerLowerRight, halfYaw * d, crossRight, color);
  110. }
  111. Handles.color = Color.white;
  112. GUI.color = Color.white;
  113. }
  114. private static void DrawPolyLineOnSphere(Vector3 center, Vector3 d1, Vector3 d2, Vector3 direction, Vector3 axis, Color color) {
  115. Handles.color = color;
  116. Vector3 normal = axis;
  117. Vector3 d1Ortho = d1;
  118. Vector3.OrthoNormalize(ref normal, ref d1Ortho);
  119. normal = axis;
  120. Vector3 d2Ortho = d2;
  121. Vector3.OrthoNormalize(ref normal, ref d2Ortho);
  122. normal = axis;
  123. Vector3 directionOrtho = direction;
  124. Vector3.OrthoNormalize(ref normal, ref directionOrtho);
  125. float angle = Vector3.Angle(d1Ortho, d2Ortho);
  126. float dot = Vector3.Dot(directionOrtho, d1Ortho);
  127. if (dot < 0) {
  128. angle = 180 + (180 - angle);
  129. }
  130. int segments = Mathf.Clamp(Mathf.RoundToInt(angle / 36f) * 5, 3, 36);
  131. float segmentF = angle / (float)(segments - 1);
  132. for (int i = 0; i < segments; i++) {
  133. poly[i] = center + Quaternion.AngleAxis(i * segmentF, axis) * d1;
  134. }
  135. Handles.color = new Color(color.r, color.g, color.b, color.a * 0.1f);
  136. for (int i = 0; i < segments; i++) {
  137. Handles.DrawLine(center, poly[i]);
  138. }
  139. Handles.color = color;
  140. for (int i = 0; i < segments - 1; i++) {
  141. Handles.DrawLine(poly[i], poly[i + 1]);
  142. }
  143. }
  144. }
  145. }