first commit
This commit is contained in:
@@ -0,0 +1,12 @@
|
||||
using UnityEngine;
|
||||
|
||||
namespace UnityEditor.Animations.Rigging
|
||||
{
|
||||
internal interface IRigEffector
|
||||
{
|
||||
Transform transform { get; }
|
||||
bool visible { get; set; }
|
||||
|
||||
void OnSceneGUI();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 5aa7c79e34bb34aab80024d95fafe526
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,10 @@
|
||||
using System;
|
||||
|
||||
namespace UnityEditor.Animations.Rigging
|
||||
{
|
||||
interface IRigEffectorOverlay : IDisposable
|
||||
{
|
||||
bool IsValid();
|
||||
void OnSceneGUIOverlay();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 4231b7e96c3094051a12f91bae5c7c90
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,307 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using UnityEngine;
|
||||
using UnityEngine.Animations.Rigging;
|
||||
|
||||
namespace UnityEditor.Animations.Rigging
|
||||
{
|
||||
[Serializable]
|
||||
internal class RigEffector : ScriptableObject, IRigEffector
|
||||
{
|
||||
[SerializeField] private RigEffectorData m_Data;
|
||||
|
||||
public Transform transform
|
||||
{
|
||||
get => m_Data.transform;
|
||||
}
|
||||
|
||||
public bool visible
|
||||
{
|
||||
get => m_Data.visible;
|
||||
set => m_Data.visible = value;
|
||||
}
|
||||
|
||||
private static int s_ButtonHash = "RigEffector".GetHashCode();
|
||||
|
||||
public void Initialize(RigEffectorData data)
|
||||
{
|
||||
m_Data = data;
|
||||
}
|
||||
|
||||
private static Material s_Material;
|
||||
|
||||
public static Material material
|
||||
{
|
||||
get
|
||||
{
|
||||
if (!s_Material)
|
||||
{
|
||||
var shader = EditorHelper.LoadShader("BoneHandles.shader");
|
||||
s_Material = new Material(shader);
|
||||
s_Material.hideFlags = HideFlags.HideAndDontSave;
|
||||
}
|
||||
|
||||
return s_Material;
|
||||
}
|
||||
}
|
||||
|
||||
public static RigEffectorData.Style defaultStyle
|
||||
{
|
||||
get
|
||||
{
|
||||
var style = new RigEffectorData.Style()
|
||||
{
|
||||
shape = EditorHelper.LoadShape("LocatorEffector.asset"),
|
||||
color = new Color(1f, 0f, 0f, 0.5f),
|
||||
size = 0.10f,
|
||||
position = Vector3.zero,
|
||||
rotation = Vector3.zero
|
||||
};
|
||||
|
||||
return style;
|
||||
}
|
||||
}
|
||||
|
||||
public void OnSceneGUI()
|
||||
{
|
||||
if (!m_Data.visible)
|
||||
return;
|
||||
|
||||
// Might happen if we delete transform while effector still exists.
|
||||
if (transform == null)
|
||||
return;
|
||||
|
||||
var style = m_Data.style;
|
||||
|
||||
// Disregard effectors without shapes.
|
||||
if (style.shape == null)
|
||||
return;
|
||||
|
||||
if (SceneVisibilityManager.instance.IsHidden(transform.gameObject, false))
|
||||
return;
|
||||
|
||||
var mask = UnityEditor.Tools.visibleLayers;
|
||||
if ((mask & (1 << transform.gameObject.layer)) == 0)
|
||||
return;
|
||||
|
||||
int id = GUIUtility.GetControlID(s_ButtonHash, FocusType.Passive);
|
||||
Event evt = Event.current;
|
||||
|
||||
switch (evt.GetTypeForControl(id))
|
||||
{
|
||||
case EventType.Layout:
|
||||
{
|
||||
HandleUtility.AddControl(id, DistanceToEffector(transform, style.shape, style.position, style.rotation, style.size));
|
||||
break;
|
||||
}
|
||||
case EventType.MouseDown:
|
||||
{
|
||||
if (evt.alt)
|
||||
break;
|
||||
|
||||
if (HandleUtility.nearestControl == id && evt.button == 0)
|
||||
{
|
||||
GameObject targetGameObject = transform.gameObject;
|
||||
if (!SceneVisibilityManager.instance.IsPickingDisabled(targetGameObject, false))
|
||||
{
|
||||
GUIUtility.hotControl = id; // Grab mouse focus
|
||||
EditorHelper.HandleClickSelection(targetGameObject, evt);
|
||||
evt.Use();
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
case EventType.MouseDrag:
|
||||
{
|
||||
if (!evt.alt && GUIUtility.hotControl == id)
|
||||
{
|
||||
GameObject targetGameObject = transform.gameObject;
|
||||
if (!SceneVisibilityManager.instance.IsPickingDisabled(targetGameObject, false))
|
||||
{
|
||||
DragAndDrop.PrepareStartDrag();
|
||||
DragAndDrop.objectReferences = new UnityEngine.Object[] {transform};
|
||||
DragAndDrop.StartDrag(ObjectNames.GetDragAndDropTitle(transform));
|
||||
|
||||
GUIUtility.hotControl = 0;
|
||||
|
||||
evt.Use();
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
case EventType.MouseUp:
|
||||
{
|
||||
if (GUIUtility.hotControl == id && (evt.button == 0 || evt.button == 2))
|
||||
{
|
||||
GUIUtility.hotControl = 0;
|
||||
evt.Use();
|
||||
}
|
||||
break;
|
||||
}
|
||||
case EventType.Repaint:
|
||||
{
|
||||
Matrix4x4 matrix = GetEffectorMatrix(transform, style.position, style.rotation, style.size);
|
||||
|
||||
Color highlight = style.color;
|
||||
|
||||
bool hoveringEffector = GUIUtility.hotControl == 0 && HandleUtility.nearestControl == id;
|
||||
hoveringEffector = hoveringEffector &&
|
||||
!SceneVisibilityManager.instance.IsPickingDisabled(transform.gameObject, false);
|
||||
|
||||
if (hoveringEffector)
|
||||
{
|
||||
highlight = Handles.preselectionColor;
|
||||
}
|
||||
else if (Selection.Contains(transform.gameObject) || Selection.activeObject == transform.gameObject)
|
||||
{
|
||||
highlight = Handles.selectedColor;
|
||||
}
|
||||
|
||||
try
|
||||
{
|
||||
Material mat = material;
|
||||
|
||||
var shapeHighlight = MeshHasWireframeShapes(style.shape) ? style.color : highlight;
|
||||
var wireHighlight = new Color(highlight.r, highlight.g, highlight.b, 1f);
|
||||
|
||||
if (style.shape.subMeshCount > 0)
|
||||
{
|
||||
// Draw every sub meshes separately to control highlight vs shape colors.
|
||||
for (int i = 0; i < style.shape.subMeshCount; ++i)
|
||||
{
|
||||
MeshTopology topology = style.shape.GetTopology(i);
|
||||
bool isFilled = (topology == MeshTopology.Triangles || topology == MeshTopology.Quads);
|
||||
|
||||
mat.SetColor("_Color", isFilled ? shapeHighlight : wireHighlight);
|
||||
mat.SetPass(0);
|
||||
|
||||
Graphics.DrawMeshNow(style.shape, matrix, i);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
MeshTopology topology = style.shape.GetTopology(0);
|
||||
bool isFilled = (topology == MeshTopology.Triangles || topology == MeshTopology.Quads);
|
||||
|
||||
mat.SetColor("_Color", isFilled ? shapeHighlight : wireHighlight);
|
||||
mat.SetPass(0);
|
||||
|
||||
Graphics.DrawMeshNow(style.shape, matrix);
|
||||
}
|
||||
}
|
||||
catch (Exception exception)
|
||||
{
|
||||
Debug.LogException(exception);
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
private bool FindMeshTopology(Mesh shape, IEnumerable<MeshTopology> topologies)
|
||||
{
|
||||
if (shape.subMeshCount > 0)
|
||||
{
|
||||
for (int i = 0; i < shape.subMeshCount; ++i)
|
||||
{
|
||||
MeshTopology topology = shape.GetTopology(i);
|
||||
foreach (var topologyQuery in topologies)
|
||||
{
|
||||
if (topologyQuery == topology)
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
var topology = shape.GetTopology(0);
|
||||
foreach (var topologyQuery in topologies)
|
||||
{
|
||||
if (topologyQuery == topology)
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
private bool MeshHasFilledShapes(Mesh shape) =>
|
||||
FindMeshTopology(shape, new MeshTopology[] {MeshTopology.Triangles, MeshTopology.Quads});
|
||||
|
||||
private bool MeshHasWireframeShapes(Mesh shape) =>
|
||||
FindMeshTopology(shape, new MeshTopology[] {MeshTopology.Lines, MeshTopology.LineStrip});
|
||||
|
||||
private Matrix4x4 GetEffectorMatrix(Transform transform, Vector3 position, Vector3 rotation, float size)
|
||||
{
|
||||
return Matrix4x4.TRS(transform.position, transform.rotation, Vector3.one) * Matrix4x4.TRS(position, Quaternion.Euler(rotation), new Vector3(size, size, size));
|
||||
}
|
||||
|
||||
private float DistanceToEffector(Transform transform, Mesh shape, Vector3 position, Vector3 rotation, float size)
|
||||
{
|
||||
Matrix4x4 matrix = GetEffectorMatrix(transform, position, rotation, size);
|
||||
Vector3 origin = matrix.MultiplyPoint(Vector3.zero);
|
||||
|
||||
if (shape == null)
|
||||
return HandleUtility.DistanceToCircle(origin, size * 0.5f);
|
||||
|
||||
if (MeshHasFilledShapes(shape))
|
||||
{
|
||||
var bounds = shape.bounds;
|
||||
var extents = Mathf.Max( Mathf.Max(bounds.extents.x, bounds.extents.y), bounds.extents.z);
|
||||
return HandleUtility.DistanceToCircle(origin + bounds.center * size, extents * size);
|
||||
}
|
||||
|
||||
float nearestDistance = Mathf.Infinity;
|
||||
|
||||
Vector3[] vertices = shape.vertices;
|
||||
|
||||
for (int i = 0; i < shape.subMeshCount; ++i)
|
||||
{
|
||||
MeshTopology topology = shape.GetTopology(i);
|
||||
if (topology == MeshTopology.Lines)
|
||||
{
|
||||
int[] indices = shape.GetIndices(i);
|
||||
|
||||
int count = 0;
|
||||
while (count < indices.Length)
|
||||
{
|
||||
float d = HandleUtility.DistanceToLine(matrix.MultiplyPoint(vertices[indices[count]]), matrix.MultiplyPoint(vertices[indices[count+1]]));
|
||||
if (d < nearestDistance)
|
||||
nearestDistance = d;
|
||||
|
||||
count += 2;
|
||||
}
|
||||
}
|
||||
else if (topology == MeshTopology.LineStrip)
|
||||
{
|
||||
int[] indices = shape.GetIndices(i);
|
||||
|
||||
if (indices.Length > 0)
|
||||
{
|
||||
int count = 0;
|
||||
float d = 0f;
|
||||
Vector3 v0 = matrix.MultiplyPoint(vertices[indices[count]]);
|
||||
Vector3 v1 = v0;
|
||||
|
||||
while (++count < indices.Length)
|
||||
{
|
||||
Vector3 v2 = matrix.MultiplyPoint(vertices[indices[count]]);
|
||||
|
||||
d = HandleUtility.DistanceToLine(v1, v2);
|
||||
if (d < nearestDistance)
|
||||
nearestDistance = d;
|
||||
|
||||
v1 = v2;
|
||||
}
|
||||
|
||||
d = HandleUtility.DistanceToLine(v1, v0);
|
||||
if (d < nearestDistance)
|
||||
nearestDistance = d;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return nearestDistance;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: ff03b96c5bd3745c28814ed6eb4341cb
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,190 @@
|
||||
using UnityEngine;
|
||||
using UnityEngine.Animations.Rigging;
|
||||
|
||||
namespace UnityEditor.Animations.Rigging
|
||||
{
|
||||
[CustomOverlay(typeof(RigEffector))]
|
||||
class RigEffectorOverlay : IRigEffectorOverlay
|
||||
{
|
||||
private Object[] m_TargetObjects;
|
||||
private SerializedObject m_SerializedObject;
|
||||
|
||||
private SerializedProperty m_Visible;
|
||||
private SerializedProperty m_Shape;
|
||||
private SerializedProperty m_Color;
|
||||
private SerializedProperty m_Size;
|
||||
private SerializedProperty m_Position;
|
||||
private SerializedProperty m_Rotation;
|
||||
|
||||
private bool m_ExpandOverlay;
|
||||
|
||||
private static GUIContent s_VisibleLabel = new GUIContent("Visible");
|
||||
private static GUIContent s_ShapeLabel = new GUIContent("Shape");
|
||||
private static GUIContent s_ColorLabel = new GUIContent("Color");
|
||||
private static GUIContent s_SizeLabel = new GUIContent("Size");
|
||||
private static GUIContent s_PositionLabel = new GUIContent("Position");
|
||||
private static GUIContent s_RotationLabel = new GUIContent("Rotation");
|
||||
|
||||
private static GUIContent s_RemoveLabel = new GUIContent("Remove");
|
||||
|
||||
private static string s_ExpandOverlayPrefKey = "AnimationRigging.ExpandOverlay";
|
||||
|
||||
private static GUILayoutOption s_FixedWidth = GUILayout.Width(210f);
|
||||
|
||||
public void Initialize(Object[] effectors)
|
||||
{
|
||||
m_TargetObjects = effectors;
|
||||
m_SerializedObject = new SerializedObject(effectors);
|
||||
|
||||
SerializedProperty data = m_SerializedObject.FindProperty("m_Data");
|
||||
|
||||
m_Visible = data.FindPropertyRelative("m_Visible");
|
||||
|
||||
SerializedProperty style = data.FindPropertyRelative("m_Style");
|
||||
|
||||
m_Shape = style.FindPropertyRelative("shape");
|
||||
m_Color = style.FindPropertyRelative("color");
|
||||
m_Size = style.FindPropertyRelative("size");
|
||||
m_Position = style.FindPropertyRelative("position");
|
||||
m_Rotation = style.FindPropertyRelative("rotation");
|
||||
|
||||
m_ExpandOverlay = EditorPrefs.GetBool(s_ExpandOverlayPrefKey, true);
|
||||
}
|
||||
|
||||
private IRigEffectorHolder FetchRigEffectorHolder(Transform transform)
|
||||
{
|
||||
var rigBuilder = EditorHelper.GetClosestComponent<RigBuilder>(transform);
|
||||
var rig = EditorHelper.GetClosestComponent<Rig>(transform, (rigBuilder != null) ? rigBuilder.transform : null);
|
||||
|
||||
if (rigBuilder.ContainsEffector(transform))
|
||||
{
|
||||
return rigBuilder;
|
||||
}
|
||||
else if (rig.ContainsEffector(transform))
|
||||
{
|
||||
return rig;
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
public bool IsValid() => m_SerializedObject.targetObject != null;
|
||||
|
||||
public void OnSceneGUIOverlay()
|
||||
{
|
||||
if (!IsValid())
|
||||
return;
|
||||
|
||||
m_SerializedObject.Update();
|
||||
|
||||
GameObject targetGameObject = null;
|
||||
if (!m_SerializedObject.isEditingMultipleObjects)
|
||||
{
|
||||
RigEffector rigEffector = m_SerializedObject.targetObject as RigEffector;
|
||||
if (rigEffector != null && rigEffector.transform != null)
|
||||
{
|
||||
targetGameObject = rigEffector.transform.gameObject;
|
||||
}
|
||||
}
|
||||
|
||||
GUILayout.BeginHorizontal(s_FixedWidth);
|
||||
|
||||
EditorGUI.BeginChangeCheck();
|
||||
m_ExpandOverlay = EditorGUILayout.Toggle(m_ExpandOverlay, EditorStyles.foldout, GUILayout.Width(12));
|
||||
if (EditorGUI.EndChangeCheck())
|
||||
{
|
||||
EditorPrefs.SetBool(s_ExpandOverlayPrefKey, m_ExpandOverlay);
|
||||
}
|
||||
|
||||
GUILayout.BeginHorizontal(EditorStyles.toolbar);
|
||||
|
||||
EditorGUILayout.PropertyField(m_Visible, GUIContent.none, GUILayout.Width(17));
|
||||
|
||||
GUILayout.Label((targetGameObject != null) ? targetGameObject.name : "(Multiple objects)");
|
||||
|
||||
if (GUILayout.Button(GUIContent.none, "OL Minus", GUILayout.Width(17)))
|
||||
{
|
||||
UnityEngine.Object[] targetObjects = m_SerializedObject.targetObjects;
|
||||
foreach(var targetObject in targetObjects)
|
||||
{
|
||||
var effector = targetObject as IRigEffector;
|
||||
Transform transform = effector.transform;
|
||||
|
||||
IRigEffectorHolder holder = FetchRigEffectorHolder(transform);
|
||||
if (holder != null)
|
||||
{
|
||||
var holderObject = holder as UnityEngine.Object;
|
||||
|
||||
Undo.RecordObject(holderObject, "Remove Effector");
|
||||
|
||||
if (PrefabUtility.IsPartOfPrefabInstance(holderObject))
|
||||
EditorUtility.SetDirty(holderObject);
|
||||
|
||||
holder.RemoveEffector(transform);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
GUILayout.EndHorizontal();
|
||||
GUILayout.EndHorizontal();
|
||||
|
||||
if (m_ExpandOverlay)
|
||||
{
|
||||
EditorGUILayout.LabelField(s_ShapeLabel, s_FixedWidth);
|
||||
EditorGUILayout.PropertyField(m_Shape, GUIContent.none, s_FixedWidth);
|
||||
|
||||
Rect rect = GUILayoutUtility.GetRect(s_ColorLabel, EditorStyles.colorField, s_FixedWidth);
|
||||
|
||||
// Shenanigans to bypass color picker bug.
|
||||
var evt = Event.current;
|
||||
if (evt.type == EventType.MouseUp)
|
||||
{
|
||||
if (rect.Contains(evt.mousePosition))
|
||||
{
|
||||
GUIUtility.hotControl = 0;
|
||||
}
|
||||
}
|
||||
|
||||
EditorGUI.BeginProperty(rect, s_ColorLabel, m_Color);
|
||||
EditorGUI.BeginChangeCheck();
|
||||
Color newColor = EditorGUI.ColorField(rect, s_ColorLabel, m_Color.colorValue, false, true, false);
|
||||
if (EditorGUI.EndChangeCheck())
|
||||
{
|
||||
m_Color.colorValue = newColor;
|
||||
}
|
||||
EditorGUI.EndProperty();
|
||||
|
||||
EditorGUILayout.PropertyField(m_Size, s_SizeLabel, s_FixedWidth);
|
||||
EditorGUILayout.PropertyField(m_Position, s_PositionLabel, s_FixedWidth);
|
||||
EditorGUILayout.PropertyField(m_Rotation, s_RotationLabel, s_FixedWidth);
|
||||
}
|
||||
|
||||
if (m_SerializedObject.hasModifiedProperties)
|
||||
{
|
||||
UnityEngine.Object[] targetObjects = m_SerializedObject.targetObjects;
|
||||
foreach(var targetObject in targetObjects)
|
||||
{
|
||||
var effector = targetObject as IRigEffector;
|
||||
Transform transform = effector.transform;
|
||||
|
||||
IRigEffectorHolder holder = FetchRigEffectorHolder(transform);
|
||||
if (holder != null)
|
||||
{
|
||||
var holderObject = holder as UnityEngine.Object;
|
||||
Undo.RecordObject(holderObject, "Edit Effector");
|
||||
|
||||
if (PrefabUtility.IsPartOfPrefabInstance(holderObject))
|
||||
EditorUtility.SetDirty(holderObject);
|
||||
}
|
||||
}
|
||||
|
||||
m_SerializedObject.ApplyModifiedProperties();
|
||||
}
|
||||
}
|
||||
|
||||
public void Dispose()
|
||||
{
|
||||
m_SerializedObject?.Dispose();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 128d92bb7c7e949569b14ae35b4b229e
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,235 @@
|
||||
using System.Collections.Generic;
|
||||
using UnityEngine;
|
||||
using UnityEngine.Animations.Rigging;
|
||||
#if SUPPORTS_SCENE_VIEW_OVERLAYS
|
||||
using UnityEditor.Overlays;
|
||||
#endif
|
||||
using UnityEditor.Experimental.SceneManagement; // required for 2020.2
|
||||
using UnityEditor.SceneManagement;
|
||||
|
||||
namespace UnityEditor.Animations.Rigging
|
||||
{
|
||||
[InitializeOnLoad]
|
||||
static class RigEffectorRenderer
|
||||
{
|
||||
const string k_OverlayId = "Scene View/Animation Rigging";
|
||||
const string k_DisplayName = "Animation Rigging";
|
||||
|
||||
static GUIContent s_OverlayTitle = new GUIContent(k_DisplayName);
|
||||
|
||||
static List<RigBuilder> s_RigBuilders = new List<RigBuilder>();
|
||||
static Dictionary<RigEffectorData, RigEffector> s_Effectors = new Dictionary<RigEffectorData, RigEffector>();
|
||||
|
||||
static Transform[] s_ActiveSelection = null;
|
||||
static List<RigEffector> s_ActiveEffectors = null;
|
||||
static IRigEffectorOverlay s_ActiveOverlay = null;
|
||||
|
||||
static bool s_ActiveOverlayDirtied = true;
|
||||
|
||||
static RigEffectorRenderer()
|
||||
{
|
||||
RigBuilder.onAddRigBuilder += OnAddRigBuilder;
|
||||
RigBuilder.onRemoveRigBuilder += OnRemoveRigBuilder;
|
||||
|
||||
SceneView.duringSceneGui += OnSceneGUI;
|
||||
Selection.selectionChanged += OnSelectionChange;
|
||||
ObjectFactory.componentWasAdded += OnComponentAdded;
|
||||
}
|
||||
|
||||
static void OnSelectionChange()
|
||||
{
|
||||
s_ActiveOverlayDirtied = true;
|
||||
}
|
||||
|
||||
static void OnComponentAdded(Component component)
|
||||
{
|
||||
if (!(component is Rig) && !(component is RigBuilder))
|
||||
return;
|
||||
|
||||
s_ActiveOverlayDirtied = true;
|
||||
}
|
||||
|
||||
static void FetchOrCreateEffectors(IRigEffectorHolder holder)
|
||||
{
|
||||
foreach(var effectorData in holder.effectors)
|
||||
{
|
||||
if (s_Effectors.ContainsKey(effectorData))
|
||||
{
|
||||
s_ActiveEffectors.Add(s_Effectors[effectorData]);
|
||||
}
|
||||
else
|
||||
{
|
||||
var newEffector = ScriptableObject.CreateInstance<RigEffector>();
|
||||
newEffector.Initialize(effectorData);
|
||||
|
||||
s_Effectors.Add(effectorData, newEffector);
|
||||
s_ActiveEffectors.Add(newEffector);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void FetchOrCreateEffectors()
|
||||
{
|
||||
s_ActiveEffectors = new List<RigEffector>();
|
||||
|
||||
PrefabStage prefabStage = PrefabStageUtility.GetCurrentPrefabStage();
|
||||
|
||||
for (int i = 0; i < s_RigBuilders.Count; i++)
|
||||
{
|
||||
var rigBuilder = s_RigBuilders[i];
|
||||
|
||||
if (rigBuilder == null)
|
||||
continue;
|
||||
|
||||
if (prefabStage != null)
|
||||
{
|
||||
StageHandle stageHandle = prefabStage.stageHandle;
|
||||
if (stageHandle.IsValid() && !stageHandle.Contains(rigBuilder.gameObject))
|
||||
continue;
|
||||
}
|
||||
|
||||
FetchOrCreateEffectors(rigBuilder);
|
||||
|
||||
var rigs = rigBuilder.GetComponentsInChildren<Rig>();
|
||||
if (rigs != null)
|
||||
{
|
||||
foreach(var rig in rigs)
|
||||
{
|
||||
FetchOrCreateEffectors(rig);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static IRigEffectorOverlay FetchOrCreateEffectorOverlay()
|
||||
{
|
||||
if (!s_ActiveOverlayDirtied && s_ActiveOverlay != null && s_ActiveOverlay.IsValid())
|
||||
return s_ActiveOverlay;
|
||||
|
||||
s_ActiveOverlay?.Dispose();
|
||||
|
||||
Transform[] transforms = Selection.GetTransforms(SelectionMode.ExcludePrefab | SelectionMode.Editable);
|
||||
var inspectedEffectors = new List<Object>();
|
||||
|
||||
for (int i = 0; i < s_ActiveEffectors.Count; ++i)
|
||||
{
|
||||
var effector = s_ActiveEffectors[i];
|
||||
if (effector != null && effector.transform != null)
|
||||
{
|
||||
if (Selection.Contains(effector.transform) || Selection.Contains(effector.transform.gameObject))
|
||||
{
|
||||
inspectedEffectors.Add(s_ActiveEffectors[i]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (inspectedEffectors.Count > 0)
|
||||
{
|
||||
var overlay = new RigEffectorOverlay();
|
||||
overlay.Initialize(inspectedEffectors.ToArray());
|
||||
|
||||
s_ActiveOverlay = overlay;
|
||||
}
|
||||
else
|
||||
{
|
||||
RigEffectorWizard wizard = null;
|
||||
|
||||
foreach(var transform in transforms)
|
||||
{
|
||||
RigBuilder rigBuilder = EditorHelper.GetClosestComponent<RigBuilder>(transform);
|
||||
Rig rig = EditorHelper.GetClosestComponent<Rig>(transform, (rigBuilder != null) ? rigBuilder.transform : null);
|
||||
IRigEffectorHolder holder = (rig != null) ? (IRigEffectorHolder)rig : (IRigEffectorHolder)rigBuilder;
|
||||
|
||||
if (holder == null)
|
||||
continue;
|
||||
|
||||
if (wizard == null)
|
||||
wizard = new RigEffectorWizard();
|
||||
|
||||
wizard.Add(holder, transform);
|
||||
}
|
||||
|
||||
if (wizard != null)
|
||||
{
|
||||
s_ActiveOverlay = wizard;
|
||||
}
|
||||
else
|
||||
{
|
||||
s_ActiveOverlay = null;
|
||||
}
|
||||
}
|
||||
|
||||
s_ActiveSelection = transforms;
|
||||
|
||||
s_ActiveOverlayDirtied = false;
|
||||
return s_ActiveOverlay;
|
||||
}
|
||||
|
||||
static void OnSceneGUI(SceneView sceneView)
|
||||
{
|
||||
// Fetch effectors and overlay once in Layout before processing events.
|
||||
if (Event.current.type == EventType.Layout)
|
||||
{
|
||||
FetchOrCreateEffectors();
|
||||
FetchOrCreateEffectorOverlay();
|
||||
}
|
||||
|
||||
// Process effector events.
|
||||
if (s_ActiveEffectors != null)
|
||||
{
|
||||
for (int i = 0; i < s_ActiveEffectors.Count; ++i)
|
||||
{
|
||||
var effector = s_ActiveEffectors[i];
|
||||
if (effector == null)
|
||||
continue;
|
||||
|
||||
effector.OnSceneGUI();
|
||||
}
|
||||
}
|
||||
|
||||
#if !SUPPORTS_SCENE_VIEW_OVERLAYS
|
||||
// Process overlay events.
|
||||
if (s_ActiveOverlay != null)
|
||||
{
|
||||
SceneViewOverlay.Begin(sceneView);
|
||||
SceneViewOverlay.Window(s_OverlayTitle, SceneViewGUICallback, 1200);
|
||||
SceneViewOverlay.End();
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
static void OnAddRigBuilder(RigBuilder rigBuilder)
|
||||
{
|
||||
s_RigBuilders.Add(rigBuilder);
|
||||
}
|
||||
|
||||
static void OnRemoveRigBuilder(RigBuilder rigBuilder)
|
||||
{
|
||||
s_RigBuilders.Remove(rigBuilder);
|
||||
s_Effectors.Clear();
|
||||
}
|
||||
|
||||
private static void SceneViewGUICallback(UnityEngine.Object target, SceneView sceneView)
|
||||
{
|
||||
if (s_ActiveOverlay != null)
|
||||
s_ActiveOverlay.OnSceneGUIOverlay();
|
||||
}
|
||||
|
||||
#if SUPPORTS_SCENE_VIEW_OVERLAYS
|
||||
[Overlay(typeof(SceneView), k_OverlayId, k_DisplayName)]
|
||||
class Overlay : IMGUIOverlay, ITransientOverlay
|
||||
{
|
||||
public bool visible
|
||||
{
|
||||
get => s_ActiveOverlay != null;
|
||||
}
|
||||
|
||||
public override void OnGUI()
|
||||
{
|
||||
if (s_ActiveOverlay != null)
|
||||
s_ActiveOverlay.OnSceneGUIOverlay();
|
||||
}
|
||||
}
|
||||
#endif
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: aedff7ad35cc7477a9786519f4791c00
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,68 @@
|
||||
using System.Collections.Generic;
|
||||
using UnityEngine;
|
||||
using UnityEngine.Animations.Rigging;
|
||||
|
||||
namespace UnityEditor.Animations.Rigging
|
||||
{
|
||||
class RigEffectorWizard : IRigEffectorOverlay
|
||||
{
|
||||
private static GUIContent s_CreateEffectorLabel = new GUIContent("Create Effector");
|
||||
|
||||
private struct HolderTransformPair
|
||||
{
|
||||
public IRigEffectorHolder holder;
|
||||
public Transform transform;
|
||||
}
|
||||
|
||||
private List<HolderTransformPair> m_Transforms = new List<HolderTransformPair>();
|
||||
|
||||
public void Add(IRigEffectorHolder holder, Transform transform)
|
||||
{
|
||||
m_Transforms.Add(new HolderTransformPair() { holder = holder, transform = transform });
|
||||
}
|
||||
|
||||
public bool IsValid() => true;
|
||||
|
||||
public void OnSceneGUIOverlay()
|
||||
{
|
||||
string labelName = "(no selection)";
|
||||
if (m_Transforms.Count > 1)
|
||||
{
|
||||
labelName = "(Multiple objects)";
|
||||
}
|
||||
else if (m_Transforms.Count > 0)
|
||||
{
|
||||
if (m_Transforms[0].transform.gameObject != null)
|
||||
{
|
||||
labelName = m_Transforms[0].transform.gameObject.name;
|
||||
}
|
||||
}
|
||||
|
||||
GUILayout.BeginHorizontal(EditorStyles.toolbar, GUILayout.Width(210.0f));
|
||||
|
||||
GUILayout.Label(labelName);
|
||||
|
||||
if (GUILayout.Button(GUIContent.none, "OL Plus", GUILayout.Width(17)))
|
||||
{
|
||||
foreach (var pair in m_Transforms)
|
||||
{
|
||||
var targetObject = pair.holder as UnityEngine.Object;
|
||||
|
||||
Undo.RecordObject(targetObject, "Add Effector");
|
||||
|
||||
if (PrefabUtility.IsPartOfPrefabInstance(targetObject))
|
||||
EditorUtility.SetDirty(targetObject);
|
||||
|
||||
pair.holder.AddEffector(pair.transform, RigEffector.defaultStyle);
|
||||
}
|
||||
}
|
||||
|
||||
GUILayout.EndHorizontal();
|
||||
}
|
||||
|
||||
public void Dispose()
|
||||
{
|
||||
// nothing to do.
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 51459fd0b87be44cbb33be7842186a5e
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
Reference in New Issue
Block a user