first commit
This commit is contained in:
@@ -0,0 +1,8 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 754562bd98582a44e875ea6d688127ac
|
||||
folderAsset: yes
|
||||
DefaultImporter:
|
||||
externalObjects: {}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,163 @@
|
||||
using System.Collections.Generic;
|
||||
using UnityEngine;
|
||||
using UnityEngine.Animations.Rigging;
|
||||
|
||||
namespace UnityEditor.Animations.Rigging
|
||||
{
|
||||
[CustomEditor(typeof(BlendConstraint))]
|
||||
[CanEditMultipleObjects]
|
||||
class BlendConstraintEditor : Editor
|
||||
{
|
||||
static class Content
|
||||
{
|
||||
public static readonly GUIContent sourceObjects = new GUIContent(CommonContent.sourceObjects.text);
|
||||
public static readonly GUIContent sourceA = EditorGUIUtility.TrTextContent(
|
||||
"Source A",
|
||||
"The first source GameObject that influences the position and rotation of the Constrained Object."
|
||||
);
|
||||
public static readonly GUIContent sourceB = EditorGUIUtility.TrTextContent(
|
||||
"Source B",
|
||||
"The second source GameObject that influences the position and rotation of the Constrained Object."
|
||||
);
|
||||
public static readonly GUIContent settings = CommonContent.settings;
|
||||
public static readonly GUIContent maintainOffset = CommonContent.maintainOffset;
|
||||
public static readonly GUIContent blendPosition = EditorGUIUtility.TrTextContent(
|
||||
"Blend A | B Position",
|
||||
"If enabled, the constrained GameObject's position blends between those of Source A and Source B by the specified amount."
|
||||
);
|
||||
public static readonly GUIContent blendRotation = EditorGUIUtility.TrTextContent(
|
||||
"Blend A | B Rotation",
|
||||
"If enabled, the constrained GameObject's rotation blends between those of Source A and Source B by the specified amount."
|
||||
);
|
||||
}
|
||||
|
||||
SerializedProperty m_Weight;
|
||||
SerializedProperty m_ConstrainedObject;
|
||||
SerializedProperty m_SourceA;
|
||||
SerializedProperty m_SourceB;
|
||||
SerializedProperty m_BlendPosition;
|
||||
SerializedProperty m_BlendRotation;
|
||||
SerializedProperty m_PositionWeight;
|
||||
SerializedProperty m_RotationWeight;
|
||||
SerializedProperty m_MaintainPositionOffsets;
|
||||
SerializedProperty m_MaintainRotationOffsets;
|
||||
|
||||
readonly FoldoutState m_SourceObjectsToggle = FoldoutState.ForSourceObjects<BlendConstraintEditor>();
|
||||
readonly FoldoutState m_SettingsToggle = FoldoutState.ForSettings<BlendConstraintEditor>();
|
||||
|
||||
void OnEnable()
|
||||
{
|
||||
m_Weight = serializedObject.FindProperty("m_Weight");
|
||||
|
||||
var data = serializedObject.FindProperty("m_Data");
|
||||
m_ConstrainedObject = data.FindPropertyRelative("m_ConstrainedObject");
|
||||
m_SourceA = data.FindPropertyRelative("m_SourceA");
|
||||
m_SourceB = data.FindPropertyRelative("m_SourceB");
|
||||
m_BlendPosition = data.FindPropertyRelative("m_BlendPosition");
|
||||
m_BlendRotation = data.FindPropertyRelative("m_BlendRotation");
|
||||
m_PositionWeight = data.FindPropertyRelative("m_PositionWeight");
|
||||
m_RotationWeight = data.FindPropertyRelative("m_RotationWeight");
|
||||
m_MaintainPositionOffsets = data.FindPropertyRelative("m_MaintainPositionOffsets");
|
||||
m_MaintainRotationOffsets = data.FindPropertyRelative("m_MaintainRotationOffsets");
|
||||
}
|
||||
|
||||
public override void OnInspectorGUI()
|
||||
{
|
||||
serializedObject.Update();
|
||||
|
||||
EditorGUILayout.PropertyField(m_Weight, CommonContent.weight);
|
||||
EditorGUILayout.PropertyField(m_ConstrainedObject, CommonContent.constrainedObject);
|
||||
|
||||
m_SourceObjectsToggle.value = EditorGUILayout.BeginFoldoutHeaderGroup(m_SourceObjectsToggle.value, Content.sourceObjects);
|
||||
if (m_SourceObjectsToggle.value)
|
||||
{
|
||||
EditorGUI.indentLevel++;
|
||||
EditorGUILayout.PropertyField(m_SourceA, Content.sourceA);
|
||||
EditorGUILayout.PropertyField(m_SourceB, Content.sourceB);
|
||||
EditorGUI.indentLevel--;
|
||||
}
|
||||
EditorGUILayout.EndFoldoutHeaderGroup();
|
||||
|
||||
m_SettingsToggle.value = EditorGUILayout.BeginFoldoutHeaderGroup(m_SettingsToggle.value, Content.settings);
|
||||
if (m_SettingsToggle.value)
|
||||
{
|
||||
EditorGUI.indentLevel++;
|
||||
|
||||
MaintainOffsetHelper.DoDropdown(Content.maintainOffset, m_MaintainPositionOffsets, m_MaintainRotationOffsets);
|
||||
|
||||
EditorGUILayout.BeginHorizontal();
|
||||
EditorGUILayout.PropertyField(m_BlendPosition, Content.blendPosition);
|
||||
using (new EditorGUI.DisabledScope(!m_BlendPosition.boolValue))
|
||||
EditorGUILayout.PropertyField(m_PositionWeight, GUIContent.none);
|
||||
EditorGUILayout.EndHorizontal();
|
||||
|
||||
EditorGUILayout.BeginHorizontal();
|
||||
EditorGUILayout.PropertyField(m_BlendRotation, Content.blendRotation);
|
||||
using (new EditorGUI.DisabledScope(!m_BlendRotation.boolValue))
|
||||
EditorGUILayout.PropertyField(m_RotationWeight, GUIContent.none);
|
||||
EditorGUILayout.EndHorizontal();
|
||||
|
||||
EditorGUI.indentLevel--;
|
||||
}
|
||||
EditorGUILayout.EndFoldoutHeaderGroup();
|
||||
|
||||
serializedObject.ApplyModifiedProperties();
|
||||
}
|
||||
|
||||
[MenuItem("CONTEXT/BlendConstraint/Transfer motion to skeleton", false, 612)]
|
||||
public static void TransferMotionToSkeleton(MenuCommand command)
|
||||
{
|
||||
var constraint = command.context as BlendConstraint;
|
||||
BakeUtils.TransferMotionToSkeleton(constraint);
|
||||
}
|
||||
|
||||
[MenuItem("CONTEXT/BlendConstraint/Transfer motion to skeleton", true)]
|
||||
public static bool TransferMotionValidate(MenuCommand command)
|
||||
{
|
||||
var constraint = command.context as BlendConstraint;
|
||||
return BakeUtils.TransferMotionValidate(constraint);
|
||||
}
|
||||
}
|
||||
|
||||
[BakeParameters(typeof(BlendConstraint))]
|
||||
class BlendConstraintBakeParameters : BakeParameters<BlendConstraint>
|
||||
{
|
||||
public override bool canBakeToSkeleton => true;
|
||||
public override bool canBakeToConstraint => false;
|
||||
|
||||
public override IEnumerable<EditorCurveBinding> GetSourceCurveBindings(RigBuilder rigBuilder, BlendConstraint constraint)
|
||||
{
|
||||
var bindings = new List<EditorCurveBinding>();
|
||||
var sourceA = constraint.data.sourceObjectA;
|
||||
var sourceB = constraint.data.sourceObjectB;
|
||||
|
||||
if (constraint.data.blendPosition)
|
||||
{
|
||||
EditorCurveBindingUtils.CollectPositionBindings(rigBuilder.transform, sourceA, bindings);
|
||||
EditorCurveBindingUtils.CollectPositionBindings(rigBuilder.transform, sourceB, bindings);
|
||||
}
|
||||
|
||||
if (constraint.data.blendRotation)
|
||||
{
|
||||
EditorCurveBindingUtils.CollectRotationBindings(rigBuilder.transform, sourceA, bindings);
|
||||
EditorCurveBindingUtils.CollectRotationBindings(rigBuilder.transform, sourceB, bindings);
|
||||
}
|
||||
|
||||
return bindings;
|
||||
}
|
||||
|
||||
public override IEnumerable<EditorCurveBinding> GetConstrainedCurveBindings(RigBuilder rigBuilder, BlendConstraint constraint)
|
||||
{
|
||||
var bindings = new List<EditorCurveBinding>();
|
||||
var constrained = constraint.data.constrainedObject;
|
||||
|
||||
if (constraint.data.blendPosition)
|
||||
EditorCurveBindingUtils.CollectPositionBindings(rigBuilder.transform, constrained, bindings);
|
||||
|
||||
if(constraint.data.blendRotation)
|
||||
EditorCurveBindingUtils.CollectRotationBindings(rigBuilder.transform, constrained, bindings);
|
||||
|
||||
return bindings;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: a8670d948642f1546a4835c189aea303
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,156 @@
|
||||
using System.Collections.Generic;
|
||||
using UnityEngine;
|
||||
using UnityEngine.Animations.Rigging;
|
||||
|
||||
namespace UnityEditor.Animations.Rigging
|
||||
{
|
||||
[CustomEditor(typeof(ChainIKConstraint))]
|
||||
[CanEditMultipleObjects]
|
||||
class ChainIKConstraintEditor : Editor
|
||||
{
|
||||
static class Content
|
||||
{
|
||||
public static readonly GUIContent root = EditorGUIUtility.TrTextContent(
|
||||
"Root",
|
||||
"The root GameObject of the chain hierarchy."
|
||||
);
|
||||
public static readonly GUIContent tip = EditorGUIUtility.TrTextContent(
|
||||
"Tip",
|
||||
"The final GameObject of the chain hierarchy. It must be a descendant of the Root GameObject."
|
||||
);
|
||||
public static readonly GUIContent target = EditorGUIUtility.TrTextContent(
|
||||
"Target",
|
||||
"The GameObject that specifies the desired target transform for the chain's Tip."
|
||||
);
|
||||
public static readonly GUIContent sourceObjects = new GUIContent(CommonContent.sourceObjects.text);
|
||||
public static readonly GUIContent chainRotationWeight = EditorGUIUtility.TrTextContent(
|
||||
"Chain Rotation Weight",
|
||||
"The weight of rotations applied throughout the chain."
|
||||
);
|
||||
public static readonly GUIContent tipRotationWeight = EditorGUIUtility.TrTextContent(
|
||||
"Tip Rotation Weight",
|
||||
"The weight of the rotation applied to the Tip."
|
||||
);
|
||||
public static readonly GUIContent maxIterations = EditorGUIUtility.TrTextContent(
|
||||
"Max Iterations",
|
||||
"The maximum number of solver iterations to perform to try to make the Tip reach the Target within the specified Tolerance threshold."
|
||||
);
|
||||
public static readonly GUIContent tolerance = EditorGUIUtility.TrTextContent(
|
||||
"Tolerance",
|
||||
"Distance tolerance between the Target and Tip GameObjects. " +
|
||||
"The solver will finish its computation if the distance is less than this value at any point, even if Max Iterations has not been reached."
|
||||
);
|
||||
}
|
||||
|
||||
SerializedProperty m_Weight;
|
||||
SerializedProperty m_Root;
|
||||
SerializedProperty m_Tip;
|
||||
SerializedProperty m_Target;
|
||||
SerializedProperty m_ChainRotationWeight;
|
||||
SerializedProperty m_TipRotationWeight;
|
||||
SerializedProperty m_MaxIterations;
|
||||
SerializedProperty m_Tolerance;
|
||||
SerializedProperty m_MaintainTargetPositionOffset;
|
||||
SerializedProperty m_MaintainTargetRotationOffset;
|
||||
|
||||
readonly FoldoutState m_SourceObjectsToggle = FoldoutState.ForSourceObjects<ChainIKConstraintEditor>();
|
||||
readonly FoldoutState m_SettingsToggle = FoldoutState.ForSettings<ChainIKConstraintEditor>();
|
||||
|
||||
void OnEnable()
|
||||
{
|
||||
m_Weight = serializedObject.FindProperty("m_Weight");
|
||||
|
||||
var data = serializedObject.FindProperty("m_Data");
|
||||
m_Root = data.FindPropertyRelative("m_Root");
|
||||
m_Tip = data.FindPropertyRelative("m_Tip");
|
||||
m_Target = data.FindPropertyRelative("m_Target");
|
||||
m_ChainRotationWeight = data.FindPropertyRelative("m_ChainRotationWeight");
|
||||
m_TipRotationWeight = data.FindPropertyRelative("m_TipRotationWeight");
|
||||
m_MaxIterations = data.FindPropertyRelative("m_MaxIterations");
|
||||
m_Tolerance = data.FindPropertyRelative("m_Tolerance");
|
||||
m_MaintainTargetPositionOffset = data.FindPropertyRelative("m_MaintainTargetPositionOffset");
|
||||
m_MaintainTargetRotationOffset = data.FindPropertyRelative("m_MaintainTargetRotationOffset");
|
||||
}
|
||||
|
||||
public override void OnInspectorGUI()
|
||||
{
|
||||
serializedObject.Update();
|
||||
|
||||
EditorGUILayout.PropertyField(m_Weight, CommonContent.weight);
|
||||
EditorGUILayout.PropertyField(m_Root, Content.root);
|
||||
EditorGUILayout.PropertyField(m_Tip, Content.tip);
|
||||
|
||||
m_SourceObjectsToggle.value = EditorGUILayout.BeginFoldoutHeaderGroup(m_SourceObjectsToggle.value, Content.sourceObjects);
|
||||
if (m_SourceObjectsToggle.value)
|
||||
{
|
||||
EditorGUI.indentLevel++;
|
||||
EditorGUILayout.PropertyField(m_Target, Content.target);
|
||||
EditorGUI.indentLevel--;
|
||||
}
|
||||
EditorGUILayout.EndFoldoutHeaderGroup();
|
||||
|
||||
m_SettingsToggle.value = EditorGUILayout.BeginFoldoutHeaderGroup(m_SettingsToggle.value, CommonContent.settings);
|
||||
if (m_SettingsToggle.value)
|
||||
{
|
||||
EditorGUI.indentLevel++;
|
||||
MaintainOffsetHelper.DoDropdown(CommonContent.maintainIKTargetOffset, m_MaintainTargetPositionOffset, m_MaintainTargetRotationOffset);
|
||||
EditorGUILayout.PropertyField(m_ChainRotationWeight, Content.chainRotationWeight);
|
||||
EditorGUILayout.PropertyField(m_TipRotationWeight, Content.tipRotationWeight);
|
||||
EditorGUILayout.PropertyField(m_MaxIterations, Content.maxIterations);
|
||||
EditorGUILayout.PropertyField(m_Tolerance, Content.tolerance);
|
||||
EditorGUI.indentLevel--;
|
||||
}
|
||||
EditorGUILayout.EndFoldoutHeaderGroup();
|
||||
|
||||
serializedObject.ApplyModifiedProperties();
|
||||
}
|
||||
|
||||
[MenuItem("CONTEXT/ChainIKConstraint/Transfer motion to skeleton", false, 612)]
|
||||
public static void TransferMotionToSkeleton(MenuCommand command)
|
||||
{
|
||||
var constraint = command.context as ChainIKConstraint;
|
||||
BakeUtils.TransferMotionToSkeleton(constraint);
|
||||
}
|
||||
|
||||
[MenuItem("CONTEXT/ChainIKConstraint/Transfer motion to skeleton", true)]
|
||||
public static bool TransferMotionValidate(MenuCommand command)
|
||||
{
|
||||
var constraint = command.context as ChainIKConstraint;
|
||||
return BakeUtils.TransferMotionValidate(constraint);
|
||||
}
|
||||
}
|
||||
|
||||
[BakeParameters(typeof(ChainIKConstraint))]
|
||||
class ChainIKConstraintBakeParameters : BakeParameters<ChainIKConstraint>
|
||||
{
|
||||
public override bool canBakeToSkeleton => true;
|
||||
public override bool canBakeToConstraint => false;
|
||||
|
||||
public override IEnumerable<EditorCurveBinding> GetSourceCurveBindings(RigBuilder rigBuilder, ChainIKConstraint constraint)
|
||||
{
|
||||
var bindings = new List<EditorCurveBinding>();
|
||||
|
||||
EditorCurveBindingUtils.CollectTRBindings(rigBuilder.transform, constraint.data.target, bindings);
|
||||
|
||||
return bindings;
|
||||
}
|
||||
|
||||
public override IEnumerable<EditorCurveBinding> GetConstrainedCurveBindings(RigBuilder rigBuilder, ChainIKConstraint constraint)
|
||||
{
|
||||
var bindings = new List<EditorCurveBinding>();
|
||||
|
||||
var root = constraint.data.root;
|
||||
var tip = constraint.data.tip;
|
||||
|
||||
var tmp = tip;
|
||||
while (tmp != root)
|
||||
{
|
||||
EditorCurveBindingUtils.CollectRotationBindings(rigBuilder.transform, tmp, bindings);
|
||||
tmp = tmp.parent;
|
||||
}
|
||||
EditorCurveBindingUtils.CollectRotationBindings(rigBuilder.transform, root, bindings);
|
||||
|
||||
return bindings;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 63110210264e2ee4da7389733e5958ae
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,122 @@
|
||||
using System.Collections.Generic;
|
||||
using UnityEngine;
|
||||
using UnityEngine.Animations.Rigging;
|
||||
|
||||
namespace UnityEditor.Animations.Rigging
|
||||
{
|
||||
[CustomEditor(typeof(DampedTransform))]
|
||||
[CanEditMultipleObjects]
|
||||
class DampedTransformEditor : Editor
|
||||
{
|
||||
static class Content
|
||||
{
|
||||
public static readonly GUIContent source = EditorGUIUtility.TrTextContent(
|
||||
"Source",
|
||||
"The GameObject that influences the Constrained Object's transform."
|
||||
);
|
||||
public static readonly GUIContent dampPosition = EditorGUIUtility.TrTextContent(
|
||||
"Damp Position",
|
||||
"The weight of positional damping to apply to the Constrained Object."
|
||||
);
|
||||
public static readonly GUIContent dampRotation = EditorGUIUtility.TrTextContent(
|
||||
"Damp Rotation",
|
||||
"The weight of rotational damping to apply to the Constrained Object."
|
||||
);
|
||||
public static readonly GUIContent maintainAim = EditorGUIUtility.TrTextContent(
|
||||
"Maintain Aim",
|
||||
"Specifies whether to maintain the initial rotation offset between the Constrained Object and the Source Object."
|
||||
);
|
||||
}
|
||||
|
||||
SerializedProperty m_Weight;
|
||||
SerializedProperty m_ConstrainedObject;
|
||||
SerializedProperty m_Source;
|
||||
SerializedProperty m_DampPosition;
|
||||
SerializedProperty m_DampRotation;
|
||||
SerializedProperty m_MaintainAim;
|
||||
|
||||
readonly FoldoutState m_SourceObjectsToggle = FoldoutState.ForSourceObjects<DampedTransformEditor>();
|
||||
readonly FoldoutState m_SettingsToggle = FoldoutState.ForSettings<DampedTransformEditor>();
|
||||
|
||||
void OnEnable()
|
||||
{
|
||||
m_Weight = serializedObject.FindProperty("m_Weight");
|
||||
|
||||
var data = serializedObject.FindProperty("m_Data");
|
||||
m_ConstrainedObject = data.FindPropertyRelative("m_ConstrainedObject");
|
||||
m_Source = data.FindPropertyRelative("m_Source");
|
||||
m_DampPosition = data.FindPropertyRelative("m_DampPosition");
|
||||
m_DampRotation = data.FindPropertyRelative("m_DampRotation");
|
||||
m_MaintainAim = data.FindPropertyRelative("m_MaintainAim");
|
||||
}
|
||||
|
||||
public override void OnInspectorGUI()
|
||||
{
|
||||
serializedObject.Update();
|
||||
|
||||
EditorGUILayout.PropertyField(m_Weight, CommonContent.weight);
|
||||
EditorGUILayout.PropertyField(m_ConstrainedObject, CommonContent.constrainedObject);
|
||||
|
||||
m_SourceObjectsToggle.value = EditorGUILayout.BeginFoldoutHeaderGroup(m_SourceObjectsToggle.value, Content.source);
|
||||
if (m_SourceObjectsToggle.value)
|
||||
{
|
||||
EditorGUI.indentLevel++;
|
||||
EditorGUILayout.PropertyField(m_Source, Content.source);
|
||||
EditorGUI.indentLevel--;
|
||||
}
|
||||
EditorGUILayout.EndFoldoutHeaderGroup();
|
||||
|
||||
m_SettingsToggle.value = EditorGUILayout.BeginFoldoutHeaderGroup(m_SettingsToggle.value, CommonContent.settings);
|
||||
if (m_SettingsToggle.value)
|
||||
{
|
||||
EditorGUI.indentLevel++;
|
||||
EditorGUILayout.PropertyField(m_DampPosition, Content.dampPosition);
|
||||
EditorGUILayout.PropertyField(m_DampRotation, Content.dampRotation);
|
||||
EditorGUILayout.PropertyField(m_MaintainAim, Content.maintainAim);
|
||||
EditorGUI.indentLevel--;
|
||||
}
|
||||
EditorGUILayout.EndFoldoutHeaderGroup();
|
||||
|
||||
serializedObject.ApplyModifiedProperties();
|
||||
}
|
||||
|
||||
[MenuItem("CONTEXT/DampedTransform/Transfer motion to skeleton", false, 612)]
|
||||
public static void TransferMotionToSkeleton(MenuCommand command)
|
||||
{
|
||||
var constraint = command.context as DampedTransform;
|
||||
BakeUtils.TransferMotionToSkeleton(constraint);
|
||||
}
|
||||
|
||||
[MenuItem("CONTEXT/DampedTransform/Transfer motion to skeleton", true)]
|
||||
public static bool TransferMotionValidate(MenuCommand command)
|
||||
{
|
||||
var constraint = command.context as DampedTransform;
|
||||
return BakeUtils.TransferMotionValidate(constraint);
|
||||
}
|
||||
}
|
||||
|
||||
[BakeParameters(typeof(DampedTransform))]
|
||||
class DampedTransformBakeParameters : BakeParameters<DampedTransform>
|
||||
{
|
||||
public override bool canBakeToSkeleton => true;
|
||||
public override bool canBakeToConstraint => false;
|
||||
|
||||
public override IEnumerable<EditorCurveBinding> GetSourceCurveBindings(RigBuilder rigBuilder, DampedTransform constraint)
|
||||
{
|
||||
var bindings = new List<EditorCurveBinding>();
|
||||
|
||||
EditorCurveBindingUtils.CollectTRBindings(rigBuilder.transform, constraint.data.sourceObject, bindings);
|
||||
|
||||
return bindings;
|
||||
}
|
||||
|
||||
public override IEnumerable<EditorCurveBinding> GetConstrainedCurveBindings(RigBuilder rigBuilder, DampedTransform constraint)
|
||||
{
|
||||
var bindings = new List<EditorCurveBinding>();
|
||||
|
||||
EditorCurveBindingUtils.CollectTRBindings(rigBuilder.transform, constraint.data.constrainedObject, bindings);
|
||||
|
||||
return bindings;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 99a3cbe2e69614541bdf264c5e905f48
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,197 @@
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using UnityEngine;
|
||||
using UnityEngine.Animations.Rigging;
|
||||
|
||||
namespace UnityEditor.Animations.Rigging
|
||||
{
|
||||
[CustomEditor(typeof(MultiAimConstraint))]
|
||||
[CanEditMultipleObjects]
|
||||
class MultiAimConstraintEditor : Editor
|
||||
{
|
||||
static class Content
|
||||
{
|
||||
public static readonly GUIContent[] axisLabels = new []{ "X", "-X", "Y", "-Y", "Z", "-Z" }
|
||||
.Select(c => new GUIContent(c))
|
||||
.ToArray();
|
||||
public static readonly GUIContent aimAxis = EditorGUIUtility.TrTextContent(
|
||||
"Aim Axis",
|
||||
"Specifies the local aim axis of the Constrained Object to use in order to orient its forward direction to the Source Objects."
|
||||
);
|
||||
public static readonly GUIContent upAxis = EditorGUIUtility.TrTextContent(
|
||||
"Up Axis",
|
||||
"Specifies the local up axis of the Constrained Object to use in order to orient its upward direction (i.e., roll orientation)."
|
||||
);
|
||||
public static readonly GUIContent worldUpType = EditorGUIUtility.TrTextContent(
|
||||
"World Up Type",
|
||||
"Specifies which mode to use to stabilize the upward direction (i.e., roll orientation) of the Constrained Object."
|
||||
);
|
||||
public static readonly GUIContent worldUpAxis = EditorGUIUtility.TrTextContent(
|
||||
"World Up Axis",
|
||||
"A vector in some reference frame that is used to stabilize the upward direction of the Constrained Object. " +
|
||||
"This value is used when World Up Type is either Vector or Object Rotation Up."
|
||||
);
|
||||
public static readonly GUIContent worldUpObject = EditorGUIUtility.TrTextContent(
|
||||
"World Up Object",
|
||||
"A GameObject used as a reference frame for World Up Axis. " +
|
||||
"This value is used when World Up Type is either Object Up or Object Rotation Up."
|
||||
);
|
||||
public static readonly GUIContent sourceObjects = CommonContent.sourceObjectsWeightedRotation;
|
||||
public static readonly GUIContent settings = CommonContent.settings;
|
||||
public static readonly GUIContent maintainOffset = CommonContent.maintainRotationOffset;
|
||||
public static readonly GUIContent minLimit = EditorGUIUtility.TrTextContent(
|
||||
"Min Limit",
|
||||
"Clamps the minimum rotation that may be applied about any of the constrained axes of rotation."
|
||||
);
|
||||
public static readonly GUIContent maxLimit = EditorGUIUtility.TrTextContent(
|
||||
"Max Limit",
|
||||
"Clamps the maximum rotation that may be applied about any of the constrained axes of rotation."
|
||||
);
|
||||
}
|
||||
|
||||
SerializedProperty m_Weight;
|
||||
SerializedProperty m_ConstrainedObject;
|
||||
SerializedProperty m_AimAxis;
|
||||
SerializedProperty m_UpAxis;
|
||||
SerializedProperty m_WorldUpType;
|
||||
SerializedProperty m_WorldUpAxis;
|
||||
SerializedProperty m_WorldUpObject;
|
||||
SerializedProperty m_SourceObjects;
|
||||
SerializedProperty m_MaintainOffset;
|
||||
SerializedProperty m_Offset;
|
||||
SerializedProperty m_ConstrainedAxes;
|
||||
SerializedProperty m_MinLimit;
|
||||
SerializedProperty m_MaxLimit;
|
||||
|
||||
readonly FoldoutState m_SettingsToggle = FoldoutState.ForSettings<MultiAimConstraintEditor>();
|
||||
|
||||
void OnEnable()
|
||||
{
|
||||
m_Weight = serializedObject.FindProperty("m_Weight");
|
||||
|
||||
var data = serializedObject.FindProperty("m_Data");
|
||||
m_ConstrainedObject = data.FindPropertyRelative("m_ConstrainedObject");
|
||||
m_AimAxis = data.FindPropertyRelative("m_AimAxis");
|
||||
m_UpAxis = data.FindPropertyRelative("m_UpAxis");
|
||||
m_WorldUpType = data.FindPropertyRelative("m_WorldUpType");
|
||||
m_WorldUpAxis = data.FindPropertyRelative("m_WorldUpAxis");
|
||||
m_WorldUpObject = data.FindPropertyRelative("m_WorldUpObject");
|
||||
m_SourceObjects = data.FindPropertyRelative("m_SourceObjects");
|
||||
m_MaintainOffset = data.FindPropertyRelative("m_MaintainOffset");
|
||||
m_Offset = data.FindPropertyRelative("m_Offset");
|
||||
m_ConstrainedAxes = data.FindPropertyRelative("m_ConstrainedAxes");
|
||||
m_MinLimit = data.FindPropertyRelative("m_MinLimit");
|
||||
m_MaxLimit = data.FindPropertyRelative("m_MaxLimit");
|
||||
}
|
||||
|
||||
public override void OnInspectorGUI()
|
||||
{
|
||||
serializedObject.Update();
|
||||
|
||||
EditorGUILayout.PropertyField(m_Weight, CommonContent.weight);
|
||||
|
||||
EditorGUILayout.PropertyField(m_ConstrainedObject, CommonContent.constrainedObject);
|
||||
|
||||
++EditorGUI.indentLevel;
|
||||
DoAxisField(m_AimAxis, Content.aimAxis);
|
||||
DoAxisField(m_UpAxis, Content.upAxis);
|
||||
--EditorGUI.indentLevel;
|
||||
|
||||
EditorGUILayout.PropertyField(m_WorldUpType, Content.worldUpType);
|
||||
|
||||
var worldUpType = (MultiAimConstraintData.WorldUpType)m_WorldUpType.intValue;
|
||||
|
||||
++EditorGUI.indentLevel;
|
||||
using (new EditorGUI.DisabledGroupScope(worldUpType != MultiAimConstraintData.WorldUpType.ObjectRotationUp && worldUpType != MultiAimConstraintData.WorldUpType.Vector))
|
||||
{
|
||||
DoAxisField(m_WorldUpAxis, Content.worldUpAxis);
|
||||
}
|
||||
using (new EditorGUI.DisabledGroupScope(worldUpType != MultiAimConstraintData.WorldUpType.ObjectUp && worldUpType != MultiAimConstraintData.WorldUpType.ObjectRotationUp))
|
||||
{
|
||||
EditorGUILayout.PropertyField(m_WorldUpObject, Content.worldUpObject);
|
||||
}
|
||||
--EditorGUI.indentLevel;
|
||||
|
||||
EditorGUILayout.PropertyField(m_SourceObjects, Content.sourceObjects);
|
||||
|
||||
m_SettingsToggle.value = EditorGUILayout.BeginFoldoutHeaderGroup(m_SettingsToggle.value, Content.settings);
|
||||
if (m_SettingsToggle.value)
|
||||
{
|
||||
EditorGUI.indentLevel++;
|
||||
EditorGUILayout.PropertyField(m_MaintainOffset, Content.maintainOffset);
|
||||
EditorGUILayout.PropertyField(m_Offset, CommonContent.offsetRotation);
|
||||
EditorGUILayout.PropertyField(m_ConstrainedAxes, CommonContent.constrainedAxesRotation);
|
||||
EditorGUILayout.PropertyField(m_MinLimit, Content.minLimit);
|
||||
EditorGUILayout.PropertyField(m_MaxLimit, Content.maxLimit);
|
||||
EditorGUI.indentLevel--;
|
||||
}
|
||||
EditorGUILayout.EndFoldoutHeaderGroup();
|
||||
|
||||
serializedObject.ApplyModifiedProperties();
|
||||
}
|
||||
|
||||
static void DoAxisField(SerializedProperty property, GUIContent label)
|
||||
{
|
||||
var rect = EditorGUILayout.GetControlRect();
|
||||
EditorGUI.BeginProperty(rect, label, property);
|
||||
EditorGUI.BeginChangeCheck();
|
||||
var newValue = EditorGUI.Popup(rect, label, property.intValue, Content.axisLabels);
|
||||
if (EditorGUI.EndChangeCheck())
|
||||
property.intValue = newValue;
|
||||
EditorGUI.EndProperty();
|
||||
}
|
||||
|
||||
[MenuItem("CONTEXT/MultiAimConstraint/Transfer motion to constraint", false, 611)]
|
||||
public static void TransferMotionToConstraint(MenuCommand command)
|
||||
{
|
||||
var constraint = command.context as MultiAimConstraint;
|
||||
BakeUtils.TransferMotionToConstraint(constraint);
|
||||
}
|
||||
|
||||
[MenuItem("CONTEXT/MultiAimConstraint/Transfer motion to skeleton", false, 612)]
|
||||
public static void TransferMotionToSkeleton(MenuCommand command)
|
||||
{
|
||||
var constraint = command.context as MultiAimConstraint;
|
||||
BakeUtils.TransferMotionToSkeleton(constraint);
|
||||
}
|
||||
|
||||
[MenuItem("CONTEXT/MultiAimConstraint/Transfer motion to constraint", true)]
|
||||
[MenuItem("CONTEXT/MultiAimConstraint/Transfer motion to skeleton", true)]
|
||||
public static bool TransferMotionValidate(MenuCommand command)
|
||||
{
|
||||
var constraint = command.context as MultiAimConstraint;
|
||||
return BakeUtils.TransferMotionValidate(constraint);
|
||||
}
|
||||
}
|
||||
|
||||
[BakeParameters(typeof(MultiAimConstraint))]
|
||||
class MultiAimConstraintBakeParameters : BakeParameters<MultiAimConstraint>
|
||||
{
|
||||
public override bool canBakeToSkeleton => true;
|
||||
public override bool canBakeToConstraint => true;
|
||||
|
||||
public override IEnumerable<EditorCurveBinding> GetSourceCurveBindings(RigBuilder rigBuilder, MultiAimConstraint constraint)
|
||||
{
|
||||
var bindings = new List<EditorCurveBinding>();
|
||||
|
||||
for (int i = 0; i < constraint.data.sourceObjects.Count; ++i)
|
||||
{
|
||||
var sourceObject = constraint.data.sourceObjects[i];
|
||||
|
||||
EditorCurveBindingUtils.CollectPositionBindings(rigBuilder.transform, sourceObject.transform, bindings);
|
||||
EditorCurveBindingUtils.CollectPropertyBindings(rigBuilder.transform, constraint, ((IMultiAimConstraintData)constraint.data).sourceObjectsProperty + ".m_Item" + i + ".weight", bindings);
|
||||
}
|
||||
|
||||
return bindings;
|
||||
}
|
||||
|
||||
public override IEnumerable<EditorCurveBinding> GetConstrainedCurveBindings(RigBuilder rigBuilder, MultiAimConstraint constraint)
|
||||
{
|
||||
var bindings = new List<EditorCurveBinding>();
|
||||
|
||||
EditorCurveBindingUtils.CollectRotationBindings(rigBuilder.transform, constraint.data.constrainedObject, bindings);
|
||||
|
||||
return bindings;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 9a96277d4d9d2d04181fc5ce44119fdf
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,121 @@
|
||||
using UnityEngine;
|
||||
using UnityEngine.Animations.Rigging;
|
||||
using System.Collections.Generic;
|
||||
|
||||
namespace UnityEditor.Animations.Rigging
|
||||
{
|
||||
[CustomEditor(typeof(MultiParentConstraint))]
|
||||
[CanEditMultipleObjects]
|
||||
class MultiParentConstraintEditor : Editor
|
||||
{
|
||||
static class Content
|
||||
{
|
||||
public static readonly GUIContent constrainedPositionAxes = new GUIContent(
|
||||
L10n.Tr("Constrained Position Axes"),
|
||||
CommonContent.constrainedAxesPosition.tooltip
|
||||
);
|
||||
public static readonly GUIContent constrainedRotationAxes = new GUIContent(
|
||||
L10n.Tr("Constrained Rotation Axes"),
|
||||
CommonContent.constrainedAxesRotation.tooltip
|
||||
);
|
||||
}
|
||||
|
||||
SerializedProperty m_Weight;
|
||||
SerializedProperty m_ConstrainedObject;
|
||||
SerializedProperty m_ConstrainedPositionAxes;
|
||||
SerializedProperty m_ConstrainedRotationAxes;
|
||||
SerializedProperty m_SourceObjects;
|
||||
SerializedProperty m_MaintainPositionOffset;
|
||||
SerializedProperty m_MaintainRotationOffset;
|
||||
|
||||
readonly FoldoutState m_SettingsToggle = FoldoutState.ForSettings<MultiParentConstraintEditor>();
|
||||
|
||||
void OnEnable()
|
||||
{
|
||||
m_Weight = serializedObject.FindProperty("m_Weight");
|
||||
|
||||
var data = serializedObject.FindProperty("m_Data");
|
||||
m_ConstrainedObject = data.FindPropertyRelative("m_ConstrainedObject");
|
||||
m_ConstrainedPositionAxes = data.FindPropertyRelative("m_ConstrainedPositionAxes");
|
||||
m_ConstrainedRotationAxes = data.FindPropertyRelative("m_ConstrainedRotationAxes");
|
||||
m_SourceObjects = data.FindPropertyRelative("m_SourceObjects");
|
||||
m_MaintainPositionOffset = data.FindPropertyRelative("m_MaintainPositionOffset");
|
||||
m_MaintainRotationOffset = data.FindPropertyRelative("m_MaintainRotationOffset");
|
||||
}
|
||||
|
||||
public override void OnInspectorGUI()
|
||||
{
|
||||
serializedObject.Update();
|
||||
|
||||
EditorGUILayout.PropertyField(m_Weight, CommonContent.weight);
|
||||
EditorGUILayout.PropertyField(m_ConstrainedObject, CommonContent.constrainedObject);
|
||||
EditorGUILayout.PropertyField(m_SourceObjects, CommonContent.sourceObjects);
|
||||
|
||||
m_SettingsToggle.value = EditorGUILayout.BeginFoldoutHeaderGroup(m_SettingsToggle.value, CommonContent.settings);
|
||||
if (m_SettingsToggle.value)
|
||||
{
|
||||
EditorGUI.indentLevel++;
|
||||
MaintainOffsetHelper.DoDropdown(CommonContent.maintainOffset, m_MaintainPositionOffset, m_MaintainRotationOffset);
|
||||
EditorGUILayout.PropertyField(m_ConstrainedPositionAxes, Content.constrainedPositionAxes);
|
||||
EditorGUILayout.PropertyField(m_ConstrainedRotationAxes, Content.constrainedRotationAxes);
|
||||
EditorGUI.indentLevel--;
|
||||
}
|
||||
EditorGUILayout.EndFoldoutHeaderGroup();
|
||||
|
||||
serializedObject.ApplyModifiedProperties();
|
||||
}
|
||||
|
||||
[MenuItem("CONTEXT/MultiParentConstraint/Transfer motion to constraint", false, 611)]
|
||||
public static void TransferMotionToConstraint(MenuCommand command)
|
||||
{
|
||||
var constraint = command.context as MultiParentConstraint;
|
||||
BakeUtils.TransferMotionToConstraint(constraint);
|
||||
}
|
||||
|
||||
[MenuItem("CONTEXT/MultiParentConstraint/Transfer motion to skeleton", false, 612)]
|
||||
public static void TransferMotionToSkeleton(MenuCommand command)
|
||||
{
|
||||
var constraint = command.context as MultiParentConstraint;
|
||||
BakeUtils.TransferMotionToSkeleton(constraint);
|
||||
}
|
||||
|
||||
[MenuItem("CONTEXT/MultiParentConstraint/Transfer motion to constraint", true)]
|
||||
[MenuItem("CONTEXT/MultiParentConstraint/Transfer motion to skeleton", true)]
|
||||
public static bool TransferMotionValidate(MenuCommand command)
|
||||
{
|
||||
var constraint = command.context as MultiParentConstraint;
|
||||
return BakeUtils.TransferMotionValidate(constraint);
|
||||
}
|
||||
}
|
||||
|
||||
[BakeParameters(typeof(MultiParentConstraint))]
|
||||
class MultiParentConstraintParameters : BakeParameters<MultiParentConstraint>
|
||||
{
|
||||
public override bool canBakeToSkeleton => true;
|
||||
public override bool canBakeToConstraint => true;
|
||||
|
||||
public override IEnumerable<EditorCurveBinding> GetSourceCurveBindings(RigBuilder rigBuilder, MultiParentConstraint constraint)
|
||||
{
|
||||
var bindings = new List<EditorCurveBinding>();
|
||||
|
||||
for (int i = 0; i < constraint.data.sourceObjects.Count; ++i)
|
||||
{
|
||||
var sourceObject = constraint.data.sourceObjects[i];
|
||||
|
||||
EditorCurveBindingUtils.CollectPositionBindings(rigBuilder.transform, sourceObject.transform, bindings);
|
||||
EditorCurveBindingUtils.CollectRotationBindings(rigBuilder.transform, sourceObject.transform, bindings);
|
||||
EditorCurveBindingUtils.CollectPropertyBindings(rigBuilder.transform, constraint, ((IMultiParentConstraintData)constraint.data).sourceObjectsProperty + ".m_Item" + i + ".weight", bindings);
|
||||
}
|
||||
|
||||
return bindings;
|
||||
}
|
||||
|
||||
public override IEnumerable<EditorCurveBinding> GetConstrainedCurveBindings(RigBuilder rigBuilder, MultiParentConstraint constraint)
|
||||
{
|
||||
var bindings = new List<EditorCurveBinding>();
|
||||
EditorCurveBindingUtils.CollectPositionBindings(rigBuilder.transform, constraint.data.constrainedObject, bindings);
|
||||
EditorCurveBindingUtils.CollectRotationBindings(rigBuilder.transform, constraint.data.constrainedObject, bindings);
|
||||
return bindings;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 2326ba71c8dbcba4ea941bf20e7e1bbc
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,118 @@
|
||||
using UnityEngine;
|
||||
using UnityEngine.Animations.Rigging;
|
||||
using System.Collections.Generic;
|
||||
|
||||
namespace UnityEditor.Animations.Rigging
|
||||
{
|
||||
[CustomEditor(typeof(MultiPositionConstraint))]
|
||||
[CanEditMultipleObjects]
|
||||
class MultiPositionConstraintEditor : Editor
|
||||
{
|
||||
SerializedProperty m_Weight;
|
||||
SerializedProperty m_ConstrainedObject;
|
||||
SerializedProperty m_ConstrainedAxes;
|
||||
SerializedProperty m_SourceObjects;
|
||||
SerializedProperty m_MaintainOffset;
|
||||
SerializedProperty m_Offset;
|
||||
|
||||
readonly FoldoutState m_SettingsToggle = FoldoutState.ForSettings<MultiPositionConstraintEditor>();
|
||||
|
||||
void OnEnable()
|
||||
{
|
||||
m_Weight = serializedObject.FindProperty("m_Weight");
|
||||
|
||||
var data = serializedObject.FindProperty("m_Data");
|
||||
m_ConstrainedObject = data.FindPropertyRelative("m_ConstrainedObject");
|
||||
m_ConstrainedAxes = data.FindPropertyRelative("m_ConstrainedAxes");
|
||||
m_SourceObjects = data.FindPropertyRelative("m_SourceObjects");
|
||||
m_MaintainOffset = data.FindPropertyRelative("m_MaintainOffset");
|
||||
m_Offset = data.FindPropertyRelative("m_Offset");
|
||||
}
|
||||
|
||||
public override void OnInspectorGUI()
|
||||
{
|
||||
serializedObject.Update();
|
||||
|
||||
EditorGUILayout.PropertyField(m_Weight, CommonContent.weight);
|
||||
EditorGUILayout.PropertyField(m_ConstrainedObject, CommonContent.constrainedObject);
|
||||
EditorGUILayout.PropertyField(m_ConstrainedAxes, CommonContent.constrainedAxesPosition);
|
||||
EditorGUILayout.PropertyField(m_SourceObjects, CommonContent.sourceObjectsWeightedPosition);
|
||||
|
||||
m_SettingsToggle.value = EditorGUILayout.BeginFoldoutHeaderGroup(m_SettingsToggle.value, CommonContent.settings);
|
||||
if (m_SettingsToggle.value)
|
||||
{
|
||||
EditorGUI.indentLevel++;
|
||||
EditorGUILayout.PropertyField(m_MaintainOffset, CommonContent.maintainPositionOffset);
|
||||
EditorGUILayout.PropertyField(m_Offset, CommonContent.offsetPosition);
|
||||
EditorGUI.indentLevel--;
|
||||
}
|
||||
EditorGUILayout.EndFoldoutHeaderGroup();
|
||||
|
||||
serializedObject.ApplyModifiedProperties();
|
||||
}
|
||||
|
||||
[MenuItem("CONTEXT/MultiPositionConstraint/Transfer motion to constraint", false, 611)]
|
||||
public static void TransferMotionToConstraint(MenuCommand command)
|
||||
{
|
||||
var constraint = command.context as MultiPositionConstraint;
|
||||
|
||||
var axesMask = new Vector3(
|
||||
System.Convert.ToSingle(constraint.data.constrainedXAxis),
|
||||
System.Convert.ToSingle(constraint.data.constrainedYAxis),
|
||||
System.Convert.ToSingle(constraint.data.constrainedZAxis));
|
||||
|
||||
if (Vector3.Dot(axesMask, axesMask) < 3f)
|
||||
{
|
||||
Debug.LogWarning("Multi-Position constraint with one or more Constrained Axes toggled off may lose precision when transferring its motion to constraint.");
|
||||
}
|
||||
|
||||
BakeUtils.TransferMotionToConstraint(constraint);
|
||||
}
|
||||
|
||||
[MenuItem("CONTEXT/MultiPositionConstraint/Transfer motion to skeleton", false, 612)]
|
||||
public static void TransferMotionToSkeleton(MenuCommand command)
|
||||
{
|
||||
var constraint = command.context as MultiPositionConstraint;
|
||||
BakeUtils.TransferMotionToSkeleton(constraint);
|
||||
}
|
||||
|
||||
[MenuItem("CONTEXT/MultiPositionConstraint/Transfer motion to constraint", true)]
|
||||
[MenuItem("CONTEXT/MultiPositionConstraint/Transfer motion to skeleton", true)]
|
||||
public static bool TransferMotionValidate(MenuCommand command)
|
||||
{
|
||||
var constraint = command.context as MultiPositionConstraint;
|
||||
return BakeUtils.TransferMotionValidate(constraint);
|
||||
}
|
||||
}
|
||||
|
||||
[BakeParameters(typeof(MultiPositionConstraint))]
|
||||
class MultiPositionConstraintBakeParameters : BakeParameters<MultiPositionConstraint>
|
||||
{
|
||||
public override bool canBakeToSkeleton => true;
|
||||
public override bool canBakeToConstraint => true;
|
||||
|
||||
public override IEnumerable<EditorCurveBinding> GetSourceCurveBindings(RigBuilder rigBuilder, MultiPositionConstraint constraint)
|
||||
{
|
||||
var bindings = new List<EditorCurveBinding>();
|
||||
|
||||
for (int i = 0; i < constraint.data.sourceObjects.Count; ++i)
|
||||
{
|
||||
var sourceObject = constraint.data.sourceObjects[i];
|
||||
|
||||
EditorCurveBindingUtils.CollectPositionBindings(rigBuilder.transform, sourceObject.transform, bindings);
|
||||
EditorCurveBindingUtils.CollectPropertyBindings(rigBuilder.transform, constraint, ((IMultiPositionConstraintData)constraint.data).sourceObjectsProperty + ".m_Item" + i + ".weight", bindings);
|
||||
}
|
||||
|
||||
return bindings;
|
||||
}
|
||||
|
||||
public override IEnumerable<EditorCurveBinding> GetConstrainedCurveBindings(RigBuilder rigBuilder, MultiPositionConstraint constraint)
|
||||
{
|
||||
var bindings = new List<EditorCurveBinding>();
|
||||
|
||||
EditorCurveBindingUtils.CollectPositionBindings(rigBuilder.transform, constraint.data.constrainedObject, bindings);
|
||||
|
||||
return bindings;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 6ca0517db96fdfc41b4230a34d84b37c
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,132 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using UnityEngine;
|
||||
using UnityEngine.Animations.Rigging;
|
||||
|
||||
namespace UnityEditor.Animations.Rigging
|
||||
{
|
||||
[CustomEditor(typeof(MultiReferentialConstraint))]
|
||||
[CanEditMultipleObjects]
|
||||
class MultiReferentialConstraintEditor : Editor
|
||||
{
|
||||
static class Content
|
||||
{
|
||||
public static readonly GUIContent driving = EditorGUIUtility.TrTextContent(
|
||||
"Driving",
|
||||
"An object from the list of Referenced Objects, whose motion drives that of all other Referenced Objects."
|
||||
);
|
||||
public static readonly GUIContent referenceObjects = EditorGUIUtility.TrTextContent(
|
||||
"Reference Objects",
|
||||
"A list of GameObjects to be driven by the specified Driving object."
|
||||
);
|
||||
}
|
||||
|
||||
SerializedProperty m_Weight;
|
||||
SerializedProperty m_Driver;
|
||||
SerializedProperty m_SourceObjects;
|
||||
SerializedProperty m_SourceObjectsSize;
|
||||
|
||||
GUIContent[] m_DrivingLabels = Array.Empty<GUIContent>();
|
||||
int m_PreviousSourceSize;
|
||||
|
||||
void OnEnable()
|
||||
{
|
||||
m_Weight = serializedObject.FindProperty("m_Weight");
|
||||
|
||||
var data = serializedObject.FindProperty("m_Data");
|
||||
m_Driver = data.FindPropertyRelative("m_Driver");
|
||||
m_SourceObjects = data.FindPropertyRelative("m_SourceObjects");
|
||||
m_SourceObjectsSize = m_SourceObjects.FindPropertyRelative("Array.size");
|
||||
m_PreviousSourceSize = m_SourceObjectsSize.intValue;
|
||||
|
||||
UpdateDrivingLabels();
|
||||
}
|
||||
|
||||
public override void OnInspectorGUI()
|
||||
{
|
||||
serializedObject.Update();
|
||||
|
||||
EditorGUILayout.PropertyField(m_Weight, CommonContent.weight);
|
||||
|
||||
Rect rect = EditorGUILayout.GetControlRect();
|
||||
EditorGUI.BeginProperty(rect, Content.driving, m_Driver);
|
||||
EditorGUI.BeginChangeCheck();
|
||||
var newValue = EditorGUI.Popup(rect, Content.driving, m_Driver.intValue, m_DrivingLabels);
|
||||
if (EditorGUI.EndChangeCheck())
|
||||
m_Driver.intValue = newValue;
|
||||
EditorGUI.EndProperty();
|
||||
|
||||
EditorGUI.BeginChangeCheck();
|
||||
EditorGUILayout.PropertyField(m_SourceObjects, Content.referenceObjects);
|
||||
// also check if size has changed, because drag/drop on default control and Reset do not trigger change
|
||||
if (EditorGUI.EndChangeCheck() || m_PreviousSourceSize != m_SourceObjectsSize.intValue)
|
||||
{
|
||||
UpdateDrivingLabels();
|
||||
m_PreviousSourceSize = m_SourceObjectsSize.intValue;
|
||||
}
|
||||
|
||||
serializedObject.ApplyModifiedProperties();
|
||||
}
|
||||
|
||||
void UpdateDrivingLabels()
|
||||
{
|
||||
Array.Resize(ref m_DrivingLabels, m_SourceObjects.arraySize);
|
||||
for (int i = 0; i < m_DrivingLabels.Length; ++i)
|
||||
{
|
||||
var element = m_SourceObjects.GetArrayElementAtIndex(i);
|
||||
var name = element.objectReferenceValue == null ? "None" : element.objectReferenceValue.name;
|
||||
m_DrivingLabels[i] = new GUIContent($"{i} : {name}");
|
||||
}
|
||||
}
|
||||
|
||||
[MenuItem("CONTEXT/MultiReferentialConstraint/Transfer motion to constraint", false, 611)]
|
||||
public static void TransferMotionToConstraint(MenuCommand command)
|
||||
{
|
||||
var constraint = command.context as MultiReferentialConstraint;
|
||||
BakeUtils.TransferMotionToConstraint(constraint);
|
||||
}
|
||||
|
||||
[MenuItem("CONTEXT/MultiReferentialConstraint/Transfer motion to skeleton", false, 612)]
|
||||
public static void TransferMotionToSkeleton(MenuCommand command)
|
||||
{
|
||||
var constraint = command.context as MultiReferentialConstraint;
|
||||
BakeUtils.TransferMotionToSkeleton(constraint);
|
||||
}
|
||||
|
||||
[MenuItem("CONTEXT/MultiReferentialConstraint/Transfer motion to constraint", true)]
|
||||
[MenuItem("CONTEXT/MultiReferentialConstraint/Transfer motion to skeleton", true)]
|
||||
public static bool TransferMotionValidate(MenuCommand command)
|
||||
{
|
||||
var constraint = command.context as MultiReferentialConstraint;
|
||||
return BakeUtils.TransferMotionValidate(constraint);
|
||||
}
|
||||
}
|
||||
|
||||
[BakeParameters(typeof(MultiReferentialConstraint))]
|
||||
class MultiReferentialConstraintBakeParameters : BakeParameters<MultiReferentialConstraint>
|
||||
{
|
||||
public override bool canBakeToSkeleton => true;
|
||||
public override bool canBakeToConstraint => true;
|
||||
|
||||
public override IEnumerable<EditorCurveBinding> GetSourceCurveBindings(RigBuilder rigBuilder, MultiReferentialConstraint constraint)
|
||||
{
|
||||
var bindings = new List<EditorCurveBinding>();
|
||||
|
||||
var sources = constraint.data.sourceObjects;
|
||||
for (int i = 1; i < sources.Count; ++i)
|
||||
EditorCurveBindingUtils.CollectTRBindings(rigBuilder.transform, sources[i], bindings);
|
||||
|
||||
return bindings;
|
||||
}
|
||||
|
||||
public override IEnumerable<EditorCurveBinding> GetConstrainedCurveBindings(RigBuilder rigBuilder, MultiReferentialConstraint constraint)
|
||||
{
|
||||
var bindings = new List<EditorCurveBinding>();
|
||||
|
||||
var transform = constraint.data.sourceObjects[0];
|
||||
EditorCurveBindingUtils.CollectTRBindings(rigBuilder.transform, transform, bindings);
|
||||
|
||||
return bindings;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 74cfdd6a1e6ff244496d38de0c2bbee5
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,118 @@
|
||||
using UnityEngine;
|
||||
using UnityEngine.Animations.Rigging;
|
||||
using System.Collections.Generic;
|
||||
|
||||
namespace UnityEditor.Animations.Rigging
|
||||
{
|
||||
[CustomEditor(typeof(MultiRotationConstraint))]
|
||||
[CanEditMultipleObjects]
|
||||
class MultiRotationConstraintEditor : Editor
|
||||
{
|
||||
SerializedProperty m_Weight;
|
||||
SerializedProperty m_ConstrainedObject;
|
||||
SerializedProperty m_ConstrainedAxes;
|
||||
SerializedProperty m_SourceObjects;
|
||||
SerializedProperty m_MaintainOffset;
|
||||
SerializedProperty m_Offset;
|
||||
|
||||
readonly FoldoutState m_SettingsToggle = FoldoutState.ForSettings<MultiRotationConstraintEditor>();
|
||||
|
||||
void OnEnable()
|
||||
{
|
||||
m_Weight = serializedObject.FindProperty("m_Weight");
|
||||
|
||||
var data = serializedObject.FindProperty("m_Data");
|
||||
m_ConstrainedObject = data.FindPropertyRelative("m_ConstrainedObject");
|
||||
m_ConstrainedAxes = data.FindPropertyRelative("m_ConstrainedAxes");
|
||||
m_SourceObjects = data.FindPropertyRelative("m_SourceObjects");
|
||||
m_MaintainOffset = data.FindPropertyRelative("m_MaintainOffset");
|
||||
m_Offset = data.FindPropertyRelative("m_Offset");
|
||||
}
|
||||
|
||||
public override void OnInspectorGUI()
|
||||
{
|
||||
serializedObject.Update();
|
||||
|
||||
EditorGUILayout.PropertyField(m_Weight, CommonContent.weight);
|
||||
EditorGUILayout.PropertyField(m_ConstrainedObject, CommonContent.constrainedObject);
|
||||
EditorGUILayout.PropertyField(m_ConstrainedAxes, CommonContent.constrainedAxesRotation);
|
||||
EditorGUILayout.PropertyField(m_SourceObjects, CommonContent.sourceObjectsWeightedRotation);
|
||||
|
||||
m_SettingsToggle.value = EditorGUILayout.BeginFoldoutHeaderGroup(m_SettingsToggle.value, CommonContent.settings);
|
||||
if (m_SettingsToggle.value)
|
||||
{
|
||||
EditorGUI.indentLevel++;
|
||||
EditorGUILayout.PropertyField(m_MaintainOffset, CommonContent.maintainRotationOffset);
|
||||
EditorGUILayout.PropertyField(m_Offset, CommonContent.offsetRotation);
|
||||
EditorGUI.indentLevel--;
|
||||
}
|
||||
EditorGUILayout.EndFoldoutHeaderGroup();
|
||||
|
||||
serializedObject.ApplyModifiedProperties();
|
||||
}
|
||||
|
||||
[MenuItem("CONTEXT/MultiRotationConstraint/Transfer motion to constraint", false, 611)]
|
||||
public static void TransferMotionToConstraint(MenuCommand command)
|
||||
{
|
||||
var constraint = command.context as MultiRotationConstraint;
|
||||
|
||||
var axesMask = new Vector3(
|
||||
System.Convert.ToSingle(constraint.data.constrainedXAxis),
|
||||
System.Convert.ToSingle(constraint.data.constrainedYAxis),
|
||||
System.Convert.ToSingle(constraint.data.constrainedZAxis));
|
||||
|
||||
if (Vector3.Dot(axesMask, axesMask) < 3f)
|
||||
{
|
||||
Debug.LogWarning("Multi-Rotation constraint with one or more Constrained Axes toggled off may lose precision when transferring its motion to constraint.");
|
||||
}
|
||||
|
||||
BakeUtils.TransferMotionToConstraint(constraint);
|
||||
}
|
||||
|
||||
[MenuItem("CONTEXT/MultiRotationConstraint/Transfer motion to skeleton", false, 612)]
|
||||
public static void TransferMotionToSkeleton(MenuCommand command)
|
||||
{
|
||||
var constraint = command.context as MultiRotationConstraint;
|
||||
BakeUtils.TransferMotionToSkeleton(constraint);
|
||||
}
|
||||
|
||||
[MenuItem("CONTEXT/MultiRotationConstraint/Transfer motion to constraint", true)]
|
||||
[MenuItem("CONTEXT/MultiRotationConstraint/Transfer motion to skeleton", true)]
|
||||
public static bool TransferMotionValidate(MenuCommand command)
|
||||
{
|
||||
var constraint = command.context as MultiRotationConstraint;
|
||||
return BakeUtils.TransferMotionValidate(constraint);
|
||||
}
|
||||
}
|
||||
|
||||
[BakeParameters(typeof(MultiRotationConstraint))]
|
||||
class MultiRotationConstraintBakeParameters : BakeParameters<MultiRotationConstraint>
|
||||
{
|
||||
public override bool canBakeToSkeleton => true;
|
||||
public override bool canBakeToConstraint => true;
|
||||
|
||||
public override IEnumerable<EditorCurveBinding> GetSourceCurveBindings(RigBuilder rigBuilder, MultiRotationConstraint constraint)
|
||||
{
|
||||
var bindings = new List<EditorCurveBinding>();
|
||||
|
||||
for (int i = 0; i < constraint.data.sourceObjects.Count; ++i)
|
||||
{
|
||||
var sourceObject = constraint.data.sourceObjects[i];
|
||||
|
||||
EditorCurveBindingUtils.CollectRotationBindings(rigBuilder.transform, sourceObject.transform, bindings);
|
||||
EditorCurveBindingUtils.CollectPropertyBindings(rigBuilder.transform, constraint, ((IMultiRotationConstraintData)constraint.data).sourceObjectsProperty + ".m_Item" + i + ".weight", bindings);
|
||||
}
|
||||
|
||||
return bindings;
|
||||
}
|
||||
|
||||
public override IEnumerable<EditorCurveBinding> GetConstrainedCurveBindings(RigBuilder rigBuilder, MultiRotationConstraint constraint)
|
||||
{
|
||||
var bindings = new List<EditorCurveBinding>();
|
||||
|
||||
EditorCurveBindingUtils.CollectRotationBindings(rigBuilder.transform, constraint.data.constrainedObject, bindings);
|
||||
|
||||
return bindings;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 91a61b91969f07d448049f1b2c1bf3c8
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,152 @@
|
||||
using System.Collections.Generic;
|
||||
using UnityEngine;
|
||||
using UnityEngine.Animations.Rigging;
|
||||
|
||||
namespace UnityEditor.Animations.Rigging
|
||||
{
|
||||
[CustomEditor(typeof(OverrideTransform))]
|
||||
[CanEditMultipleObjects]
|
||||
class OverrideTransformEditor : Editor
|
||||
{
|
||||
static class Content
|
||||
{
|
||||
public static readonly GUIContent sourceObjects = new GUIContent(CommonContent.sourceObjects.text);
|
||||
public static readonly GUIContent overrideSource = EditorGUIUtility.TrTextContent(
|
||||
"Override Source",
|
||||
"The GameObject that influences the Constrained Object's transform. " +
|
||||
"If specified, Override Position and Override Rotation fields are ignored."
|
||||
);
|
||||
public static readonly GUIContent overridePosition = EditorGUIUtility.TrTextContent(
|
||||
"Override Position",
|
||||
"A specific position value to apply to the Constrained Object. " +
|
||||
"This value is ignored if an Override Source is specified."
|
||||
);
|
||||
public static readonly GUIContent overrideRotation = EditorGUIUtility.TrTextContent(
|
||||
"Override Rotation",
|
||||
"A specific rotation value to apply to the Constrained Object. " +
|
||||
"This value is ignored if an Override Source is specified."
|
||||
);
|
||||
public static readonly GUIContent space = EditorGUIUtility.TrTextContent(
|
||||
"Space",
|
||||
"Specifies how the Override Source's local transform values (or manual Override Position and Rotation) should be applied to Constrained Object."
|
||||
);
|
||||
public static readonly GUIContent positionWeight = EditorGUIUtility.TrTextContent(
|
||||
"Position Weight",
|
||||
"The weight of the position influence."
|
||||
);
|
||||
public static readonly GUIContent rotationWeight = EditorGUIUtility.TrTextContent(
|
||||
"Rotation Weight",
|
||||
"The weight of the rotation influence."
|
||||
);
|
||||
}
|
||||
|
||||
SerializedProperty m_Weight;
|
||||
SerializedProperty m_ConstrainedObject;
|
||||
SerializedProperty m_OverrideSource;
|
||||
SerializedProperty m_OverridePosition;
|
||||
SerializedProperty m_OverrideRotation;
|
||||
SerializedProperty m_Space;
|
||||
SerializedProperty m_PositionWeight;
|
||||
SerializedProperty m_RotationWeight;
|
||||
|
||||
readonly FoldoutState m_SourceObjectsToggle = FoldoutState.ForSourceObjects<OverrideTransformEditor>();
|
||||
readonly FoldoutState m_SettingsToggle = FoldoutState.ForSettings<OverrideTransformEditor>();
|
||||
|
||||
void OnEnable()
|
||||
{
|
||||
m_Weight = serializedObject.FindProperty("m_Weight");
|
||||
|
||||
var data = serializedObject.FindProperty("m_Data");
|
||||
m_ConstrainedObject = data.FindPropertyRelative("m_ConstrainedObject");
|
||||
m_OverrideSource = data.FindPropertyRelative("m_OverrideSource");
|
||||
m_OverridePosition = data.FindPropertyRelative("m_OverridePosition");
|
||||
m_OverrideRotation = data.FindPropertyRelative("m_OverrideRotation");
|
||||
m_Space = data.FindPropertyRelative("m_Space");
|
||||
m_PositionWeight = data.FindPropertyRelative("m_PositionWeight");
|
||||
m_RotationWeight = data.FindPropertyRelative("m_RotationWeight");
|
||||
}
|
||||
|
||||
public override void OnInspectorGUI()
|
||||
{
|
||||
serializedObject.Update();
|
||||
|
||||
EditorGUILayout.PropertyField(m_Weight, CommonContent.weight);
|
||||
EditorGUILayout.PropertyField(m_ConstrainedObject, CommonContent.constrainedObject);
|
||||
|
||||
m_SourceObjectsToggle.value = EditorGUILayout.BeginFoldoutHeaderGroup(m_SourceObjectsToggle.value, Content.sourceObjects);
|
||||
if (m_SourceObjectsToggle.value)
|
||||
{
|
||||
EditorGUI.indentLevel++;
|
||||
EditorGUILayout.PropertyField(m_OverrideSource, Content.overrideSource);
|
||||
using (new EditorGUI.DisabledScope(m_OverrideSource.objectReferenceValue != null))
|
||||
{
|
||||
EditorGUILayout.PropertyField(m_OverridePosition, Content.overridePosition);
|
||||
EditorGUILayout.PropertyField(m_OverrideRotation, Content.overrideRotation);
|
||||
}
|
||||
EditorGUI.indentLevel--;
|
||||
}
|
||||
EditorGUILayout.EndFoldoutHeaderGroup();
|
||||
|
||||
m_SettingsToggle.value = EditorGUILayout.BeginFoldoutHeaderGroup(m_SettingsToggle.value, CommonContent.settings);
|
||||
if (m_SettingsToggle.value)
|
||||
{
|
||||
EditorGUI.indentLevel++;
|
||||
EditorGUILayout.PropertyField(m_Space, Content.space);
|
||||
EditorGUILayout.PropertyField(m_PositionWeight, Content.positionWeight);
|
||||
EditorGUILayout.PropertyField(m_RotationWeight, Content.rotationWeight);
|
||||
EditorGUI.indentLevel--;
|
||||
}
|
||||
EditorGUILayout.EndFoldoutHeaderGroup();
|
||||
|
||||
serializedObject.ApplyModifiedProperties();
|
||||
}
|
||||
|
||||
[MenuItem("CONTEXT/OverrideTransform/Transfer motion to skeleton", false, 612)]
|
||||
public static void TransferMotionToSkeleton(MenuCommand command)
|
||||
{
|
||||
var constraint = command.context as OverrideTransform;
|
||||
BakeUtils.TransferMotionToSkeleton(constraint);
|
||||
}
|
||||
|
||||
[MenuItem("CONTEXT/OverrideTransform/Transfer motion to skeleton", true)]
|
||||
public static bool TransferMotionValidate(MenuCommand command)
|
||||
{
|
||||
var constraint = command.context as OverrideTransform;
|
||||
return BakeUtils.TransferMotionValidate(constraint);
|
||||
}
|
||||
}
|
||||
|
||||
[BakeParameters(typeof(OverrideTransform))]
|
||||
class OverrideTransformBakeParameters : BakeParameters<OverrideTransform>
|
||||
{
|
||||
public override bool canBakeToSkeleton => true;
|
||||
public override bool canBakeToConstraint => false;
|
||||
|
||||
public override IEnumerable<EditorCurveBinding> GetSourceCurveBindings(RigBuilder rigBuilder, OverrideTransform constraint)
|
||||
{
|
||||
var bindings = new List<EditorCurveBinding>();
|
||||
|
||||
if (constraint.data.sourceObject != null)
|
||||
{
|
||||
EditorCurveBindingUtils.CollectTRBindings(rigBuilder.transform, constraint.data.sourceObject, bindings);
|
||||
}
|
||||
else
|
||||
{
|
||||
var data = (IOverrideTransformData)constraint.data;
|
||||
EditorCurveBindingUtils.CollectVector3Bindings(rigBuilder.transform, constraint, data.positionVector3Property, bindings);
|
||||
EditorCurveBindingUtils.CollectVector3Bindings(rigBuilder.transform, constraint, data.rotationVector3Property, bindings);
|
||||
}
|
||||
|
||||
return bindings;
|
||||
}
|
||||
|
||||
public override IEnumerable<EditorCurveBinding> GetConstrainedCurveBindings(RigBuilder rigBuilder, OverrideTransform constraint)
|
||||
{
|
||||
var bindings = new List<EditorCurveBinding>();
|
||||
|
||||
EditorCurveBindingUtils.CollectTRSBindings(rigBuilder.transform, constraint.data.constrainedObject, bindings);
|
||||
|
||||
return bindings;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 16cd7f77b75e35946b191bd98757e5a2
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,143 @@
|
||||
using System.Collections.Generic;
|
||||
using UnityEngine;
|
||||
using UnityEngine.Animations.Rigging;
|
||||
|
||||
namespace UnityEditor.Animations.Rigging
|
||||
{
|
||||
[CustomEditor(typeof(TwistChainConstraint))]
|
||||
[CanEditMultipleObjects]
|
||||
class TwistChainConstraintEditor : Editor
|
||||
{
|
||||
static class Content
|
||||
{
|
||||
public static readonly GUIContent root = EditorGUIUtility.TrTextContent(
|
||||
"Root",
|
||||
"The root GameObject of the chain hierarchy."
|
||||
);
|
||||
public static readonly GUIContent tip = EditorGUIUtility.TrTextContent(
|
||||
"Tip",
|
||||
"The final GameObject of the chain hierarchy. It must be a descendant of the Root GameObject."
|
||||
);
|
||||
public static readonly GUIContent sourceObjects = new GUIContent(CommonContent.sourceObjects.text);
|
||||
public static readonly GUIContent rootTarget = EditorGUIUtility.TrTextContent(
|
||||
"Root Target",
|
||||
"The GameObject that specifies the desired target rotation for the chain's Root."
|
||||
);
|
||||
public static readonly GUIContent tipTarget = EditorGUIUtility.TrTextContent(
|
||||
"Tip Target",
|
||||
"The GameObject that specifies the desired target rotation for the chain's Tip."
|
||||
);
|
||||
public static readonly GUIContent curve = EditorGUIUtility.TrTextContent(
|
||||
"Curve",
|
||||
"A curve with a normalized domain and range, specifying how the twist rotation should be distributed down the length of the chain."
|
||||
);
|
||||
}
|
||||
|
||||
SerializedProperty m_Weight;
|
||||
SerializedProperty m_Root;
|
||||
SerializedProperty m_Tip;
|
||||
SerializedProperty m_RootTarget;
|
||||
SerializedProperty m_TipTarget;
|
||||
SerializedProperty m_Curve;
|
||||
|
||||
readonly FoldoutState m_SourceObjectsToggle = FoldoutState.ForSourceObjects<TwistChainConstraintEditor>();
|
||||
readonly FoldoutState m_SettingsToggle = FoldoutState.ForSettings<TwistChainConstraintEditor>();
|
||||
|
||||
void OnEnable()
|
||||
{
|
||||
m_Weight = serializedObject.FindProperty("m_Weight");
|
||||
|
||||
var data = serializedObject.FindProperty("m_Data");
|
||||
m_RootTarget = data.FindPropertyRelative("m_RootTarget");
|
||||
m_TipTarget = data.FindPropertyRelative("m_TipTarget");
|
||||
m_Root = data.FindPropertyRelative("m_Root");
|
||||
m_Tip = data.FindPropertyRelative("m_Tip");
|
||||
m_Curve = data.FindPropertyRelative("m_Curve");
|
||||
}
|
||||
|
||||
public override void OnInspectorGUI()
|
||||
{
|
||||
serializedObject.Update();
|
||||
|
||||
EditorGUILayout.PropertyField(m_Weight, CommonContent.weight);
|
||||
EditorGUILayout.PropertyField(m_Root, Content.root);
|
||||
EditorGUILayout.PropertyField(m_Tip, Content.tip);
|
||||
|
||||
m_SourceObjectsToggle.value = EditorGUILayout.BeginFoldoutHeaderGroup(m_SourceObjectsToggle.value, Content.sourceObjects);
|
||||
if (m_SourceObjectsToggle.value)
|
||||
{
|
||||
EditorGUI.indentLevel++;
|
||||
EditorGUILayout.PropertyField(m_RootTarget, Content.rootTarget);
|
||||
EditorGUILayout.PropertyField(m_TipTarget, Content.tipTarget);
|
||||
EditorGUI.indentLevel--;
|
||||
}
|
||||
EditorGUILayout.EndFoldoutHeaderGroup();
|
||||
|
||||
m_SettingsToggle.value = EditorGUILayout.BeginFoldoutHeaderGroup(m_SettingsToggle.value, CommonContent.settings);
|
||||
if (m_SettingsToggle.value)
|
||||
{
|
||||
EditorGUI.indentLevel++;
|
||||
EditorGUILayout.PropertyField(m_Curve, Content.curve);
|
||||
EditorGUI.indentLevel--;
|
||||
}
|
||||
EditorGUILayout.EndFoldoutHeaderGroup();
|
||||
|
||||
serializedObject.ApplyModifiedProperties();
|
||||
}
|
||||
|
||||
[MenuItem("CONTEXT/TwistChainConstraint/Transfer motion to constraint", false, 611)]
|
||||
public static void TransferMotionToConstraint(MenuCommand command)
|
||||
{
|
||||
var constraint = command.context as TwistChainConstraint;
|
||||
BakeUtils.TransferMotionToConstraint(constraint);
|
||||
}
|
||||
|
||||
[MenuItem("CONTEXT/TwistChainConstraint/Transfer motion to skeleton", false, 612)]
|
||||
public static void TransferMotionToSkeleton(MenuCommand command)
|
||||
{
|
||||
var constraint = command.context as TwistChainConstraint;
|
||||
BakeUtils.TransferMotionToSkeleton(constraint);
|
||||
}
|
||||
|
||||
[MenuItem("CONTEXT/TwistChainConstraint/Transfer motion to constraint", true)]
|
||||
[MenuItem("CONTEXT/TwistChainConstraint/Transfer motion to skeleton", true)]
|
||||
public static bool TransferMotionValidate(MenuCommand command)
|
||||
{
|
||||
var constraint = command.context as TwistChainConstraint;
|
||||
return BakeUtils.TransferMotionValidate(constraint);
|
||||
}
|
||||
}
|
||||
|
||||
[BakeParameters(typeof(TwistChainConstraint))]
|
||||
class TwistChainConstraintBakeParameters : BakeParameters<TwistChainConstraint>
|
||||
{
|
||||
public override bool canBakeToSkeleton => true;
|
||||
public override bool canBakeToConstraint => true;
|
||||
|
||||
public override IEnumerable<EditorCurveBinding> GetSourceCurveBindings(RigBuilder rigBuilder, TwistChainConstraint constraint)
|
||||
{
|
||||
var bindings = new List<EditorCurveBinding>();
|
||||
|
||||
EditorCurveBindingUtils.CollectTRBindings(rigBuilder.transform, constraint.data.rootTarget, bindings);
|
||||
EditorCurveBindingUtils.CollectTRBindings(rigBuilder.transform, constraint.data.tipTarget, bindings);
|
||||
|
||||
return bindings;
|
||||
}
|
||||
|
||||
public override IEnumerable<EditorCurveBinding> GetConstrainedCurveBindings(RigBuilder rigBuilder, TwistChainConstraint constraint)
|
||||
{
|
||||
var bindings = new List<EditorCurveBinding>();
|
||||
|
||||
// Retrieve chain in-between root and tip transforms.
|
||||
Transform[] chain = ConstraintsUtils.ExtractChain(constraint.data.root, constraint.data.tip);
|
||||
|
||||
for (int i = 0; i < chain.Length; ++i)
|
||||
{
|
||||
EditorCurveBindingUtils.CollectRotationBindings(rigBuilder.transform, chain[i], bindings);
|
||||
}
|
||||
|
||||
return bindings;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 6f51e9e105d754014895d13788b539ae
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,114 @@
|
||||
using UnityEngine;
|
||||
using UnityEngine.Animations.Rigging;
|
||||
using System.Collections.Generic;
|
||||
|
||||
namespace UnityEditor.Animations.Rigging
|
||||
{
|
||||
[CustomEditor(typeof(TwistCorrection))]
|
||||
[CanEditMultipleObjects]
|
||||
class TwistCorrectionEditor : Editor
|
||||
{
|
||||
static class Content
|
||||
{
|
||||
public static readonly GUIContent source = EditorGUIUtility.TrTextContent(
|
||||
"Source",
|
||||
"The GameObject that influences the Twist Nodes to rotate around a specific Twist Axis."
|
||||
);
|
||||
public static readonly GUIContent twistAxis = EditorGUIUtility.TrTextContent(
|
||||
"Twist Axis",
|
||||
"Specifies the axis on the Source object from which the rotation is extracted and then redistributed to the Twist Nodes."
|
||||
);
|
||||
public static readonly GUIContent twistNodes = EditorGUIUtility.TrTextContent(
|
||||
"Twist Nodes",
|
||||
"The list of GameObjects that will be influenced by the Source GameObject, and the cumulative percentage of the Source's twist rotation they should inherit. " +
|
||||
"They are generally expected to all be leaf nodes in the hierarchy (i.e., they have a common parent and no children), and to have their twist axes oriented the same as the Source object in their initial pose."
|
||||
);
|
||||
}
|
||||
|
||||
SerializedProperty m_Weight;
|
||||
SerializedProperty m_Source;
|
||||
SerializedProperty m_TwistAxis;
|
||||
SerializedProperty m_TwistNodes;
|
||||
SerializedProperty m_TwistNodesLength;
|
||||
|
||||
readonly FoldoutState m_SourceObjectsToggle = FoldoutState.ForSourceObjects<TwistChainConstraintEditor>();
|
||||
|
||||
void OnEnable()
|
||||
{
|
||||
m_Weight = serializedObject.FindProperty("m_Weight");
|
||||
var data = serializedObject.FindProperty("m_Data");
|
||||
m_Source = data.FindPropertyRelative("m_Source");
|
||||
m_TwistAxis = data.FindPropertyRelative("m_TwistAxis");
|
||||
m_TwistNodes = data.FindPropertyRelative("m_TwistNodes");
|
||||
m_TwistNodesLength = m_TwistNodes.FindPropertyRelative("m_Length");
|
||||
}
|
||||
|
||||
public override void OnInspectorGUI()
|
||||
{
|
||||
serializedObject.Update();
|
||||
|
||||
EditorGUILayout.PropertyField(m_Weight, CommonContent.weight);
|
||||
|
||||
// by default, the first WeightedTransform element a user adds has a weight of 1
|
||||
// for this constraint, the first twist node usually should not have a value of 1
|
||||
// TODO: make drag/drop auto-distribute weights
|
||||
EditorGUI.BeginChangeCheck();
|
||||
var oldLength = m_TwistNodesLength.intValue;
|
||||
EditorGUILayout.PropertyField(m_TwistNodes, Content.twistNodes);
|
||||
if (EditorGUI.EndChangeCheck() && oldLength == 0 && m_TwistNodesLength.intValue != oldLength)
|
||||
m_TwistNodes.FindPropertyRelative("m_Item0.weight").floatValue = 0f;
|
||||
|
||||
EditorGUILayout.PropertyField(m_TwistAxis, Content.twistAxis);
|
||||
|
||||
m_SourceObjectsToggle.value = EditorGUILayout.BeginFoldoutHeaderGroup(m_SourceObjectsToggle.value, Content.source);
|
||||
{
|
||||
++EditorGUI.indentLevel;
|
||||
EditorGUILayout.PropertyField(m_Source);
|
||||
--EditorGUI.indentLevel;
|
||||
}
|
||||
EditorGUILayout.EndFoldoutHeaderGroup();
|
||||
|
||||
serializedObject.ApplyModifiedProperties();
|
||||
}
|
||||
|
||||
[MenuItem("CONTEXT/TwistCorrection/Transfer motion to skeleton", false, 612)]
|
||||
public static void TransferMotionToSkeleton(MenuCommand command)
|
||||
{
|
||||
var constraint = command.context as TwistCorrection;
|
||||
BakeUtils.TransferMotionToSkeleton(constraint);
|
||||
}
|
||||
|
||||
[MenuItem("CONTEXT/TwistCorrection/Transfer motion to skeleton", true)]
|
||||
public static bool TransferMotionValidate(MenuCommand command)
|
||||
{
|
||||
var constraint = command.context as TwistCorrection;
|
||||
return BakeUtils.TransferMotionValidate(constraint);
|
||||
}
|
||||
}
|
||||
|
||||
[BakeParameters(typeof(TwistCorrection))]
|
||||
class TwistCorrectionBakeParameters : BakeParameters<TwistCorrection>
|
||||
{
|
||||
public override bool canBakeToSkeleton => true;
|
||||
public override bool canBakeToConstraint => false;
|
||||
|
||||
public override IEnumerable<EditorCurveBinding> GetSourceCurveBindings(RigBuilder rigBuilder, TwistCorrection constraint)
|
||||
{
|
||||
var bindings = new List<EditorCurveBinding>();
|
||||
|
||||
EditorCurveBindingUtils.CollectRotationBindings(rigBuilder.transform, constraint.data.sourceObject, bindings);
|
||||
|
||||
return bindings;
|
||||
}
|
||||
|
||||
public override IEnumerable<EditorCurveBinding> GetConstrainedCurveBindings(RigBuilder rigBuilder, TwistCorrection constraint)
|
||||
{
|
||||
var bindings = new List<EditorCurveBinding>();
|
||||
|
||||
foreach (var node in constraint.data.twistNodes)
|
||||
EditorCurveBindingUtils.CollectRotationBindings(rigBuilder.transform, node.transform, bindings);
|
||||
|
||||
return bindings;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: e52e5d5c12dea4e4397e6781cbeac36d
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,301 @@
|
||||
using System.Collections.Generic;
|
||||
using UnityEngine;
|
||||
using UnityEngine.Animations.Rigging;
|
||||
|
||||
namespace UnityEditor.Animations.Rigging
|
||||
{
|
||||
[CustomEditor(typeof(TwoBoneIKConstraint))]
|
||||
[CanEditMultipleObjects]
|
||||
class TwoBoneIKConstraintEditor : Editor
|
||||
{
|
||||
static class Content
|
||||
{
|
||||
public static readonly GUIContent root = EditorGUIUtility.TrTextContent(
|
||||
"Root",
|
||||
"The root GameObject of the limb hierarchy."
|
||||
);
|
||||
public static readonly GUIContent mid = EditorGUIUtility.TrTextContent(
|
||||
"Mid",
|
||||
"The middle GameObject of the limb hierarchy. It must be a child of the Root GameObject."
|
||||
);
|
||||
public static readonly GUIContent tip = EditorGUIUtility.TrTextContent(
|
||||
"Tip",
|
||||
"The final GameObject of the limb hierarchy. It must be a child of the Mid GameObject."
|
||||
);
|
||||
public static readonly GUIContent sourceObjects = new GUIContent(CommonContent.sourceObjects.text);
|
||||
public static readonly GUIContent target = EditorGUIUtility.TrTextContent(
|
||||
"Target",
|
||||
"Source GameObject that specifies the desired position of the Tip."
|
||||
);
|
||||
public static readonly GUIContent hint = EditorGUIUtility.TrTextContent(
|
||||
"Hint",
|
||||
"Optional Source GameObject, whose position is used to specify the direction the limb should be oriented when it bends."
|
||||
);
|
||||
public static readonly GUIContent targetPositionWeight = EditorGUIUtility.TrTextContent(
|
||||
"Target Position Weight",
|
||||
"The weight to apply for calculating the desired position when reaching for the Target."
|
||||
);
|
||||
public static readonly GUIContent targetRotationWeight = EditorGUIUtility.TrTextContent(
|
||||
"Target Rotation Weight",
|
||||
"The weight of the rotation applied to the Tip."
|
||||
);
|
||||
public static readonly GUIContent hintWeight = EditorGUIUtility.TrTextContent(
|
||||
"Hint Weight",
|
||||
"The amount of influence the Hint has on the configuration of the hierarchy."
|
||||
);
|
||||
}
|
||||
|
||||
SerializedProperty m_Weight;
|
||||
SerializedProperty m_Root;
|
||||
SerializedProperty m_Mid;
|
||||
SerializedProperty m_Tip;
|
||||
SerializedProperty m_Target;
|
||||
SerializedProperty m_Hint;
|
||||
SerializedProperty m_TargetPositionWeight;
|
||||
SerializedProperty m_TargetRotationWeight;
|
||||
SerializedProperty m_HintWeight;
|
||||
SerializedProperty m_MaintainTargetPositionOffset;
|
||||
SerializedProperty m_MaintainTargetRotationOffset;
|
||||
|
||||
readonly FoldoutState m_SourceObjectsToggle = FoldoutState.ForSourceObjects<TwoBoneIKConstraintEditor>();
|
||||
readonly FoldoutState m_SettingsToggle = FoldoutState.ForSettings<TwoBoneIKConstraintEditor>();
|
||||
|
||||
void OnEnable()
|
||||
{
|
||||
m_Weight = serializedObject.FindProperty("m_Weight");
|
||||
|
||||
var data = serializedObject.FindProperty("m_Data");
|
||||
m_Root = data.FindPropertyRelative("m_Root");
|
||||
m_Mid = data.FindPropertyRelative("m_Mid");
|
||||
m_Tip = data.FindPropertyRelative("m_Tip");
|
||||
m_Target = data.FindPropertyRelative("m_Target");
|
||||
m_Hint = data.FindPropertyRelative("m_Hint");
|
||||
m_TargetPositionWeight = data.FindPropertyRelative("m_TargetPositionWeight");
|
||||
m_TargetRotationWeight = data.FindPropertyRelative("m_TargetRotationWeight");
|
||||
m_HintWeight = data.FindPropertyRelative("m_HintWeight");
|
||||
m_MaintainTargetPositionOffset = data.FindPropertyRelative("m_MaintainTargetPositionOffset");
|
||||
m_MaintainTargetRotationOffset = data.FindPropertyRelative("m_MaintainTargetRotationOffset");
|
||||
}
|
||||
|
||||
public override void OnInspectorGUI()
|
||||
{
|
||||
serializedObject.Update();
|
||||
|
||||
EditorGUILayout.PropertyField(m_Weight, CommonContent.weight);
|
||||
EditorGUILayout.PropertyField(m_Root, Content.root);
|
||||
EditorGUILayout.PropertyField(m_Mid, Content.mid);
|
||||
EditorGUILayout.PropertyField(m_Tip, Content.tip);
|
||||
|
||||
m_SourceObjectsToggle.value = EditorGUILayout.BeginFoldoutHeaderGroup(m_SourceObjectsToggle.value, Content.sourceObjects);
|
||||
if (m_SourceObjectsToggle.value)
|
||||
{
|
||||
EditorGUI.indentLevel++;
|
||||
EditorGUILayout.PropertyField(m_Target, Content.target);
|
||||
EditorGUILayout.PropertyField(m_Hint, Content.hint);
|
||||
EditorGUI.indentLevel--;
|
||||
}
|
||||
EditorGUILayout.EndFoldoutHeaderGroup();
|
||||
|
||||
m_SettingsToggle.value = EditorGUILayout.BeginFoldoutHeaderGroup(m_SettingsToggle.value, CommonContent.settings);
|
||||
if (m_SettingsToggle.value)
|
||||
{
|
||||
EditorGUI.indentLevel++;
|
||||
MaintainOffsetHelper.DoDropdown(CommonContent.maintainIKTargetOffset, m_MaintainTargetPositionOffset, m_MaintainTargetRotationOffset);
|
||||
EditorGUILayout.PropertyField(m_TargetPositionWeight, Content.targetPositionWeight);
|
||||
EditorGUILayout.PropertyField(m_TargetRotationWeight, Content.targetRotationWeight);
|
||||
EditorGUILayout.PropertyField(m_HintWeight, Content.hintWeight);
|
||||
EditorGUI.indentLevel--;
|
||||
}
|
||||
EditorGUILayout.EndFoldoutHeaderGroup();
|
||||
|
||||
serializedObject.ApplyModifiedProperties();
|
||||
}
|
||||
|
||||
[MenuItem("CONTEXT/TwoBoneIKConstraint/Transfer motion to constraint", false, 611)]
|
||||
public static void TransferMotionToConstraint(MenuCommand command)
|
||||
{
|
||||
var constraint = command.context as TwoBoneIKConstraint;
|
||||
BakeUtils.TransferMotionToConstraint(constraint);
|
||||
}
|
||||
|
||||
[MenuItem("CONTEXT/TwoBoneIKConstraint/Transfer motion to skeleton", false, 612)]
|
||||
public static void TransferMotionToSkeleton(MenuCommand command)
|
||||
{
|
||||
var constraint = command.context as TwoBoneIKConstraint;
|
||||
BakeUtils.TransferMotionToSkeleton(constraint);
|
||||
}
|
||||
|
||||
[MenuItem("CONTEXT/TwoBoneIKConstraint/Transfer motion to constraint", true)]
|
||||
[MenuItem("CONTEXT/TwoBoneIKConstraint/Transfer motion to skeleton", true)]
|
||||
public static bool TransferMotionValidate(MenuCommand command)
|
||||
{
|
||||
var constraint = command.context as TwoBoneIKConstraint;
|
||||
return BakeUtils.TransferMotionValidate(constraint);
|
||||
}
|
||||
|
||||
[MenuItem("CONTEXT/TwoBoneIKConstraint/Auto Setup from Tip Transform", false, 631)]
|
||||
public static void TwoBoneIKAutoSetup(MenuCommand command)
|
||||
{
|
||||
var constraint = command.context as TwoBoneIKConstraint;
|
||||
var tip = constraint.data.tip;
|
||||
var animator = constraint.GetComponentInParent<Animator>()?.transform;
|
||||
var dirty = false;
|
||||
|
||||
if (!tip)
|
||||
{
|
||||
var selection = Selection.transforms;
|
||||
var constraintInSelection = false;
|
||||
|
||||
// Take transform from selection that is part of the animator hierarchy & not the constraint transform.
|
||||
if (animator)
|
||||
{
|
||||
for (int i = 0; i < selection.Length; i++)
|
||||
{
|
||||
if (selection[i].IsChildOf(animator))
|
||||
{
|
||||
if (selection[i] != constraint.transform)
|
||||
{
|
||||
tip = selection[i];
|
||||
break;
|
||||
}
|
||||
else
|
||||
{
|
||||
constraintInSelection = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// If the constraint itself was selected and we haven't found anything use that.
|
||||
if (!tip && constraintInSelection)
|
||||
tip = constraint.transform;
|
||||
|
||||
// If there is still no tip return.
|
||||
if (!tip)
|
||||
{
|
||||
Debug.LogWarning("Please provide a tip before running auto setup!");
|
||||
return;
|
||||
}
|
||||
else
|
||||
{
|
||||
Undo.RecordObject(constraint, "Setup tip bone from user selection");
|
||||
constraint.data.tip = tip;
|
||||
dirty = true;
|
||||
}
|
||||
}
|
||||
|
||||
if (!constraint.data.mid)
|
||||
{
|
||||
Undo.RecordObject(constraint, "Setup mid bone for TwoBoneIK");
|
||||
constraint.data.mid = tip.parent;
|
||||
dirty = true;
|
||||
}
|
||||
|
||||
if (!constraint.data.root)
|
||||
{
|
||||
Undo.RecordObject(constraint, "Setup root bone for TwoBoneIK");
|
||||
constraint.data.root = tip.parent.parent;
|
||||
dirty = true;
|
||||
}
|
||||
|
||||
if (!constraint.data.target)
|
||||
{
|
||||
var target = constraint.transform.Find(constraint.gameObject.name + "_target");
|
||||
if (target == null)
|
||||
{
|
||||
var t = new GameObject();
|
||||
Undo.RegisterCreatedObjectUndo(t, "Created target");
|
||||
t.name = constraint.gameObject.name + "_target";
|
||||
t.transform.localScale = .1f * t.transform.localScale;
|
||||
Undo.SetTransformParent(t.transform, constraint.transform, "Set new parent");
|
||||
target = t.transform;
|
||||
}
|
||||
constraint.data.target = target;
|
||||
dirty = true;
|
||||
}
|
||||
|
||||
if (!constraint.data.hint)
|
||||
{
|
||||
var hint = constraint.transform.Find(constraint.gameObject.name + "_hint");
|
||||
if (hint == null)
|
||||
{
|
||||
var t = new GameObject();
|
||||
Undo.RegisterCreatedObjectUndo(t, "Created hint");
|
||||
t.name = constraint.gameObject.name + "_hint";
|
||||
t.transform.localScale = .1f * t.transform.localScale;
|
||||
Undo.SetTransformParent(t.transform, constraint.transform, "Set new parent");
|
||||
hint = t.transform;
|
||||
}
|
||||
constraint.data.hint = hint;
|
||||
dirty = true;
|
||||
}
|
||||
|
||||
Vector3 rootPosition = constraint.data.root.position;
|
||||
Vector3 midPosition = constraint.data.mid.position;
|
||||
Vector3 tipPosition = constraint.data.tip.position;
|
||||
Quaternion tipRotation = constraint.data.tip.rotation;
|
||||
Vector3 targetPosition = constraint.data.target.position;
|
||||
Quaternion targetRotation = constraint.data.target.rotation;
|
||||
Vector3 hintPosition = constraint.data.hint.position;
|
||||
float posWeight = constraint.data.targetPositionWeight;
|
||||
float rotWeight = constraint.data.targetRotationWeight;
|
||||
float hintWeight = constraint.data.hintWeight;
|
||||
AffineTransform targetOffset = new AffineTransform(Vector3.zero, Quaternion.identity);
|
||||
|
||||
AnimationRuntimeUtils.InverseSolveTwoBoneIK(rootPosition, midPosition, tipPosition, tipRotation,
|
||||
ref targetPosition, ref targetRotation, ref hintPosition, true, posWeight, rotWeight, hintWeight, targetOffset);
|
||||
|
||||
constraint.data.target.position = targetPosition;
|
||||
constraint.data.target.rotation = targetRotation;
|
||||
constraint.data.hint.position = hintPosition;
|
||||
|
||||
Rig rig = constraint.GetComponentInParent<Rig>();
|
||||
if (rig != null)
|
||||
{
|
||||
RigEffectorData.Style targetStyle = RigEffector.defaultStyle;
|
||||
targetStyle.shape = EditorHelper.LoadShape("BoxEffector.asset");
|
||||
rig.AddEffector(constraint.data.target, targetStyle);
|
||||
RigEffectorData.Style hintStyle = RigEffector.defaultStyle;
|
||||
hintStyle.shape = EditorHelper.LoadShape("BallEffector.asset");
|
||||
rig.AddEffector(constraint.data.hint, hintStyle);
|
||||
}
|
||||
|
||||
if (dirty && PrefabUtility.IsPartOfPrefabInstance(constraint))
|
||||
EditorUtility.SetDirty(constraint);
|
||||
}
|
||||
}
|
||||
|
||||
[BakeParameters(typeof(TwoBoneIKConstraint))]
|
||||
class TwoBoneIKConstraintBakeParameters : BakeParameters<TwoBoneIKConstraint>
|
||||
{
|
||||
public override bool canBakeToSkeleton => true;
|
||||
public override bool canBakeToConstraint => true;
|
||||
|
||||
public override IEnumerable<EditorCurveBinding> GetSourceCurveBindings(RigBuilder rigBuilder, TwoBoneIKConstraint constraint)
|
||||
{
|
||||
var bindings = new List<EditorCurveBinding>();
|
||||
|
||||
EditorCurveBindingUtils.CollectTRBindings(rigBuilder.transform, constraint.data.target, bindings);
|
||||
|
||||
if (constraint.data.hint != null)
|
||||
EditorCurveBindingUtils.CollectPositionBindings(rigBuilder.transform, constraint.data.hint, bindings);
|
||||
|
||||
return bindings;
|
||||
}
|
||||
|
||||
public override IEnumerable<EditorCurveBinding> GetConstrainedCurveBindings(RigBuilder rigBuilder, TwoBoneIKConstraint constraint)
|
||||
{
|
||||
var bindings = new List<EditorCurveBinding>();
|
||||
|
||||
var root = constraint.data.root;
|
||||
var mid = constraint.data.mid;
|
||||
var tip = constraint.data.tip;
|
||||
|
||||
EditorCurveBindingUtils.CollectRotationBindings(rigBuilder.transform, root, bindings);
|
||||
EditorCurveBindingUtils.CollectRotationBindings(rigBuilder.transform, mid, bindings);
|
||||
EditorCurveBindingUtils.CollectRotationBindings(rigBuilder.transform, tip, bindings);
|
||||
|
||||
return bindings;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: d47d5b10876eed042af2bccb184f9a5b
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,61 @@
|
||||
using UnityEngine;
|
||||
using UnityEngine.Animations.Rigging;
|
||||
using UnityEditorInternal;
|
||||
|
||||
namespace UnityEditor.Animations.Rigging
|
||||
{
|
||||
[CustomEditor(typeof(RigBuilder))]
|
||||
class RigBuilderEditor : Editor
|
||||
{
|
||||
static readonly GUIContent k_RigLabel = new GUIContent("Rig Layers");
|
||||
|
||||
SerializedProperty m_Rigs;
|
||||
ReorderableList m_ReorderableList;
|
||||
|
||||
void OnEnable()
|
||||
{
|
||||
m_Rigs = serializedObject.FindProperty("m_RigLayers");
|
||||
m_ReorderableList = ReorderableListHelper.Create(serializedObject, m_Rigs, true, true);
|
||||
if (m_ReorderableList.count == 0)
|
||||
((RigBuilder)serializedObject.targetObject).layers.Add(new RigLayer(null));
|
||||
|
||||
m_ReorderableList.drawHeaderCallback = (Rect rect) => EditorGUI.LabelField(rect, k_RigLabel);
|
||||
|
||||
m_ReorderableList.onAddCallback = (ReorderableList list) =>
|
||||
{
|
||||
((RigBuilder)(serializedObject.targetObject)).layers.Add(new RigLayer(null, true));
|
||||
};
|
||||
}
|
||||
|
||||
public override void OnInspectorGUI()
|
||||
{
|
||||
serializedObject.Update();
|
||||
EditorGUILayout.Separator();
|
||||
m_ReorderableList.DoLayoutList();
|
||||
serializedObject.ApplyModifiedProperties();
|
||||
}
|
||||
|
||||
[MenuItem("CONTEXT/RigBuilder/Transfer motion to constraint", false, 611)]
|
||||
public static void TransferMotionToConstraint(MenuCommand command)
|
||||
{
|
||||
var rigBuilder = command.context as RigBuilder;
|
||||
BakeUtils.TransferMotionToConstraint(rigBuilder);
|
||||
}
|
||||
|
||||
[MenuItem("CONTEXT/RigBuilder/Transfer motion to skeleton", false, 612)]
|
||||
public static void TransferMotionToSkeleton(MenuCommand command)
|
||||
{
|
||||
var rigBuilder = command.context as RigBuilder;
|
||||
BakeUtils.TransferMotionToSkeleton(rigBuilder);
|
||||
}
|
||||
|
||||
[MenuItem("CONTEXT/RigBuilder/Transfer motion to constraint", true)]
|
||||
[MenuItem("CONTEXT/RigBuilder/Transfer motion to skeleton", true)]
|
||||
public static bool TransferMotionValidate(MenuCommand command)
|
||||
{
|
||||
var rigBuilder = command.context as RigBuilder;
|
||||
return BakeUtils.TransferMotionValidate(rigBuilder);
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 5f920510daf5fba46b137a815f4e9a1b
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,76 @@
|
||||
using UnityEngine.Animations.Rigging;
|
||||
|
||||
namespace UnityEditor.Animations.Rigging
|
||||
{
|
||||
[CustomEditor(typeof(Rig))]
|
||||
[CanEditMultipleObjects]
|
||||
class RigEditor : Editor
|
||||
{
|
||||
SerializedProperty m_Weight;
|
||||
|
||||
void OnEnable()
|
||||
{
|
||||
m_Weight = serializedObject.FindProperty("m_Weight");
|
||||
}
|
||||
|
||||
public override void OnInspectorGUI()
|
||||
{
|
||||
bool isEditingMultipleObjects = targets.Length > 1;
|
||||
|
||||
serializedObject.Update();
|
||||
EditorGUILayout.Separator();
|
||||
EditorGUILayout.PropertyField(m_Weight);
|
||||
serializedObject.ApplyModifiedProperties();
|
||||
|
||||
if (!isEditingMultipleObjects)
|
||||
{
|
||||
var rig = target as Rig;
|
||||
var rigBuilder = rig.GetComponentInParent<RigBuilder>();
|
||||
|
||||
if (rigBuilder == null)
|
||||
{
|
||||
EditorGUILayout.HelpBox("Rig component is not child of a GameObject with a RigBuilder component.", MessageType.Warning, true);
|
||||
}
|
||||
else
|
||||
{
|
||||
var inRigBuilder = false;
|
||||
var layers = rigBuilder.layers;
|
||||
|
||||
for (int i = 0; i < layers.Count; ++i)
|
||||
{
|
||||
if (layers[i].rig == rig && layers[i].active)
|
||||
{
|
||||
inRigBuilder = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (!inRigBuilder)
|
||||
EditorGUILayout.HelpBox("Rig component is not referenced or not active in the RigBuilder component.", MessageType.Warning, true);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
[MenuItem("CONTEXT/Rig/Transfer motion to constraint", false, 611)]
|
||||
public static void TransferMotionToConstraint(MenuCommand command)
|
||||
{
|
||||
var rig = command.context as Rig;
|
||||
BakeUtils.TransferMotionToConstraint(rig);
|
||||
}
|
||||
|
||||
[MenuItem("CONTEXT/Rig/Transfer motion to skeleton", false, 612)]
|
||||
public static void TransferMotionToSkeleton(MenuCommand command)
|
||||
{
|
||||
var rig = command.context as Rig;
|
||||
BakeUtils.TransferMotionToSkeleton(rig);
|
||||
}
|
||||
|
||||
[MenuItem("CONTEXT/Rig/Transfer motion to constraint", true)]
|
||||
[MenuItem("CONTEXT/Rig/Transfer motion to skeleton", true)]
|
||||
public static bool TransferMotionValidate(MenuCommand command)
|
||||
{
|
||||
var rig = command.context as Rig;
|
||||
return BakeUtils.TransferMotionValidate(rig);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 6856dd80c42d3244b9d9eb1844f8715f
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,40 @@
|
||||
using UnityEngine;
|
||||
using UnityEngine.Animations.Rigging;
|
||||
|
||||
namespace UnityEditor.Animations.Rigging
|
||||
{
|
||||
[CustomPropertyDrawer(typeof(RigLayer))]
|
||||
class RigLayerDrawer : PropertyDrawer
|
||||
{
|
||||
const int k_Padding = 6;
|
||||
const int k_TogglePadding = 30;
|
||||
|
||||
public override float GetPropertyHeight(SerializedProperty property, GUIContent label)
|
||||
{
|
||||
return EditorGUIUtility.singleLineHeight;
|
||||
}
|
||||
|
||||
public override void OnGUI(Rect rect, SerializedProperty property, GUIContent label)
|
||||
{
|
||||
EditorGUI.BeginProperty(rect, label, property);
|
||||
|
||||
var w = rect.width - k_TogglePadding;
|
||||
var weightRect = new Rect(rect.x + w + k_Padding, rect.y, rect.width - w - k_Padding, rect.height);
|
||||
rect.width = w;
|
||||
|
||||
EditorGUI.BeginChangeCheck();
|
||||
EditorGUI.PropertyField(rect, property.FindPropertyRelative("m_Rig"), label);
|
||||
|
||||
var indentLvl = EditorGUI.indentLevel;
|
||||
EditorGUI.indentLevel = 0;
|
||||
EditorGUI.PropertyField(weightRect, property.FindPropertyRelative("m_Active"), GUIContent.none);
|
||||
EditorGUI.indentLevel = indentLvl;
|
||||
|
||||
if (EditorGUI.EndChangeCheck())
|
||||
property.serializedObject.ApplyModifiedProperties();
|
||||
|
||||
EditorGUI.EndProperty();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: cfddd68cbf078454ab5dfd53ed554127
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,12 @@
|
||||
using UnityEngine.Animations.Rigging;
|
||||
|
||||
namespace UnityEditor.Animations.Rigging
|
||||
{
|
||||
[CustomEditor(typeof(RigTransform))]
|
||||
class RigTransformEditor : Editor
|
||||
{
|
||||
public override void OnInspectorGUI()
|
||||
{
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: ab480ae8b7295e54c9c72a011401317e
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,249 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Reflection;
|
||||
using UnityEditorInternal;
|
||||
using UnityEngine;
|
||||
using UnityEngine.Animations.Rigging;
|
||||
using UnityObject = UnityEngine.Object;
|
||||
|
||||
namespace UnityEditor.Animations.Rigging
|
||||
{
|
||||
[CustomPropertyDrawer(typeof(WeightedTransformArray))]
|
||||
sealed class WeightedTransformArrayDrawer : PropertyDrawer
|
||||
{
|
||||
const string k_LengthPath = "m_Length";
|
||||
const string k_ItemTransformPath = nameof(WeightedTransform.transform);
|
||||
const string k_ItemWeightPath = nameof(WeightedTransform.weight);
|
||||
static readonly string[] k_ItemPropertyPaths =
|
||||
Enumerable.Range(0, WeightedTransformArray.k_MaxLength).Select(i => $"m_Item{i}").ToArray();
|
||||
|
||||
// one reorderable list per unique property path
|
||||
readonly Dictionary<string, (ReorderableList listControl, SerializedProperty lengthProperty)> m_GUIState =
|
||||
new Dictionary<string, (ReorderableList listControl, SerializedProperty lengthProperty)>();
|
||||
|
||||
// function to get WeightedTransform from item property
|
||||
static WeightedTransform GetValueSingle(SerializedProperty item) => new WeightedTransform
|
||||
{
|
||||
transform = item.FindPropertyRelative(k_ItemTransformPath).objectReferenceValue as Transform,
|
||||
weight = item.FindPropertyRelative(k_ItemWeightPath).floatValue
|
||||
};
|
||||
|
||||
// function to modify a list of items per target
|
||||
static void ModifyItemsSingle(SerializedProperty parentProperty, Action<List<WeightedTransform>> modifyList)
|
||||
{
|
||||
foreach (var target in parentProperty.serializedObject.targetObjects)
|
||||
{
|
||||
using (var so = new SerializedObject(target))
|
||||
{
|
||||
var sp = so.FindProperty(parentProperty.propertyPath);
|
||||
var length = sp.FindPropertyRelative(k_LengthPath);
|
||||
|
||||
// create a live list of items
|
||||
var items =
|
||||
Enumerable.Range(0, length.intValue)
|
||||
.Select(i => GetValueSingle(sp.FindPropertyRelative(k_ItemPropertyPaths[i])))
|
||||
.ToList();
|
||||
|
||||
// modify the list
|
||||
modifyList(items);
|
||||
|
||||
// write the results back to the serialized data stream
|
||||
for (var i = 0; i < items.Count; ++i)
|
||||
{
|
||||
var item = sp.FindPropertyRelative(k_ItemPropertyPaths[i]);
|
||||
item.FindPropertyRelative(k_ItemTransformPath).objectReferenceValue = items[i].transform;
|
||||
item.FindPropertyRelative(k_ItemWeightPath).floatValue = items[i].weight;
|
||||
}
|
||||
// clear other items
|
||||
for (var i = items.Count; i < WeightedTransformArray.k_MaxLength; ++i)
|
||||
{
|
||||
var item = sp.FindPropertyRelative(k_ItemPropertyPaths[i]);
|
||||
item.FindPropertyRelative(k_ItemTransformPath).objectReferenceValue = default;
|
||||
item.FindPropertyRelative(k_ItemWeightPath).floatValue = default;
|
||||
}
|
||||
|
||||
// synchronize length property
|
||||
length.intValue = items.Count;
|
||||
|
||||
// write back results
|
||||
so.ApplyModifiedProperties();
|
||||
}
|
||||
}
|
||||
// update parent property's serialized data stream to get new (shared) values for all targets
|
||||
parentProperty.serializedObject.Update();
|
||||
}
|
||||
|
||||
(ReorderableList listControl, SerializedProperty lengthProperty) GetGUIState(SerializedProperty property, GUIContent label)
|
||||
{
|
||||
var lengthProperty = property.FindPropertyRelative(k_LengthPath);
|
||||
|
||||
// create a new reorderable list if one does not exist
|
||||
if (!m_GUIState.TryGetValue(property.propertyPath, out var guiState))
|
||||
{
|
||||
// bind the control to a proxy list
|
||||
var proxy = Enumerable.Range(0, lengthProperty.intValue)
|
||||
.ToList();
|
||||
var reorderableList = new ReorderableList(proxy, typeof(int));
|
||||
|
||||
reorderableList.headerHeight = Styles.minHeaderHeight;
|
||||
|
||||
// default array control only allocates single line height, but that leaves no spacing between object fields
|
||||
reorderableList.elementHeight =
|
||||
EditorGUIUtility.singleLineHeight + EditorGUIUtility.standardVerticalSpacing;
|
||||
|
||||
var attr = fieldInfo.GetCustomAttribute<WeightRangeAttribute>();
|
||||
var legacyAttr = fieldInfo.GetCustomAttribute<RangeAttribute>();
|
||||
var min = attr?.min ?? legacyAttr?.min ?? float.NaN;
|
||||
var max = attr?.max ?? legacyAttr?.max ?? float.NaN;
|
||||
var spacing = EditorGUIUtility.standardVerticalSpacing / 2f;
|
||||
reorderableList.drawElementCallback += (rect, index, active, focused) =>
|
||||
{
|
||||
rect = new Rect(rect) { height = EditorGUIUtility.singleLineHeight, y = rect.y + spacing };
|
||||
WeightedTransformDrawer.DoGUI(rect, property.FindPropertyRelative(k_ItemPropertyPaths[index]), min, max);
|
||||
};
|
||||
|
||||
reorderableList.onCanAddCallback += list =>
|
||||
!Application.isPlaying
|
||||
&& !AnimationMode.InAnimationMode()
|
||||
&& lengthProperty.intValue < WeightedTransformArray.k_MaxLength;
|
||||
|
||||
reorderableList.onCanRemoveCallback += list =>
|
||||
!Application.isPlaying
|
||||
&& !AnimationMode.InAnimationMode()
|
||||
&& lengthProperty.intValue > 0;
|
||||
|
||||
reorderableList.onAddCallback += list =>
|
||||
{
|
||||
ModifyItemsSingle(property, items =>
|
||||
{
|
||||
int insertIndex = Math.Max(0, reorderableList.index >= 0 ? reorderableList.index : items.Count - 1);
|
||||
if (items.Count < WeightedTransformArray.k_MaxLength)
|
||||
items.Insert(insertIndex, insertIndex < items.Count ? items[insertIndex] : WeightedTransform.Default(1f));
|
||||
});
|
||||
proxy.Add(proxy.Count);
|
||||
};
|
||||
|
||||
reorderableList.onRemoveCallback += list =>
|
||||
{
|
||||
ModifyItemsSingle(property, items =>
|
||||
{
|
||||
int removeIndex = Math.Max(0, reorderableList.index >= 0 ? reorderableList.index : items.Count - 1);
|
||||
if (removeIndex >= 0)
|
||||
items.RemoveAt(removeIndex);
|
||||
});
|
||||
proxy.RemoveAt(proxy.Count - 1);
|
||||
};
|
||||
|
||||
reorderableList.onReorderCallbackWithDetails += (list, srcIndex, dstIndex) =>
|
||||
ModifyItemsSingle(property, items =>
|
||||
{
|
||||
var moved = items[srcIndex];
|
||||
items.RemoveAt(srcIndex);
|
||||
items.Insert(dstIndex, moved);
|
||||
});
|
||||
|
||||
guiState = m_GUIState[property.propertyPath] = (reorderableList, lengthProperty.Copy());
|
||||
}
|
||||
|
||||
// synchronize proxy list to serialized length
|
||||
var proxyList = guiState.listControl.list;
|
||||
while (proxyList.Count < lengthProperty.intValue)
|
||||
proxyList.Add(proxyList.Count);
|
||||
while (proxyList.Count > lengthProperty.intValue)
|
||||
proxyList.RemoveAt(proxyList.Count - 1);
|
||||
|
||||
return guiState;
|
||||
}
|
||||
|
||||
static class Styles
|
||||
{
|
||||
// cf. ReorderableList.Defaults.minHeaderHeight;
|
||||
public static float minHeaderHeight = 2f;
|
||||
// cf. ReorderableListWrapper.cs
|
||||
public const float headerPadding = 3f;
|
||||
public const float arraySizeWidth = 50f; // 48 in ReorderableListWrapper, but EditorGUI.Slider() field is 50
|
||||
public const float defaultFoldoutHeaderHeight = 18f;
|
||||
public static readonly GUIContent sizeLabel = EditorGUIUtility.TrTextContent("", "Length");
|
||||
}
|
||||
|
||||
public override float GetPropertyHeight(SerializedProperty property, GUIContent label) =>
|
||||
Styles.defaultFoldoutHeaderHeight
|
||||
+ (property.isExpanded ? Styles.headerPadding + GetGUIState(property, label).listControl.GetHeight() : 0f);
|
||||
|
||||
public override void OnGUI(Rect position, SerializedProperty property, GUIContent label)
|
||||
{
|
||||
var guiState = GetGUIState(property, label);
|
||||
|
||||
Rect headerRect = new Rect(position) { height = EditorGUIUtility.singleLineHeight };
|
||||
Rect sizeRect = new Rect(headerRect) { xMin = headerRect.xMax - Styles.arraySizeWidth };
|
||||
|
||||
EventType prevType = Event.current.type;
|
||||
if (Event.current.type == EventType.MouseUp && sizeRect.Contains(Event.current.mousePosition))
|
||||
{
|
||||
Event.current.type = EventType.Used;
|
||||
}
|
||||
|
||||
property.isExpanded = EditorGUI.BeginFoldoutHeaderGroup(headerRect, property.isExpanded, label);
|
||||
EditorGUI.EndFoldoutHeaderGroup();
|
||||
|
||||
if (Event.current.type == EventType.Used && sizeRect.Contains(Event.current.mousePosition)) Event.current.type = prevType;
|
||||
|
||||
EditorGUI.BeginChangeCheck();
|
||||
EditorGUI.DelayedIntField(sizeRect, guiState.lengthProperty, Styles.sizeLabel);
|
||||
if (EditorGUI.EndChangeCheck())
|
||||
guiState.lengthProperty.intValue = Mathf.Clamp(guiState.lengthProperty.intValue, 0, WeightedTransformArray.k_MaxLength);
|
||||
EditorGUI.LabelField(sizeRect, Styles.sizeLabel);
|
||||
|
||||
if (headerRect.Contains(Event.current.mousePosition))
|
||||
{
|
||||
if (Event.current.type == EventType.DragUpdated || Event.current.type == EventType.DragPerform)
|
||||
{
|
||||
OnDropObjects(property, DragAndDrop.objectReferences, guiState.listControl);
|
||||
DragAndDrop.AcceptDrag();
|
||||
Event.current.Use();
|
||||
}
|
||||
}
|
||||
|
||||
if (Event.current.type == EventType.DragExited)
|
||||
{
|
||||
DragAndDrop.visualMode = DragAndDropVisualMode.None;
|
||||
Event.current.Use();
|
||||
}
|
||||
|
||||
if (property.isExpanded)
|
||||
guiState.listControl.DoList(new Rect(position) { yMin = headerRect.yMax + Styles.headerPadding });
|
||||
}
|
||||
|
||||
static void OnDropObjects(SerializedProperty property, UnityObject[] objectReferences, ReorderableList listControl)
|
||||
{
|
||||
foreach (var o in objectReferences)
|
||||
{
|
||||
var go = o as GameObject;
|
||||
var c = o as Component;
|
||||
|
||||
if (go == null && c == null)
|
||||
continue;
|
||||
|
||||
if (listControl.list.Count >= WeightedTransformArray.k_MaxLength)
|
||||
{
|
||||
DragAndDrop.visualMode = DragAndDropVisualMode.Rejected;
|
||||
continue;
|
||||
}
|
||||
|
||||
DragAndDrop.visualMode = DragAndDropVisualMode.Generic;
|
||||
|
||||
var t = c == null ? go.transform : c.transform;
|
||||
if (Event.current.type == EventType.DragPerform)
|
||||
{
|
||||
ModifyItemsSingle(property, items =>
|
||||
{
|
||||
var weight = items.Count == 0 ? 1f : items[items.Count - 1].weight;
|
||||
items.Add(new WeightedTransform(t, weight));
|
||||
});
|
||||
listControl.list.Add(listControl.list.Count);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,3 @@
|
||||
fileFormatVersion: 2
|
||||
guid: ee7818cdc02e4548adb5ae6bc5901523
|
||||
timeCreated: 1607593832
|
||||
@@ -0,0 +1,59 @@
|
||||
using System.Reflection;
|
||||
using UnityEngine;
|
||||
using UnityEngine.Animations.Rigging;
|
||||
|
||||
namespace UnityEditor.Animations.Rigging
|
||||
{
|
||||
[CustomPropertyDrawer(typeof(WeightedTransform))]
|
||||
class WeightedTransformDrawer : PropertyDrawer
|
||||
{
|
||||
public override float GetPropertyHeight(SerializedProperty property, GUIContent label) =>
|
||||
EditorGUIUtility.singleLineHeight;
|
||||
|
||||
(WeightRangeAttribute attr, RangeAttribute legacyAttr)? m_RangeAttributes;
|
||||
|
||||
public override void OnGUI(Rect rect, SerializedProperty property, GUIContent label)
|
||||
{
|
||||
var (attr, legacyAttr) = m_RangeAttributes ??= (
|
||||
fieldInfo.GetCustomAttribute<WeightRangeAttribute>(),
|
||||
fieldInfo.GetCustomAttribute<RangeAttribute>()
|
||||
);
|
||||
|
||||
float min = attr?.min ?? legacyAttr?.min ?? float.NaN;
|
||||
float max = attr?.max ?? legacyAttr?.max ?? float.NaN;
|
||||
|
||||
DoGUI(rect, property, min, max);
|
||||
}
|
||||
|
||||
static class Styles
|
||||
{
|
||||
public static float transformFieldWidthScale = 0.65f;
|
||||
public static readonly int horizontalMargin = (
|
||||
EditorStyles.objectField.margin.right + GUI.skin.horizontalSlider.margin.left
|
||||
) / 2;
|
||||
}
|
||||
|
||||
internal static void DoGUI(Rect rect, SerializedProperty property, float min, float max)
|
||||
{
|
||||
EditorGUI.BeginProperty(rect, GUIContent.none, property);
|
||||
|
||||
var w = rect.width * Styles.transformFieldWidthScale;
|
||||
var weightRect = new Rect(rect.x + w, rect.y, rect.width - w, EditorGUIUtility.singleLineHeight);
|
||||
rect.width = w;
|
||||
|
||||
var transformRect = new Rect(rect.x, rect.y, rect.width - Styles.horizontalMargin, EditorGUIUtility.singleLineHeight);
|
||||
|
||||
EditorGUI.PropertyField(transformRect, property.FindPropertyRelative("transform"), GUIContent.none);
|
||||
|
||||
var indentLvl = EditorGUI.indentLevel;
|
||||
EditorGUI.indentLevel = 0;
|
||||
if (float.IsNaN(max) || float.IsNaN(min))
|
||||
EditorGUI.PropertyField(weightRect, property.FindPropertyRelative("weight"), GUIContent.none);
|
||||
else
|
||||
EditorGUI.Slider(weightRect, property.FindPropertyRelative("weight"), min, max, GUIContent.none);
|
||||
EditorGUI.indentLevel = indentLvl;
|
||||
|
||||
EditorGUI.EndProperty();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: a015bc034afc6b742996a3d23fa85902
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
Reference in New Issue
Block a user