using UnityEngine; using UnityEditor; using System.Collections; using RootMotion; namespace RootMotion.FinalIK { /// /// Custom inspector for the Aim Poser for visualizing pose range /// [CustomEditor(typeof(AimPoser))] public class AimPoserInspector : Editor { [System.Serializable] public struct ColorDirection { public Vector3 direction; public Vector3 color; public float dot; public ColorDirection(Vector3 direction, Vector3 color) { this.direction = direction.normalized; this.color = color; this.dot = 0; } } private AimPoser script { get { return target as AimPoser; }} private ColorDirection[] colorDirections; private static Vector3[] poly = new Vector3[36]; void OnSceneGUI() { for (int i = 0; i < script.poses.Length; i++) { script.poses[i].yaw = Mathf.Clamp(script.poses[i].yaw, 0, 180); script.poses[i].pitch = Mathf.Clamp(script.poses[i].pitch, 0, 180); } if (colorDirections == null) { colorDirections = new ColorDirection[6] { new ColorDirection(Vector3.right, Vector3.right), new ColorDirection(Vector3.up, Vector3.up), new ColorDirection(Vector3.forward, Vector3.forward), new ColorDirection(Vector3.left, new Vector3(0f, 1f, 1f)), new ColorDirection(Vector3.down, new Vector3(1f, 0f, 1f)), new ColorDirection(Vector3.back, new Vector3(1f, 1f, 0f)) }; } for (int i = 0; i < script.poses.Length; i++) { if (script.poses[i].visualize) { DrawPose(script.poses[i], script.transform.position, script.transform.rotation, GetDirectionColor(script.poses[i].direction)); } } } private Color GetDirectionColor(Vector3 localDirection) { localDirection = localDirection.normalized; // Calculating dot products for all AxisDirections for (int i = 0; i < colorDirections.Length; i++) { colorDirections[i].dot = Mathf.Clamp(Vector3.Dot(colorDirections[i].direction, localDirection), 0f, 1f); } // Summing up the arm bend axis Vector3 sum = Vector3.zero; for (int i = 0; i < colorDirections.Length; i++) { sum = Vector3.Lerp(sum, colorDirections[i].color, colorDirections[i].dot * colorDirections[i].dot); } return new Color(sum.x, sum.y, sum.z); } private static void DrawPose(AimPoser.Pose pose, Vector3 position, Quaternion rotation, Color color) { if (pose.pitch <= 0f || pose.yaw <= 0f) return; if (pose.direction == Vector3.zero) return; Handles.color = color; GUI.color = color; Vector3 up = rotation * Vector3.up; Vector3 normalizedPoseDirection = pose.direction.normalized; Vector3 direction = rotation * normalizedPoseDirection; // Direction and label Handles.DrawLine(position, position + direction); Inspector.ConeCap(0, position + direction, Quaternion.LookRotation(direction), 0.05f); Handles.Label(position + direction.normalized * 1.1f, pose.name); if (pose.yaw >= 180f && pose.pitch >= 180f) { Handles.color = Color.white; GUI.color = Color.white; return; } Quaternion halfYaw = Quaternion.AngleAxis(pose.yaw, up); float directionPitch = Vector3.Angle(up, direction); Vector3 crossRight = halfYaw * Vector3.Cross(up, direction); Vector3 crossLeft = Quaternion.Inverse(halfYaw) * Vector3.Cross(up, direction); bool isVertical = normalizedPoseDirection == Vector3.up || normalizedPoseDirection == Vector3.down; if (isVertical) { crossRight = halfYaw * Vector3.right; crossLeft = Quaternion.Inverse(halfYaw) * Vector3.right; } float minPitch = Mathf.Clamp(directionPitch - pose.pitch, 0f, 180f); float maxPitch = Mathf.Clamp(directionPitch + pose.pitch, 0f, 180f); Quaternion upToCornerUpperRight = Quaternion.AngleAxis(minPitch, crossRight); Quaternion upToCornerLowerRight = Quaternion.AngleAxis(maxPitch, crossRight); Quaternion upToCornerUpperLeft = Quaternion.AngleAxis(minPitch, crossLeft); Quaternion upToCornerLowerLeft = Quaternion.AngleAxis(maxPitch, crossLeft); Vector3 toCornerUpperRight = upToCornerUpperRight * up; Vector3 toCornerLowerRight = upToCornerLowerRight * up; Vector3 toCornerUpperLeft = upToCornerUpperLeft * up; Vector3 toCornerLowerLeft = upToCornerLowerLeft * up; if (pose.yaw < 180f) { Handles.DrawLine(position, position + toCornerUpperRight); Handles.DrawLine(position, position + toCornerUpperLeft); Handles.DrawLine(position, position + toCornerLowerRight); Handles.DrawLine(position, position + toCornerLowerLeft); } Vector3 d = direction; if (isVertical) d = Vector3.forward; if (pose.pitch < 180f) { DrawPolyLineOnSphere(position, toCornerUpperLeft, toCornerUpperRight, d, Vector3.up, color); DrawPolyLineOnSphere(position, toCornerLowerLeft, toCornerLowerRight, d, Vector3.up, color); } if (pose.yaw < 180f) { DrawPolyLineOnSphere(position, toCornerUpperLeft, toCornerLowerLeft, Quaternion.Inverse(halfYaw) * d, crossLeft, color); DrawPolyLineOnSphere(position, toCornerUpperRight, toCornerLowerRight, halfYaw * d, crossRight, color); } Handles.color = Color.white; GUI.color = Color.white; } private static void DrawPolyLineOnSphere(Vector3 center, Vector3 d1, Vector3 d2, Vector3 direction, Vector3 axis, Color color) { Handles.color = color; Vector3 normal = axis; Vector3 d1Ortho = d1; Vector3.OrthoNormalize(ref normal, ref d1Ortho); normal = axis; Vector3 d2Ortho = d2; Vector3.OrthoNormalize(ref normal, ref d2Ortho); normal = axis; Vector3 directionOrtho = direction; Vector3.OrthoNormalize(ref normal, ref directionOrtho); float angle = Vector3.Angle(d1Ortho, d2Ortho); float dot = Vector3.Dot(directionOrtho, d1Ortho); if (dot < 0) { angle = 180 + (180 - angle); } int segments = Mathf.Clamp(Mathf.RoundToInt(angle / 36f) * 5, 3, 36); float segmentF = angle / (float)(segments - 1); for (int i = 0; i < segments; i++) { poly[i] = center + Quaternion.AngleAxis(i * segmentF, axis) * d1; } Handles.color = new Color(color.r, color.g, color.b, color.a * 0.1f); for (int i = 0; i < segments; i++) { Handles.DrawLine(center, poly[i]); } Handles.color = color; for (int i = 0; i < segments - 1; i++) { Handles.DrawLine(poly[i], poly[i + 1]); } } } }