using System.Collections.Generic; namespace UnityEngine.Animations.Rigging { /// /// The BoneRenderer component is responsible for displaying pickable bones in the Scene View. /// This component does nothing during runtime. /// [ExecuteInEditMode] [AddComponentMenu("Animation Rigging/Setup/Bone Renderer")] [HelpURL("https://docs.unity3d.com/Packages/com.unity.animation.rigging@1.3/manual/RiggingWorkflow.html#bone-renderer-component")] public class BoneRenderer : MonoBehaviour { /// /// Shape used by individual bones. /// public enum BoneShape { /// Bones are rendered with single lines. Line, /// Bones are rendered with pyramid shapes. Pyramid, /// Bones are rendered with box shapes. Box }; /// Shape of the bones. public BoneShape boneShape = BoneShape.Pyramid; /// Toggles whether to render bone shapes or not. public bool drawBones = true; /// Toggles whether to draw tripods on bones or not. public bool drawTripods = false; /// Size of the bones. [Range(0.01f, 5.0f)] public float boneSize = 1.0f; /// Size of the tripod axis. [Range(0.01f, 5.0f)] public float tripodSize = 1.0f; /// Color of the bones. public Color boneColor = new Color(0f, 0f, 1f, 0.5f); [SerializeField] private Transform[] m_Transforms; /// Transform references in the BoneRenderer hierarchy that are used to build bones. public Transform[] transforms { get { return m_Transforms; } #if UNITY_EDITOR set { m_Transforms = value; ExtractBones(); } #endif } #if UNITY_EDITOR /// /// Bone described by two Transform references. /// public struct TransformPair { public Transform first; public Transform second; }; private TransformPair[] m_Bones; private Transform[] m_Tips; /// Retrieves the bones isolated from the Transform references. /// public TransformPair[] bones { get => m_Bones; } /// Retrieves the tip bones isolated from the Transform references. /// public Transform[] tips { get => m_Tips; } /// /// Delegate function that covers a BoneRenderer calling OnEnable. /// /// The BoneRenderer component public delegate void OnAddBoneRendererCallback(BoneRenderer boneRenderer); /// /// Delegate function that covers a BoneRenderer calling OnDisable. /// /// The BoneRenderer component public delegate void OnRemoveBoneRendererCallback(BoneRenderer boneRenderer); /// /// Notification callback that is sent whenever a BoneRenderer calls OnEnable. /// public static OnAddBoneRendererCallback onAddBoneRenderer; /// /// Notification callback that is sent whenever a BoneRenderer calls OnDisable. /// public static OnRemoveBoneRendererCallback onRemoveBoneRenderer; void OnEnable() { ExtractBones(); onAddBoneRenderer?.Invoke(this); } void OnDisable() { onRemoveBoneRenderer?.Invoke(this); } /// /// Invalidate and Rebuild bones and tip bones from Transform references. /// public void Invalidate() { ExtractBones(); } /// /// Resets the BoneRenderer to default values. /// public void Reset() { ClearBones(); } /// /// Clears bones and tip bones. /// public void ClearBones() { m_Bones = null; m_Tips = null; } /// /// Builds bones and tip bones from Transform references. /// public void ExtractBones() { if (m_Transforms == null || m_Transforms.Length == 0) { ClearBones(); return; } var transformsHashSet = new HashSet(m_Transforms); var bonesList = new List(m_Transforms.Length); var tipsList = new List(m_Transforms.Length); for (int i = 0; i < m_Transforms.Length; ++i) { bool hasValidChildren = false; var transform = m_Transforms[i]; if (transform == null) continue; if (UnityEditor.SceneVisibilityManager.instance.IsHidden(transform.gameObject, false)) continue; var mask = UnityEditor.Tools.visibleLayers; if ((mask & (1 << transform.gameObject.layer)) == 0) continue; if (transform.childCount > 0) { for (var k = 0; k < transform.childCount; ++k) { var childTransform = transform.GetChild(k); if (transformsHashSet.Contains(childTransform)) { bonesList.Add(new TransformPair() {first = transform, second = childTransform}); hasValidChildren = true; } } } if (!hasValidChildren) { tipsList.Add(transform); } } m_Bones = bonesList.ToArray(); m_Tips = tipsList.ToArray(); } #endif // UNITY_EDITOR } }