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
}
}