first commit
This commit is contained in:
@@ -0,0 +1,8 @@
|
||||
fileFormatVersion: 2
|
||||
guid: eade225a3b4a03d49af6485534a9dc23
|
||||
folderAsset: yes
|
||||
DefaultImporter:
|
||||
externalObjects: {}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -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:
|
||||
@@ -0,0 +1,2 @@
|
||||
using System.Runtime.CompilerServices;
|
||||
[assembly: InternalsVisibleTo("Unity.Animation.Rigging.EditorTests")]
|
||||
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 0e9f01c83e9859644bb453f6f07af6d6
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,8 @@
|
||||
fileFormatVersion: 2
|
||||
guid: f53358c1055884db9ba27bfa39aae0a0
|
||||
folderAsset: yes
|
||||
DefaultImporter:
|
||||
externalObjects: {}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,116 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using UnityEngine;
|
||||
using UnityEngine.Animations.Rigging;
|
||||
|
||||
namespace UnityEditor.Animations.Rigging
|
||||
{
|
||||
/// <summary>
|
||||
/// Attribute that can be placed on BakeParameters. The attribute is used to declare to which RigConstraint the BakeParameters belong.
|
||||
/// </summary>
|
||||
[AttributeUsage(AttributeTargets.Class, Inherited = false, AllowMultiple = false)]
|
||||
public sealed class BakeParametersAttribute : Attribute
|
||||
{
|
||||
/// <summary>
|
||||
/// Constructor.
|
||||
/// </summary>
|
||||
/// <param name="constraintType">The RigConstraint to which the BakeParameters belong.</param>
|
||||
public BakeParametersAttribute(Type constraintType)
|
||||
{
|
||||
if (constraintType == null || !typeof(IRigConstraint).IsAssignableFrom(constraintType))
|
||||
Debug.LogError("Invalid constraint for InverseRigConstraint attribute.");
|
||||
|
||||
this.constraintType = constraintType;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// The RigConstraint to which the BakeParameters belong.
|
||||
/// </summary>
|
||||
public Type constraintType { get; }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Class that holds bi-directional baking capabilities and curve bindings of a RigConstraint.
|
||||
/// </summary>
|
||||
/// <typeparam name="T">The Type of RigConstraint the parameters belong to.</typeparam>
|
||||
public abstract class BakeParameters<T> : IBakeParameters
|
||||
where T : IRigConstraint
|
||||
{
|
||||
/// <summary>
|
||||
/// Boolean used to determine if the RigConstraint can transfer motion from itself to the skeleton
|
||||
/// </summary>
|
||||
public abstract bool canBakeToSkeleton { get; }
|
||||
/// <summary>
|
||||
/// Boolean used to determine if the RigConstraint can transfer motion to itself from the skeleton.
|
||||
/// </summary>
|
||||
public abstract bool canBakeToConstraint { get; }
|
||||
|
||||
/// <summary>
|
||||
/// Collects the editor curve bindings for all the properties that this RigConstraint modifies when transferring motion to the skeleton.
|
||||
/// </summary>
|
||||
/// <param name="rigBuilder">The RigBuilder which the constraint is part of.</param>
|
||||
/// <param name="constraint">The RigConstraint for which the bindings should be collected.</param>
|
||||
/// <returns></returns>
|
||||
public abstract IEnumerable<EditorCurveBinding> GetSourceCurveBindings(RigBuilder rigBuilder, T constraint);
|
||||
/// <summary>
|
||||
/// Collects the editor curve bindings for all the properties that this RigConstraint modifies when transferring motion to this constraint.
|
||||
/// </summary>
|
||||
/// <param name="rigBuilder">The RigBuilder which the constraint is part of.</param>
|
||||
/// <param name="constraint">The RigConstraint for which the bindings should be collected.</param>
|
||||
/// <returns></returns>
|
||||
public abstract IEnumerable<EditorCurveBinding> GetConstrainedCurveBindings(RigBuilder rigBuilder, T constraint);
|
||||
|
||||
|
||||
/// <inheritdoc />
|
||||
bool IBakeParameters.canBakeToSkeleton => canBakeToSkeleton;
|
||||
/// <inheritdoc />
|
||||
bool IBakeParameters.canBakeToConstraint => canBakeToConstraint;
|
||||
|
||||
/// <inheritdoc />
|
||||
IEnumerable<EditorCurveBinding> IBakeParameters.GetSourceCurveBindings(RigBuilder rigBuilder, IRigConstraint constraint)
|
||||
{
|
||||
Debug.Assert(constraint is T);
|
||||
T tConstraint = (T)constraint;
|
||||
return GetSourceCurveBindings(rigBuilder, tConstraint);
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
IEnumerable<EditorCurveBinding> IBakeParameters.GetConstrainedCurveBindings(RigBuilder rigBuilder, IRigConstraint constraint)
|
||||
{
|
||||
Debug.Assert(constraint is T);
|
||||
T tConstraint = (T)constraint;
|
||||
return GetConstrainedCurveBindings(rigBuilder, tConstraint);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// This is the base interface for BakeParameters.
|
||||
/// </summary>
|
||||
public interface IBakeParameters
|
||||
{
|
||||
/// <summary>
|
||||
/// Boolean used to determine if the RigConstraint can transfer motion from itself to the skeleton
|
||||
/// </summary>
|
||||
bool canBakeToSkeleton { get; }
|
||||
/// <summary>
|
||||
/// Boolean used to determine if the RigConstraint can transfer motion to itself from the skeleton.
|
||||
/// </summary>
|
||||
bool canBakeToConstraint { get; }
|
||||
|
||||
/// <summary>
|
||||
/// Collects the editor curve bindings for all the properties that this RigConstraint modifies when transferring motion to the skeleton.
|
||||
/// </summary>
|
||||
/// <param name="rigBuilder">The RigBuilder which the constraint is part of.</param>
|
||||
/// <param name="constraint">The RigConstraint for which the bindings should be collected.</param>
|
||||
/// <returns></returns>
|
||||
IEnumerable<EditorCurveBinding> GetSourceCurveBindings(RigBuilder rigBuilder, IRigConstraint constraint);
|
||||
/// <summary>
|
||||
/// Collects the editor curve bindings for all the properties that this RigConstraint modifies when transferring motion to this constraint.
|
||||
/// </summary>
|
||||
/// <param name="rigBuilder">The RigBuilder which the constraint is part of.</param>
|
||||
/// <param name="constraint">The RigConstraint for which the bindings should be collected.</param>
|
||||
/// <returns></returns>
|
||||
IEnumerable<EditorCurveBinding> GetConstrainedCurveBindings(RigBuilder rigBuilder, IRigConstraint constraint);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: bc4c7bdb3fbef4e6f8eb6ea619b7c442
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,18 @@
|
||||
using System;
|
||||
using UnityEngine;
|
||||
|
||||
namespace UnityEditor.Animations.Rigging
|
||||
{
|
||||
[AttributeUsage(AttributeTargets.Class, Inherited = false, AllowMultiple = false)]
|
||||
internal sealed class CustomOverlayAttribute : Attribute
|
||||
{
|
||||
private Type m_EffectorType;
|
||||
|
||||
public CustomOverlayAttribute(Type effectorType)
|
||||
{
|
||||
m_EffectorType = effectorType;
|
||||
}
|
||||
|
||||
public Type effectorType { get => m_EffectorType; }
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 54d375d3ab6254023a5ab55153af9c84
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,32 @@
|
||||
using System;
|
||||
using UnityEngine;
|
||||
using UnityEngine.Animations.Rigging;
|
||||
|
||||
namespace UnityEditor.Animations.Rigging
|
||||
{
|
||||
/// <summary>
|
||||
/// The [InverseRigConstraint] attribute allows to match an inverse constraint (inverse solve) to its
|
||||
/// base constraint (forward solve) counterpart. This is used in bi-directional baking to override
|
||||
/// constraints when baking animations to constraints.
|
||||
/// </summary>
|
||||
[AttributeUsage(AttributeTargets.Class, Inherited = false, AllowMultiple = false)]
|
||||
public sealed class InverseRigConstraintAttribute : Attribute
|
||||
{
|
||||
/// <summary>
|
||||
/// Constructor.
|
||||
/// </summary>
|
||||
/// <param name="targetBinderType">The base constraint type.</param>
|
||||
public InverseRigConstraintAttribute(Type targetBinderType)
|
||||
{
|
||||
if (targetBinderType == null || !typeof(IRigConstraint).IsAssignableFrom(targetBinderType))
|
||||
Debug.LogError("Invalid constraint for InverseRigConstraint attribute.");
|
||||
|
||||
this.baseConstraint = targetBinderType;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Retrieves the base constraint type.
|
||||
/// </summary>
|
||||
public Type baseConstraint { get; }
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 28f235e117a7e453fa6d4c1cb6094700
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,8 @@
|
||||
fileFormatVersion: 2
|
||||
guid: fbd5015e3b81f464aa1b87826a3eaf55
|
||||
folderAsset: yes
|
||||
DefaultImporter:
|
||||
externalObjects: {}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,12 @@
|
||||
using UnityEngine;
|
||||
|
||||
namespace UnityEditor.Animations.Rigging
|
||||
{
|
||||
internal interface IRigEffector
|
||||
{
|
||||
Transform transform { get; }
|
||||
bool visible { get; set; }
|
||||
|
||||
void OnSceneGUI();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 5aa7c79e34bb34aab80024d95fafe526
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,10 @@
|
||||
using System;
|
||||
|
||||
namespace UnityEditor.Animations.Rigging
|
||||
{
|
||||
interface IRigEffectorOverlay : IDisposable
|
||||
{
|
||||
bool IsValid();
|
||||
void OnSceneGUIOverlay();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 4231b7e96c3094051a12f91bae5c7c90
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,307 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using UnityEngine;
|
||||
using UnityEngine.Animations.Rigging;
|
||||
|
||||
namespace UnityEditor.Animations.Rigging
|
||||
{
|
||||
[Serializable]
|
||||
internal class RigEffector : ScriptableObject, IRigEffector
|
||||
{
|
||||
[SerializeField] private RigEffectorData m_Data;
|
||||
|
||||
public Transform transform
|
||||
{
|
||||
get => m_Data.transform;
|
||||
}
|
||||
|
||||
public bool visible
|
||||
{
|
||||
get => m_Data.visible;
|
||||
set => m_Data.visible = value;
|
||||
}
|
||||
|
||||
private static int s_ButtonHash = "RigEffector".GetHashCode();
|
||||
|
||||
public void Initialize(RigEffectorData data)
|
||||
{
|
||||
m_Data = data;
|
||||
}
|
||||
|
||||
private static Material s_Material;
|
||||
|
||||
public static Material material
|
||||
{
|
||||
get
|
||||
{
|
||||
if (!s_Material)
|
||||
{
|
||||
var shader = EditorHelper.LoadShader("BoneHandles.shader");
|
||||
s_Material = new Material(shader);
|
||||
s_Material.hideFlags = HideFlags.HideAndDontSave;
|
||||
}
|
||||
|
||||
return s_Material;
|
||||
}
|
||||
}
|
||||
|
||||
public static RigEffectorData.Style defaultStyle
|
||||
{
|
||||
get
|
||||
{
|
||||
var style = new RigEffectorData.Style()
|
||||
{
|
||||
shape = EditorHelper.LoadShape("LocatorEffector.asset"),
|
||||
color = new Color(1f, 0f, 0f, 0.5f),
|
||||
size = 0.10f,
|
||||
position = Vector3.zero,
|
||||
rotation = Vector3.zero
|
||||
};
|
||||
|
||||
return style;
|
||||
}
|
||||
}
|
||||
|
||||
public void OnSceneGUI()
|
||||
{
|
||||
if (!m_Data.visible)
|
||||
return;
|
||||
|
||||
// Might happen if we delete transform while effector still exists.
|
||||
if (transform == null)
|
||||
return;
|
||||
|
||||
var style = m_Data.style;
|
||||
|
||||
// Disregard effectors without shapes.
|
||||
if (style.shape == null)
|
||||
return;
|
||||
|
||||
if (SceneVisibilityManager.instance.IsHidden(transform.gameObject, false))
|
||||
return;
|
||||
|
||||
var mask = UnityEditor.Tools.visibleLayers;
|
||||
if ((mask & (1 << transform.gameObject.layer)) == 0)
|
||||
return;
|
||||
|
||||
int id = GUIUtility.GetControlID(s_ButtonHash, FocusType.Passive);
|
||||
Event evt = Event.current;
|
||||
|
||||
switch (evt.GetTypeForControl(id))
|
||||
{
|
||||
case EventType.Layout:
|
||||
{
|
||||
HandleUtility.AddControl(id, DistanceToEffector(transform, style.shape, style.position, style.rotation, style.size));
|
||||
break;
|
||||
}
|
||||
case EventType.MouseDown:
|
||||
{
|
||||
if (evt.alt)
|
||||
break;
|
||||
|
||||
if (HandleUtility.nearestControl == id && evt.button == 0)
|
||||
{
|
||||
GameObject targetGameObject = transform.gameObject;
|
||||
if (!SceneVisibilityManager.instance.IsPickingDisabled(targetGameObject, false))
|
||||
{
|
||||
GUIUtility.hotControl = id; // Grab mouse focus
|
||||
EditorHelper.HandleClickSelection(targetGameObject, evt);
|
||||
evt.Use();
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
case EventType.MouseDrag:
|
||||
{
|
||||
if (!evt.alt && GUIUtility.hotControl == id)
|
||||
{
|
||||
GameObject targetGameObject = transform.gameObject;
|
||||
if (!SceneVisibilityManager.instance.IsPickingDisabled(targetGameObject, false))
|
||||
{
|
||||
DragAndDrop.PrepareStartDrag();
|
||||
DragAndDrop.objectReferences = new UnityEngine.Object[] {transform};
|
||||
DragAndDrop.StartDrag(ObjectNames.GetDragAndDropTitle(transform));
|
||||
|
||||
GUIUtility.hotControl = 0;
|
||||
|
||||
evt.Use();
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
case EventType.MouseUp:
|
||||
{
|
||||
if (GUIUtility.hotControl == id && (evt.button == 0 || evt.button == 2))
|
||||
{
|
||||
GUIUtility.hotControl = 0;
|
||||
evt.Use();
|
||||
}
|
||||
break;
|
||||
}
|
||||
case EventType.Repaint:
|
||||
{
|
||||
Matrix4x4 matrix = GetEffectorMatrix(transform, style.position, style.rotation, style.size);
|
||||
|
||||
Color highlight = style.color;
|
||||
|
||||
bool hoveringEffector = GUIUtility.hotControl == 0 && HandleUtility.nearestControl == id;
|
||||
hoveringEffector = hoveringEffector &&
|
||||
!SceneVisibilityManager.instance.IsPickingDisabled(transform.gameObject, false);
|
||||
|
||||
if (hoveringEffector)
|
||||
{
|
||||
highlight = Handles.preselectionColor;
|
||||
}
|
||||
else if (Selection.Contains(transform.gameObject) || Selection.activeObject == transform.gameObject)
|
||||
{
|
||||
highlight = Handles.selectedColor;
|
||||
}
|
||||
|
||||
try
|
||||
{
|
||||
Material mat = material;
|
||||
|
||||
var shapeHighlight = MeshHasWireframeShapes(style.shape) ? style.color : highlight;
|
||||
var wireHighlight = new Color(highlight.r, highlight.g, highlight.b, 1f);
|
||||
|
||||
if (style.shape.subMeshCount > 0)
|
||||
{
|
||||
// Draw every sub meshes separately to control highlight vs shape colors.
|
||||
for (int i = 0; i < style.shape.subMeshCount; ++i)
|
||||
{
|
||||
MeshTopology topology = style.shape.GetTopology(i);
|
||||
bool isFilled = (topology == MeshTopology.Triangles || topology == MeshTopology.Quads);
|
||||
|
||||
mat.SetColor("_Color", isFilled ? shapeHighlight : wireHighlight);
|
||||
mat.SetPass(0);
|
||||
|
||||
Graphics.DrawMeshNow(style.shape, matrix, i);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
MeshTopology topology = style.shape.GetTopology(0);
|
||||
bool isFilled = (topology == MeshTopology.Triangles || topology == MeshTopology.Quads);
|
||||
|
||||
mat.SetColor("_Color", isFilled ? shapeHighlight : wireHighlight);
|
||||
mat.SetPass(0);
|
||||
|
||||
Graphics.DrawMeshNow(style.shape, matrix);
|
||||
}
|
||||
}
|
||||
catch (Exception exception)
|
||||
{
|
||||
Debug.LogException(exception);
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
private bool FindMeshTopology(Mesh shape, IEnumerable<MeshTopology> topologies)
|
||||
{
|
||||
if (shape.subMeshCount > 0)
|
||||
{
|
||||
for (int i = 0; i < shape.subMeshCount; ++i)
|
||||
{
|
||||
MeshTopology topology = shape.GetTopology(i);
|
||||
foreach (var topologyQuery in topologies)
|
||||
{
|
||||
if (topologyQuery == topology)
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
var topology = shape.GetTopology(0);
|
||||
foreach (var topologyQuery in topologies)
|
||||
{
|
||||
if (topologyQuery == topology)
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
private bool MeshHasFilledShapes(Mesh shape) =>
|
||||
FindMeshTopology(shape, new MeshTopology[] {MeshTopology.Triangles, MeshTopology.Quads});
|
||||
|
||||
private bool MeshHasWireframeShapes(Mesh shape) =>
|
||||
FindMeshTopology(shape, new MeshTopology[] {MeshTopology.Lines, MeshTopology.LineStrip});
|
||||
|
||||
private Matrix4x4 GetEffectorMatrix(Transform transform, Vector3 position, Vector3 rotation, float size)
|
||||
{
|
||||
return Matrix4x4.TRS(transform.position, transform.rotation, Vector3.one) * Matrix4x4.TRS(position, Quaternion.Euler(rotation), new Vector3(size, size, size));
|
||||
}
|
||||
|
||||
private float DistanceToEffector(Transform transform, Mesh shape, Vector3 position, Vector3 rotation, float size)
|
||||
{
|
||||
Matrix4x4 matrix = GetEffectorMatrix(transform, position, rotation, size);
|
||||
Vector3 origin = matrix.MultiplyPoint(Vector3.zero);
|
||||
|
||||
if (shape == null)
|
||||
return HandleUtility.DistanceToCircle(origin, size * 0.5f);
|
||||
|
||||
if (MeshHasFilledShapes(shape))
|
||||
{
|
||||
var bounds = shape.bounds;
|
||||
var extents = Mathf.Max( Mathf.Max(bounds.extents.x, bounds.extents.y), bounds.extents.z);
|
||||
return HandleUtility.DistanceToCircle(origin + bounds.center * size, extents * size);
|
||||
}
|
||||
|
||||
float nearestDistance = Mathf.Infinity;
|
||||
|
||||
Vector3[] vertices = shape.vertices;
|
||||
|
||||
for (int i = 0; i < shape.subMeshCount; ++i)
|
||||
{
|
||||
MeshTopology topology = shape.GetTopology(i);
|
||||
if (topology == MeshTopology.Lines)
|
||||
{
|
||||
int[] indices = shape.GetIndices(i);
|
||||
|
||||
int count = 0;
|
||||
while (count < indices.Length)
|
||||
{
|
||||
float d = HandleUtility.DistanceToLine(matrix.MultiplyPoint(vertices[indices[count]]), matrix.MultiplyPoint(vertices[indices[count+1]]));
|
||||
if (d < nearestDistance)
|
||||
nearestDistance = d;
|
||||
|
||||
count += 2;
|
||||
}
|
||||
}
|
||||
else if (topology == MeshTopology.LineStrip)
|
||||
{
|
||||
int[] indices = shape.GetIndices(i);
|
||||
|
||||
if (indices.Length > 0)
|
||||
{
|
||||
int count = 0;
|
||||
float d = 0f;
|
||||
Vector3 v0 = matrix.MultiplyPoint(vertices[indices[count]]);
|
||||
Vector3 v1 = v0;
|
||||
|
||||
while (++count < indices.Length)
|
||||
{
|
||||
Vector3 v2 = matrix.MultiplyPoint(vertices[indices[count]]);
|
||||
|
||||
d = HandleUtility.DistanceToLine(v1, v2);
|
||||
if (d < nearestDistance)
|
||||
nearestDistance = d;
|
||||
|
||||
v1 = v2;
|
||||
}
|
||||
|
||||
d = HandleUtility.DistanceToLine(v1, v0);
|
||||
if (d < nearestDistance)
|
||||
nearestDistance = d;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return nearestDistance;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: ff03b96c5bd3745c28814ed6eb4341cb
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,190 @@
|
||||
using UnityEngine;
|
||||
using UnityEngine.Animations.Rigging;
|
||||
|
||||
namespace UnityEditor.Animations.Rigging
|
||||
{
|
||||
[CustomOverlay(typeof(RigEffector))]
|
||||
class RigEffectorOverlay : IRigEffectorOverlay
|
||||
{
|
||||
private Object[] m_TargetObjects;
|
||||
private SerializedObject m_SerializedObject;
|
||||
|
||||
private SerializedProperty m_Visible;
|
||||
private SerializedProperty m_Shape;
|
||||
private SerializedProperty m_Color;
|
||||
private SerializedProperty m_Size;
|
||||
private SerializedProperty m_Position;
|
||||
private SerializedProperty m_Rotation;
|
||||
|
||||
private bool m_ExpandOverlay;
|
||||
|
||||
private static GUIContent s_VisibleLabel = new GUIContent("Visible");
|
||||
private static GUIContent s_ShapeLabel = new GUIContent("Shape");
|
||||
private static GUIContent s_ColorLabel = new GUIContent("Color");
|
||||
private static GUIContent s_SizeLabel = new GUIContent("Size");
|
||||
private static GUIContent s_PositionLabel = new GUIContent("Position");
|
||||
private static GUIContent s_RotationLabel = new GUIContent("Rotation");
|
||||
|
||||
private static GUIContent s_RemoveLabel = new GUIContent("Remove");
|
||||
|
||||
private static string s_ExpandOverlayPrefKey = "AnimationRigging.ExpandOverlay";
|
||||
|
||||
private static GUILayoutOption s_FixedWidth = GUILayout.Width(210f);
|
||||
|
||||
public void Initialize(Object[] effectors)
|
||||
{
|
||||
m_TargetObjects = effectors;
|
||||
m_SerializedObject = new SerializedObject(effectors);
|
||||
|
||||
SerializedProperty data = m_SerializedObject.FindProperty("m_Data");
|
||||
|
||||
m_Visible = data.FindPropertyRelative("m_Visible");
|
||||
|
||||
SerializedProperty style = data.FindPropertyRelative("m_Style");
|
||||
|
||||
m_Shape = style.FindPropertyRelative("shape");
|
||||
m_Color = style.FindPropertyRelative("color");
|
||||
m_Size = style.FindPropertyRelative("size");
|
||||
m_Position = style.FindPropertyRelative("position");
|
||||
m_Rotation = style.FindPropertyRelative("rotation");
|
||||
|
||||
m_ExpandOverlay = EditorPrefs.GetBool(s_ExpandOverlayPrefKey, true);
|
||||
}
|
||||
|
||||
private IRigEffectorHolder FetchRigEffectorHolder(Transform transform)
|
||||
{
|
||||
var rigBuilder = EditorHelper.GetClosestComponent<RigBuilder>(transform);
|
||||
var rig = EditorHelper.GetClosestComponent<Rig>(transform, (rigBuilder != null) ? rigBuilder.transform : null);
|
||||
|
||||
if (rigBuilder.ContainsEffector(transform))
|
||||
{
|
||||
return rigBuilder;
|
||||
}
|
||||
else if (rig.ContainsEffector(transform))
|
||||
{
|
||||
return rig;
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
public bool IsValid() => m_SerializedObject.targetObject != null;
|
||||
|
||||
public void OnSceneGUIOverlay()
|
||||
{
|
||||
if (!IsValid())
|
||||
return;
|
||||
|
||||
m_SerializedObject.Update();
|
||||
|
||||
GameObject targetGameObject = null;
|
||||
if (!m_SerializedObject.isEditingMultipleObjects)
|
||||
{
|
||||
RigEffector rigEffector = m_SerializedObject.targetObject as RigEffector;
|
||||
if (rigEffector != null && rigEffector.transform != null)
|
||||
{
|
||||
targetGameObject = rigEffector.transform.gameObject;
|
||||
}
|
||||
}
|
||||
|
||||
GUILayout.BeginHorizontal(s_FixedWidth);
|
||||
|
||||
EditorGUI.BeginChangeCheck();
|
||||
m_ExpandOverlay = EditorGUILayout.Toggle(m_ExpandOverlay, EditorStyles.foldout, GUILayout.Width(12));
|
||||
if (EditorGUI.EndChangeCheck())
|
||||
{
|
||||
EditorPrefs.SetBool(s_ExpandOverlayPrefKey, m_ExpandOverlay);
|
||||
}
|
||||
|
||||
GUILayout.BeginHorizontal(EditorStyles.toolbar);
|
||||
|
||||
EditorGUILayout.PropertyField(m_Visible, GUIContent.none, GUILayout.Width(17));
|
||||
|
||||
GUILayout.Label((targetGameObject != null) ? targetGameObject.name : "(Multiple objects)");
|
||||
|
||||
if (GUILayout.Button(GUIContent.none, "OL Minus", GUILayout.Width(17)))
|
||||
{
|
||||
UnityEngine.Object[] targetObjects = m_SerializedObject.targetObjects;
|
||||
foreach(var targetObject in targetObjects)
|
||||
{
|
||||
var effector = targetObject as IRigEffector;
|
||||
Transform transform = effector.transform;
|
||||
|
||||
IRigEffectorHolder holder = FetchRigEffectorHolder(transform);
|
||||
if (holder != null)
|
||||
{
|
||||
var holderObject = holder as UnityEngine.Object;
|
||||
|
||||
Undo.RecordObject(holderObject, "Remove Effector");
|
||||
|
||||
if (PrefabUtility.IsPartOfPrefabInstance(holderObject))
|
||||
EditorUtility.SetDirty(holderObject);
|
||||
|
||||
holder.RemoveEffector(transform);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
GUILayout.EndHorizontal();
|
||||
GUILayout.EndHorizontal();
|
||||
|
||||
if (m_ExpandOverlay)
|
||||
{
|
||||
EditorGUILayout.LabelField(s_ShapeLabel, s_FixedWidth);
|
||||
EditorGUILayout.PropertyField(m_Shape, GUIContent.none, s_FixedWidth);
|
||||
|
||||
Rect rect = GUILayoutUtility.GetRect(s_ColorLabel, EditorStyles.colorField, s_FixedWidth);
|
||||
|
||||
// Shenanigans to bypass color picker bug.
|
||||
var evt = Event.current;
|
||||
if (evt.type == EventType.MouseUp)
|
||||
{
|
||||
if (rect.Contains(evt.mousePosition))
|
||||
{
|
||||
GUIUtility.hotControl = 0;
|
||||
}
|
||||
}
|
||||
|
||||
EditorGUI.BeginProperty(rect, s_ColorLabel, m_Color);
|
||||
EditorGUI.BeginChangeCheck();
|
||||
Color newColor = EditorGUI.ColorField(rect, s_ColorLabel, m_Color.colorValue, false, true, false);
|
||||
if (EditorGUI.EndChangeCheck())
|
||||
{
|
||||
m_Color.colorValue = newColor;
|
||||
}
|
||||
EditorGUI.EndProperty();
|
||||
|
||||
EditorGUILayout.PropertyField(m_Size, s_SizeLabel, s_FixedWidth);
|
||||
EditorGUILayout.PropertyField(m_Position, s_PositionLabel, s_FixedWidth);
|
||||
EditorGUILayout.PropertyField(m_Rotation, s_RotationLabel, s_FixedWidth);
|
||||
}
|
||||
|
||||
if (m_SerializedObject.hasModifiedProperties)
|
||||
{
|
||||
UnityEngine.Object[] targetObjects = m_SerializedObject.targetObjects;
|
||||
foreach(var targetObject in targetObjects)
|
||||
{
|
||||
var effector = targetObject as IRigEffector;
|
||||
Transform transform = effector.transform;
|
||||
|
||||
IRigEffectorHolder holder = FetchRigEffectorHolder(transform);
|
||||
if (holder != null)
|
||||
{
|
||||
var holderObject = holder as UnityEngine.Object;
|
||||
Undo.RecordObject(holderObject, "Edit Effector");
|
||||
|
||||
if (PrefabUtility.IsPartOfPrefabInstance(holderObject))
|
||||
EditorUtility.SetDirty(holderObject);
|
||||
}
|
||||
}
|
||||
|
||||
m_SerializedObject.ApplyModifiedProperties();
|
||||
}
|
||||
}
|
||||
|
||||
public void Dispose()
|
||||
{
|
||||
m_SerializedObject?.Dispose();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 128d92bb7c7e949569b14ae35b4b229e
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,235 @@
|
||||
using System.Collections.Generic;
|
||||
using UnityEngine;
|
||||
using UnityEngine.Animations.Rigging;
|
||||
#if SUPPORTS_SCENE_VIEW_OVERLAYS
|
||||
using UnityEditor.Overlays;
|
||||
#endif
|
||||
using UnityEditor.Experimental.SceneManagement; // required for 2020.2
|
||||
using UnityEditor.SceneManagement;
|
||||
|
||||
namespace UnityEditor.Animations.Rigging
|
||||
{
|
||||
[InitializeOnLoad]
|
||||
static class RigEffectorRenderer
|
||||
{
|
||||
const string k_OverlayId = "Scene View/Animation Rigging";
|
||||
const string k_DisplayName = "Animation Rigging";
|
||||
|
||||
static GUIContent s_OverlayTitle = new GUIContent(k_DisplayName);
|
||||
|
||||
static List<RigBuilder> s_RigBuilders = new List<RigBuilder>();
|
||||
static Dictionary<RigEffectorData, RigEffector> s_Effectors = new Dictionary<RigEffectorData, RigEffector>();
|
||||
|
||||
static Transform[] s_ActiveSelection = null;
|
||||
static List<RigEffector> s_ActiveEffectors = null;
|
||||
static IRigEffectorOverlay s_ActiveOverlay = null;
|
||||
|
||||
static bool s_ActiveOverlayDirtied = true;
|
||||
|
||||
static RigEffectorRenderer()
|
||||
{
|
||||
RigBuilder.onAddRigBuilder += OnAddRigBuilder;
|
||||
RigBuilder.onRemoveRigBuilder += OnRemoveRigBuilder;
|
||||
|
||||
SceneView.duringSceneGui += OnSceneGUI;
|
||||
Selection.selectionChanged += OnSelectionChange;
|
||||
ObjectFactory.componentWasAdded += OnComponentAdded;
|
||||
}
|
||||
|
||||
static void OnSelectionChange()
|
||||
{
|
||||
s_ActiveOverlayDirtied = true;
|
||||
}
|
||||
|
||||
static void OnComponentAdded(Component component)
|
||||
{
|
||||
if (!(component is Rig) && !(component is RigBuilder))
|
||||
return;
|
||||
|
||||
s_ActiveOverlayDirtied = true;
|
||||
}
|
||||
|
||||
static void FetchOrCreateEffectors(IRigEffectorHolder holder)
|
||||
{
|
||||
foreach(var effectorData in holder.effectors)
|
||||
{
|
||||
if (s_Effectors.ContainsKey(effectorData))
|
||||
{
|
||||
s_ActiveEffectors.Add(s_Effectors[effectorData]);
|
||||
}
|
||||
else
|
||||
{
|
||||
var newEffector = ScriptableObject.CreateInstance<RigEffector>();
|
||||
newEffector.Initialize(effectorData);
|
||||
|
||||
s_Effectors.Add(effectorData, newEffector);
|
||||
s_ActiveEffectors.Add(newEffector);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void FetchOrCreateEffectors()
|
||||
{
|
||||
s_ActiveEffectors = new List<RigEffector>();
|
||||
|
||||
PrefabStage prefabStage = PrefabStageUtility.GetCurrentPrefabStage();
|
||||
|
||||
for (int i = 0; i < s_RigBuilders.Count; i++)
|
||||
{
|
||||
var rigBuilder = s_RigBuilders[i];
|
||||
|
||||
if (rigBuilder == null)
|
||||
continue;
|
||||
|
||||
if (prefabStage != null)
|
||||
{
|
||||
StageHandle stageHandle = prefabStage.stageHandle;
|
||||
if (stageHandle.IsValid() && !stageHandle.Contains(rigBuilder.gameObject))
|
||||
continue;
|
||||
}
|
||||
|
||||
FetchOrCreateEffectors(rigBuilder);
|
||||
|
||||
var rigs = rigBuilder.GetComponentsInChildren<Rig>();
|
||||
if (rigs != null)
|
||||
{
|
||||
foreach(var rig in rigs)
|
||||
{
|
||||
FetchOrCreateEffectors(rig);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static IRigEffectorOverlay FetchOrCreateEffectorOverlay()
|
||||
{
|
||||
if (!s_ActiveOverlayDirtied && s_ActiveOverlay != null && s_ActiveOverlay.IsValid())
|
||||
return s_ActiveOverlay;
|
||||
|
||||
s_ActiveOverlay?.Dispose();
|
||||
|
||||
Transform[] transforms = Selection.GetTransforms(SelectionMode.ExcludePrefab | SelectionMode.Editable);
|
||||
var inspectedEffectors = new List<Object>();
|
||||
|
||||
for (int i = 0; i < s_ActiveEffectors.Count; ++i)
|
||||
{
|
||||
var effector = s_ActiveEffectors[i];
|
||||
if (effector != null && effector.transform != null)
|
||||
{
|
||||
if (Selection.Contains(effector.transform) || Selection.Contains(effector.transform.gameObject))
|
||||
{
|
||||
inspectedEffectors.Add(s_ActiveEffectors[i]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (inspectedEffectors.Count > 0)
|
||||
{
|
||||
var overlay = new RigEffectorOverlay();
|
||||
overlay.Initialize(inspectedEffectors.ToArray());
|
||||
|
||||
s_ActiveOverlay = overlay;
|
||||
}
|
||||
else
|
||||
{
|
||||
RigEffectorWizard wizard = null;
|
||||
|
||||
foreach(var transform in transforms)
|
||||
{
|
||||
RigBuilder rigBuilder = EditorHelper.GetClosestComponent<RigBuilder>(transform);
|
||||
Rig rig = EditorHelper.GetClosestComponent<Rig>(transform, (rigBuilder != null) ? rigBuilder.transform : null);
|
||||
IRigEffectorHolder holder = (rig != null) ? (IRigEffectorHolder)rig : (IRigEffectorHolder)rigBuilder;
|
||||
|
||||
if (holder == null)
|
||||
continue;
|
||||
|
||||
if (wizard == null)
|
||||
wizard = new RigEffectorWizard();
|
||||
|
||||
wizard.Add(holder, transform);
|
||||
}
|
||||
|
||||
if (wizard != null)
|
||||
{
|
||||
s_ActiveOverlay = wizard;
|
||||
}
|
||||
else
|
||||
{
|
||||
s_ActiveOverlay = null;
|
||||
}
|
||||
}
|
||||
|
||||
s_ActiveSelection = transforms;
|
||||
|
||||
s_ActiveOverlayDirtied = false;
|
||||
return s_ActiveOverlay;
|
||||
}
|
||||
|
||||
static void OnSceneGUI(SceneView sceneView)
|
||||
{
|
||||
// Fetch effectors and overlay once in Layout before processing events.
|
||||
if (Event.current.type == EventType.Layout)
|
||||
{
|
||||
FetchOrCreateEffectors();
|
||||
FetchOrCreateEffectorOverlay();
|
||||
}
|
||||
|
||||
// Process effector events.
|
||||
if (s_ActiveEffectors != null)
|
||||
{
|
||||
for (int i = 0; i < s_ActiveEffectors.Count; ++i)
|
||||
{
|
||||
var effector = s_ActiveEffectors[i];
|
||||
if (effector == null)
|
||||
continue;
|
||||
|
||||
effector.OnSceneGUI();
|
||||
}
|
||||
}
|
||||
|
||||
#if !SUPPORTS_SCENE_VIEW_OVERLAYS
|
||||
// Process overlay events.
|
||||
if (s_ActiveOverlay != null)
|
||||
{
|
||||
SceneViewOverlay.Begin(sceneView);
|
||||
SceneViewOverlay.Window(s_OverlayTitle, SceneViewGUICallback, 1200);
|
||||
SceneViewOverlay.End();
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
static void OnAddRigBuilder(RigBuilder rigBuilder)
|
||||
{
|
||||
s_RigBuilders.Add(rigBuilder);
|
||||
}
|
||||
|
||||
static void OnRemoveRigBuilder(RigBuilder rigBuilder)
|
||||
{
|
||||
s_RigBuilders.Remove(rigBuilder);
|
||||
s_Effectors.Clear();
|
||||
}
|
||||
|
||||
private static void SceneViewGUICallback(UnityEngine.Object target, SceneView sceneView)
|
||||
{
|
||||
if (s_ActiveOverlay != null)
|
||||
s_ActiveOverlay.OnSceneGUIOverlay();
|
||||
}
|
||||
|
||||
#if SUPPORTS_SCENE_VIEW_OVERLAYS
|
||||
[Overlay(typeof(SceneView), k_OverlayId, k_DisplayName)]
|
||||
class Overlay : IMGUIOverlay, ITransientOverlay
|
||||
{
|
||||
public bool visible
|
||||
{
|
||||
get => s_ActiveOverlay != null;
|
||||
}
|
||||
|
||||
public override void OnGUI()
|
||||
{
|
||||
if (s_ActiveOverlay != null)
|
||||
s_ActiveOverlay.OnSceneGUIOverlay();
|
||||
}
|
||||
}
|
||||
#endif
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: aedff7ad35cc7477a9786519f4791c00
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,68 @@
|
||||
using System.Collections.Generic;
|
||||
using UnityEngine;
|
||||
using UnityEngine.Animations.Rigging;
|
||||
|
||||
namespace UnityEditor.Animations.Rigging
|
||||
{
|
||||
class RigEffectorWizard : IRigEffectorOverlay
|
||||
{
|
||||
private static GUIContent s_CreateEffectorLabel = new GUIContent("Create Effector");
|
||||
|
||||
private struct HolderTransformPair
|
||||
{
|
||||
public IRigEffectorHolder holder;
|
||||
public Transform transform;
|
||||
}
|
||||
|
||||
private List<HolderTransformPair> m_Transforms = new List<HolderTransformPair>();
|
||||
|
||||
public void Add(IRigEffectorHolder holder, Transform transform)
|
||||
{
|
||||
m_Transforms.Add(new HolderTransformPair() { holder = holder, transform = transform });
|
||||
}
|
||||
|
||||
public bool IsValid() => true;
|
||||
|
||||
public void OnSceneGUIOverlay()
|
||||
{
|
||||
string labelName = "(no selection)";
|
||||
if (m_Transforms.Count > 1)
|
||||
{
|
||||
labelName = "(Multiple objects)";
|
||||
}
|
||||
else if (m_Transforms.Count > 0)
|
||||
{
|
||||
if (m_Transforms[0].transform.gameObject != null)
|
||||
{
|
||||
labelName = m_Transforms[0].transform.gameObject.name;
|
||||
}
|
||||
}
|
||||
|
||||
GUILayout.BeginHorizontal(EditorStyles.toolbar, GUILayout.Width(210.0f));
|
||||
|
||||
GUILayout.Label(labelName);
|
||||
|
||||
if (GUILayout.Button(GUIContent.none, "OL Plus", GUILayout.Width(17)))
|
||||
{
|
||||
foreach (var pair in m_Transforms)
|
||||
{
|
||||
var targetObject = pair.holder as UnityEngine.Object;
|
||||
|
||||
Undo.RecordObject(targetObject, "Add Effector");
|
||||
|
||||
if (PrefabUtility.IsPartOfPrefabInstance(targetObject))
|
||||
EditorUtility.SetDirty(targetObject);
|
||||
|
||||
pair.holder.AddEffector(pair.transform, RigEffector.defaultStyle);
|
||||
}
|
||||
}
|
||||
|
||||
GUILayout.EndHorizontal();
|
||||
}
|
||||
|
||||
public void Dispose()
|
||||
{
|
||||
// nothing to do.
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 51459fd0b87be44cbb33be7842186a5e
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,8 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 756c4b6dd3c75480781e03b559e98355
|
||||
folderAsset: yes
|
||||
DefaultImporter:
|
||||
externalObjects: {}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
Binary file not shown.
|
After Width: | Height: | Size: 5.9 KiB |
@@ -0,0 +1,120 @@
|
||||
fileFormatVersion: 2
|
||||
guid: ca41524ec86f0d84ab5675c9622cc1a2
|
||||
TextureImporter:
|
||||
internalIDToNameTable: []
|
||||
externalObjects: {}
|
||||
serializedVersion: 11
|
||||
mipmaps:
|
||||
mipMapMode: 0
|
||||
enableMipMap: 1
|
||||
sRGBTexture: 1
|
||||
linearTexture: 0
|
||||
fadeOut: 0
|
||||
borderMipMap: 0
|
||||
mipMapsPreserveCoverage: 0
|
||||
alphaTestReferenceValue: 0.5
|
||||
mipMapFadeDistanceStart: 1
|
||||
mipMapFadeDistanceEnd: 3
|
||||
bumpmap:
|
||||
convertToNormalMap: 0
|
||||
externalNormalMap: 0
|
||||
heightScale: 0.25
|
||||
normalMapFilter: 0
|
||||
isReadable: 0
|
||||
streamingMipmaps: 0
|
||||
streamingMipmapsPriority: 0
|
||||
vTOnly: 0
|
||||
grayScaleToAlpha: 0
|
||||
generateCubemap: 6
|
||||
cubemapConvolution: 0
|
||||
seamlessCubemap: 0
|
||||
textureFormat: 1
|
||||
maxTextureSize: 2048
|
||||
textureSettings:
|
||||
serializedVersion: 2
|
||||
filterMode: 1
|
||||
aniso: 0
|
||||
mipBias: 0
|
||||
wrapU: 1
|
||||
wrapV: 1
|
||||
wrapW: 1
|
||||
nPOTScale: 0
|
||||
lightmap: 0
|
||||
compressionQuality: 50
|
||||
spriteMode: 0
|
||||
spriteExtrude: 1
|
||||
spriteMeshType: 1
|
||||
alignment: 0
|
||||
spritePivot: {x: 0.5, y: 0.5}
|
||||
spritePixelsToUnits: 100
|
||||
spriteBorder: {x: 0, y: 0, z: 0, w: 0}
|
||||
spriteGenerateFallbackPhysicsShape: 1
|
||||
alphaUsage: 1
|
||||
alphaIsTransparency: 1
|
||||
spriteTessellationDetail: -1
|
||||
textureType: 2
|
||||
textureShape: 1
|
||||
singleChannelComponent: 0
|
||||
flipbookRows: 1
|
||||
flipbookColumns: 1
|
||||
maxTextureSizeSet: 0
|
||||
compressionQualitySet: 0
|
||||
textureFormatSet: 0
|
||||
ignorePngGamma: 0
|
||||
applyGammaDecoding: 1
|
||||
platformSettings:
|
||||
- serializedVersion: 3
|
||||
buildTarget: DefaultTexturePlatform
|
||||
maxTextureSize: 2048
|
||||
resizeAlgorithm: 0
|
||||
textureFormat: -1
|
||||
textureCompression: 0
|
||||
compressionQuality: 50
|
||||
crunchedCompression: 0
|
||||
allowsAlphaSplitting: 0
|
||||
overridden: 0
|
||||
androidETC2FallbackOverride: 0
|
||||
forceMaximumCompressionQuality_BC6H_BC7: 0
|
||||
- serializedVersion: 3
|
||||
buildTarget: Standalone
|
||||
maxTextureSize: 2048
|
||||
resizeAlgorithm: 0
|
||||
textureFormat: -1
|
||||
textureCompression: 0
|
||||
compressionQuality: 50
|
||||
crunchedCompression: 0
|
||||
allowsAlphaSplitting: 0
|
||||
overridden: 0
|
||||
androidETC2FallbackOverride: 0
|
||||
forceMaximumCompressionQuality_BC6H_BC7: 0
|
||||
- serializedVersion: 3
|
||||
buildTarget: WebGL
|
||||
maxTextureSize: 2048
|
||||
resizeAlgorithm: 0
|
||||
textureFormat: -1
|
||||
textureCompression: 0
|
||||
compressionQuality: 50
|
||||
crunchedCompression: 0
|
||||
allowsAlphaSplitting: 0
|
||||
overridden: 0
|
||||
androidETC2FallbackOverride: 0
|
||||
forceMaximumCompressionQuality_BC6H_BC7: 0
|
||||
spriteSheet:
|
||||
serializedVersion: 2
|
||||
sprites: []
|
||||
outline: []
|
||||
physicsShape: []
|
||||
bones: []
|
||||
spriteID:
|
||||
internalID: 0
|
||||
vertices: []
|
||||
indices:
|
||||
edges: []
|
||||
weights: []
|
||||
secondaryTextures: []
|
||||
spritePackingTag:
|
||||
pSDRemoveMatte: 0
|
||||
pSDShowRemoveMatteOption: 0
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,8 @@
|
||||
fileFormatVersion: 2
|
||||
guid: afac13c76cd0741e4b5af60059fba0e8
|
||||
folderAsset: yes
|
||||
DefaultImporter:
|
||||
externalObjects: {}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,8 @@
|
||||
fileFormatVersion: 2
|
||||
guid: f72a409037e7942fc86acf5dcd9f4716
|
||||
folderAsset: yes
|
||||
DefaultImporter:
|
||||
externalObjects: {}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,130 @@
|
||||
using Unity.Collections;
|
||||
using UnityEngine;
|
||||
using UnityEngine.Animations;
|
||||
using UnityEngine.Animations.Rigging;
|
||||
|
||||
namespace UnityEditor.Animations.Rigging
|
||||
{
|
||||
/// <summary>
|
||||
/// The MultiAim inverse constraint job.
|
||||
/// </summary>
|
||||
[Unity.Burst.BurstCompile]
|
||||
public struct MultiAimInverseConstraintJob : IWeightedAnimationJob
|
||||
{
|
||||
const float k_Epsilon = 1e-5f;
|
||||
|
||||
/// <summary>The Transform handle for the constrained object Transform.</summary>
|
||||
public ReadOnlyTransformHandle driven;
|
||||
/// <summary>The Transform handle for the constrained object parent Transform.</summary>
|
||||
public ReadOnlyTransformHandle drivenParent;
|
||||
/// <summary>The post-rotation offset applied to the constrained object.</summary>
|
||||
public Vector3Property drivenOffset;
|
||||
|
||||
/// <summary>List of Transform handles for the source objects.</summary>
|
||||
public NativeArray<ReadWriteTransformHandle> sourceTransforms;
|
||||
/// <summary>List of weights for the source objects.</summary>
|
||||
public NativeArray<PropertyStreamHandle> sourceWeights;
|
||||
/// <summary>List of offsets to apply to source rotations if maintainOffset is enabled.</summary>
|
||||
public NativeArray<Quaternion> sourceOffsets;
|
||||
|
||||
/// <summary>Buffer used to store weights during job execution.</summary>
|
||||
public NativeArray<float> weightBuffer;
|
||||
|
||||
/// <summary>Local axis of the constrained object Transform.</summary>
|
||||
public Vector3 aimAxis;
|
||||
|
||||
/// <inheritdoc />
|
||||
public FloatProperty jobWeight { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Defines what to do when processing the root motion.
|
||||
/// </summary>
|
||||
/// <param name="stream">The animation stream to work on.</param>
|
||||
public void ProcessRootMotion(AnimationStream stream) { }
|
||||
|
||||
/// <summary>
|
||||
/// Defines what to do when processing the animation.
|
||||
/// </summary>
|
||||
/// <param name="stream">The animation stream to work on.</param>
|
||||
public void ProcessAnimation(AnimationStream stream)
|
||||
{
|
||||
jobWeight.Set(stream, 1f);
|
||||
|
||||
var lRot = driven.GetLocalRotation(stream);
|
||||
var offset = drivenOffset.Get(stream);
|
||||
|
||||
if (Vector3.Dot(offset, offset) > 0f)
|
||||
lRot *= Quaternion.Inverse(Quaternion.Euler(offset));
|
||||
|
||||
var localToWorld = Quaternion.identity;
|
||||
var wPos = driven.GetPosition(stream);
|
||||
if (drivenParent.IsValid(stream))
|
||||
localToWorld = drivenParent.GetRotation(stream);
|
||||
|
||||
for (int i = 0; i < sourceTransforms.Length; ++i)
|
||||
{
|
||||
sourceWeights[i].SetFloat(stream, 1f);
|
||||
|
||||
var sourceTransform = sourceTransforms[i];
|
||||
|
||||
sourceTransform.SetPosition(stream, wPos + localToWorld * sourceOffsets[i] * lRot * aimAxis);
|
||||
|
||||
// Required to update handles with binding info.
|
||||
sourceTransforms[i] = sourceTransform;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// The MultiAim inverse constraint job binder.
|
||||
/// </summary>
|
||||
/// <typeparam name="T">The constraint data type</typeparam>
|
||||
public class MultiAimInverseConstraintJobBinder<T> : AnimationJobBinder<MultiAimInverseConstraintJob, T>
|
||||
where T : struct, IAnimationJobData, IMultiAimConstraintData
|
||||
{
|
||||
/// <inheritdoc />
|
||||
public override MultiAimInverseConstraintJob Create(Animator animator, ref T data, Component component)
|
||||
{
|
||||
var job = new MultiAimInverseConstraintJob();
|
||||
|
||||
job.driven = ReadOnlyTransformHandle.Bind(animator, data.constrainedObject);
|
||||
job.drivenParent = ReadOnlyTransformHandle.Bind(animator, data.constrainedObject.parent);
|
||||
job.drivenOffset = Vector3Property.Bind(animator, component, data.offsetVector3Property);
|
||||
job.aimAxis = data.aimAxis;
|
||||
|
||||
WeightedTransformArray sourceObjects = data.sourceObjects;
|
||||
|
||||
WeightedTransformArrayBinder.BindReadWriteTransforms(animator, component, sourceObjects, out job.sourceTransforms);
|
||||
WeightedTransformArrayBinder.BindWeights(animator, component, sourceObjects, data.sourceObjectsProperty, out job.sourceWeights);
|
||||
|
||||
job.sourceOffsets = new NativeArray<Quaternion>(sourceObjects.Count, Allocator.Persistent, NativeArrayOptions.UninitializedMemory);
|
||||
for (int i = 0; i < sourceObjects.Count; ++i)
|
||||
{
|
||||
if (data.maintainOffset)
|
||||
{
|
||||
var aimDirection = data.constrainedObject.rotation * data.aimAxis;
|
||||
var dataToSource = sourceObjects[i].transform.position - data.constrainedObject.position;
|
||||
var rot = QuaternionExt.FromToRotation(dataToSource, aimDirection);
|
||||
job.sourceOffsets[i] = Quaternion.Inverse(rot);
|
||||
}
|
||||
else
|
||||
{
|
||||
job.sourceOffsets[i] = Quaternion.identity;
|
||||
}
|
||||
}
|
||||
|
||||
job.weightBuffer = new NativeArray<float>(sourceObjects.Count, Allocator.Persistent, NativeArrayOptions.UninitializedMemory);
|
||||
|
||||
return job;
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public override void Destroy(MultiAimInverseConstraintJob job)
|
||||
{
|
||||
job.sourceTransforms.Dispose();
|
||||
job.sourceWeights.Dispose();
|
||||
job.sourceOffsets.Dispose();
|
||||
job.weightBuffer.Dispose();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 05face438934c204d87b0e772c7c0a71
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,116 @@
|
||||
using Unity.Collections;
|
||||
using UnityEngine;
|
||||
using UnityEngine.Animations;
|
||||
using UnityEngine.Animations.Rigging;
|
||||
|
||||
namespace UnityEditor.Animations.Rigging
|
||||
{
|
||||
/// <summary>
|
||||
/// The MultiParent inverse constraint job.
|
||||
/// </summary>
|
||||
[Unity.Burst.BurstCompile]
|
||||
public struct MultiParentInverseConstraintJob : IWeightedAnimationJob
|
||||
{
|
||||
const float k_Epsilon = 1e-5f;
|
||||
|
||||
/// <summary>The Transform handle for the constrained object Transform.</summary>
|
||||
public ReadOnlyTransformHandle driven;
|
||||
/// <summary>The Transform handle for the constrained object parent Transform.</summary>
|
||||
public ReadOnlyTransformHandle drivenParent;
|
||||
|
||||
/// <summary>List of Transform handles for the source objects.</summary>
|
||||
public NativeArray<ReadWriteTransformHandle> sourceTransforms;
|
||||
/// <summary>List of weights for the source objects.</summary>
|
||||
public NativeArray<PropertyStreamHandle> sourceWeights;
|
||||
/// <summary>List of offsets to apply to source rotations if maintainOffset is enabled.</summary>
|
||||
public NativeArray<AffineTransform> sourceOffsets;
|
||||
|
||||
/// <inheritdoc />
|
||||
public FloatProperty jobWeight { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Defines what to do when processing the root motion.
|
||||
/// </summary>
|
||||
/// <param name="stream">The animation stream to work on.</param>
|
||||
public void ProcessRootMotion(AnimationStream stream) { }
|
||||
|
||||
/// <summary>
|
||||
/// Defines what to do when processing the animation.
|
||||
/// </summary>
|
||||
/// <param name="stream">The animation stream to work on.</param>
|
||||
public void ProcessAnimation(AnimationStream stream)
|
||||
{
|
||||
jobWeight.Set(stream, 1f);
|
||||
|
||||
driven.GetGlobalTR(stream, out Vector3 currentWPos, out Quaternion currentWRot);
|
||||
var drivenTx = new AffineTransform(currentWPos, currentWRot);
|
||||
|
||||
for (int i = 0; i < sourceTransforms.Length; ++i)
|
||||
{
|
||||
sourceWeights[i].SetFloat(stream, 1f);
|
||||
|
||||
var sourceTransform = sourceTransforms[i];
|
||||
sourceTransform.GetGlobalTR(stream, out var sourcePosition, out var sourceRotation);
|
||||
|
||||
var result = drivenTx;
|
||||
result *= sourceOffsets[i];
|
||||
|
||||
sourceTransform.SetGlobalTR(stream, result.translation, result.rotation);
|
||||
sourceTransforms[i] = sourceTransform;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// The MultiParent inverse constraint job binder.
|
||||
/// </summary>
|
||||
/// <typeparam name="T">The constraint data type</typeparam>
|
||||
public class MultiParentInverseConstraintJobBinder<T> : AnimationJobBinder<MultiParentInverseConstraintJob, T>
|
||||
where T : struct, IAnimationJobData, IMultiParentConstraintData
|
||||
{
|
||||
/// <inheritdoc />
|
||||
public override MultiParentInverseConstraintJob Create(Animator animator, ref T data, Component component)
|
||||
{
|
||||
var job = new MultiParentInverseConstraintJob();
|
||||
|
||||
job.driven = ReadOnlyTransformHandle.Bind(animator, data.constrainedObject);
|
||||
job.drivenParent = ReadOnlyTransformHandle.Bind(animator, data.constrainedObject.parent);
|
||||
|
||||
WeightedTransformArray sourceObjects = data.sourceObjects;
|
||||
|
||||
WeightedTransformArrayBinder.BindReadWriteTransforms(animator, component, sourceObjects, out job.sourceTransforms);
|
||||
WeightedTransformArrayBinder.BindWeights(animator, component, sourceObjects, data.sourceObjectsProperty, out job.sourceWeights);
|
||||
|
||||
job.sourceOffsets = new NativeArray<AffineTransform>(sourceObjects.Count, Allocator.Persistent, NativeArrayOptions.UninitializedMemory);
|
||||
|
||||
var drivenTx = new AffineTransform(data.constrainedObject.position, data.constrainedObject.rotation);
|
||||
for (int i = 0; i < sourceObjects.Count; ++i)
|
||||
{
|
||||
var sourceTransform = sourceObjects[i].transform;
|
||||
|
||||
var srcTx = new AffineTransform(sourceTransform.position, sourceTransform.rotation);
|
||||
var srcOffset = AffineTransform.identity;
|
||||
var tmp = srcTx.InverseMul(drivenTx);
|
||||
|
||||
if (data.maintainPositionOffset)
|
||||
srcOffset.translation = tmp.translation;
|
||||
if (data.maintainRotationOffset)
|
||||
srcOffset.rotation = tmp.rotation;
|
||||
|
||||
srcOffset = srcOffset.Inverse();
|
||||
|
||||
job.sourceOffsets[i] = srcOffset;
|
||||
}
|
||||
|
||||
return job;
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public override void Destroy(MultiParentInverseConstraintJob job)
|
||||
{
|
||||
job.sourceTransforms.Dispose();
|
||||
job.sourceWeights.Dispose();
|
||||
job.sourceOffsets.Dispose();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 288c55302720e3e498d76fcd7909373d
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,116 @@
|
||||
using Unity.Collections;
|
||||
using UnityEngine;
|
||||
using UnityEngine.Animations;
|
||||
using UnityEngine.Animations.Rigging;
|
||||
|
||||
namespace UnityEditor.Animations.Rigging
|
||||
{
|
||||
/// <summary>
|
||||
/// The MultiPosition inverse constraint job.
|
||||
/// </summary>
|
||||
[Unity.Burst.BurstCompile]
|
||||
public struct MultiPositionInverseConstraintJob : IWeightedAnimationJob
|
||||
{
|
||||
const float k_Epsilon = 1e-5f;
|
||||
|
||||
/// <summary>The Transform handle for the constrained object Transform.</summary>
|
||||
public ReadOnlyTransformHandle driven;
|
||||
/// <summary>The Transform handle for the constrained object parent Transform.</summary>
|
||||
public ReadOnlyTransformHandle drivenParent;
|
||||
/// <summary>The post-translation offset applied to the constrained object.</summary>
|
||||
public Vector3Property drivenOffset;
|
||||
|
||||
/// <summary>List of Transform handles for the source objects.</summary>
|
||||
public NativeArray<ReadWriteTransformHandle> sourceTransforms;
|
||||
/// <summary>List of weights for the source objects.</summary>
|
||||
public NativeArray<PropertyStreamHandle> sourceWeights;
|
||||
/// <summary>List of offsets to apply to source rotations if maintainOffset is enabled.</summary>
|
||||
public NativeArray<Vector3> sourceOffsets;
|
||||
|
||||
/// <inheritdoc />
|
||||
public FloatProperty jobWeight { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Defines what to do when processing the root motion.
|
||||
/// </summary>
|
||||
/// <param name="stream">The animation stream to work on.</param>
|
||||
public void ProcessRootMotion(AnimationStream stream) { }
|
||||
|
||||
/// <summary>
|
||||
/// Defines what to do when processing the animation.
|
||||
/// </summary>
|
||||
/// <param name="stream">The animation stream to work on.</param>
|
||||
public void ProcessAnimation(AnimationStream stream)
|
||||
{
|
||||
jobWeight.Set(stream, 1f);
|
||||
|
||||
var parentTx = new AffineTransform();
|
||||
if (drivenParent.IsValid(stream))
|
||||
{
|
||||
drivenParent.GetGlobalTR(stream, out Vector3 parentWPos, out Quaternion parentWRot);
|
||||
parentTx = new AffineTransform(parentWPos, parentWRot);
|
||||
}
|
||||
|
||||
var drivenPos = driven.GetPosition(stream);
|
||||
drivenPos = parentTx.InverseTransform(drivenPos);
|
||||
|
||||
var offset = drivenOffset.Get(stream);
|
||||
|
||||
var lPos = drivenPos - offset;
|
||||
|
||||
var wPos = parentTx.Transform(lPos);
|
||||
for (int i = 0; i < sourceTransforms.Length; ++i)
|
||||
{
|
||||
sourceWeights[i].SetFloat(stream, 1f);
|
||||
|
||||
ReadWriteTransformHandle sourceTransform = sourceTransforms[i];
|
||||
|
||||
sourceTransform.SetPosition(stream, wPos - sourceOffsets[i]);
|
||||
|
||||
// Required to update handles with binding info.
|
||||
sourceTransforms[i] = sourceTransform;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// The MultiPosition inverse constraint job binder.
|
||||
/// </summary>
|
||||
/// <typeparam name="T">The constraint data type</typeparam>
|
||||
public class MultiPositionInverseConstraintJobBinder<T> : AnimationJobBinder<MultiPositionInverseConstraintJob, T>
|
||||
where T : struct, IAnimationJobData, IMultiPositionConstraintData
|
||||
{
|
||||
/// <inheritdoc />
|
||||
public override MultiPositionInverseConstraintJob Create(Animator animator, ref T data, Component component)
|
||||
{
|
||||
var job = new MultiPositionInverseConstraintJob();
|
||||
|
||||
job.driven = ReadOnlyTransformHandle.Bind(animator, data.constrainedObject);
|
||||
job.drivenParent = ReadOnlyTransformHandle.Bind(animator, data.constrainedObject.parent);
|
||||
job.drivenOffset = Vector3Property.Bind(animator, component, data.offsetVector3Property);
|
||||
|
||||
WeightedTransformArray sourceObjects = data.sourceObjects;
|
||||
|
||||
WeightedTransformArrayBinder.BindReadWriteTransforms(animator, component, sourceObjects, out job.sourceTransforms);
|
||||
WeightedTransformArrayBinder.BindWeights(animator, component, sourceObjects, data.sourceObjectsProperty, out job.sourceWeights);
|
||||
|
||||
job.sourceOffsets = new NativeArray<Vector3>(sourceObjects.Count, Allocator.Persistent, NativeArrayOptions.UninitializedMemory);
|
||||
|
||||
Vector3 drivenPos = data.constrainedObject.position;
|
||||
for (int i = 0; i < sourceObjects.Count; ++i)
|
||||
{
|
||||
job.sourceOffsets[i] = data.maintainOffset ? (drivenPos - sourceObjects[i].transform.position) : Vector3.zero;
|
||||
}
|
||||
|
||||
return job;
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public override void Destroy(MultiPositionInverseConstraintJob job)
|
||||
{
|
||||
job.sourceTransforms.Dispose();
|
||||
job.sourceWeights.Dispose();
|
||||
job.sourceOffsets.Dispose();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: dd9bd1ef777641d4b8ec163f15579bf2
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,96 @@
|
||||
using UnityEngine;
|
||||
using UnityEngine.Animations;
|
||||
using UnityEngine.Animations.Rigging;
|
||||
using Unity.Collections;
|
||||
|
||||
namespace UnityEditor.Animations.Rigging
|
||||
{
|
||||
/// <summary>
|
||||
/// The MultiReferential inverse constraint job.
|
||||
/// </summary>
|
||||
[Unity.Burst.BurstCompile]
|
||||
public struct MultiReferentialInverseConstraintJob : IWeightedAnimationJob
|
||||
{
|
||||
/// <summary>The list of Transforms that are affected by the specified driver.</summary>
|
||||
public NativeArray<ReadWriteTransformHandle> sources;
|
||||
/// <summary>List of AffineTransform to apply to driven source objects.</summary>
|
||||
public NativeArray<AffineTransform> offsetTx;
|
||||
|
||||
/// <inheritdoc />
|
||||
public FloatProperty jobWeight { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Defines what to do when processing the root motion.
|
||||
/// </summary>
|
||||
/// <param name="stream">The animation stream to work on.</param>
|
||||
public void ProcessRootMotion(AnimationStream stream) { }
|
||||
|
||||
/// <summary>
|
||||
/// Defines what to do when processing the animation.
|
||||
/// </summary>
|
||||
/// <param name="stream">The animation stream to work on.</param>
|
||||
public void ProcessAnimation(AnimationStream stream)
|
||||
{
|
||||
jobWeight.Set(stream, 1f);
|
||||
|
||||
sources[0].GetGlobalTR(stream, out Vector3 driverWPos, out Quaternion driverWRot);
|
||||
var driverTx = new AffineTransform(driverWPos, driverWRot);
|
||||
|
||||
int offset = 0;
|
||||
for (int i = 1; i < sources.Length; ++i)
|
||||
{
|
||||
var tx = driverTx * offsetTx[offset];
|
||||
|
||||
var src = sources[i];
|
||||
src.GetGlobalTR(stream, out Vector3 srcWPos, out Quaternion srcWRot);
|
||||
src.SetGlobalTR(stream, tx.translation, tx.rotation);
|
||||
offset++;
|
||||
|
||||
sources[i] = src;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// The MultiReferential inverse constraint job binder.
|
||||
/// </summary>
|
||||
/// <typeparam name="T">The constraint data type</typeparam>
|
||||
public class MultiReferentialInverseConstraintJobBinder<T> : AnimationJobBinder<MultiReferentialInverseConstraintJob, T>
|
||||
where T : struct, IAnimationJobData, IMultiReferentialConstraintData
|
||||
{
|
||||
/// <inheritdoc />
|
||||
public override MultiReferentialInverseConstraintJob Create(Animator animator, ref T data, Component component)
|
||||
{
|
||||
var job = new MultiReferentialInverseConstraintJob();
|
||||
|
||||
var sources = data.sourceObjects;
|
||||
job.sources = new NativeArray<ReadWriteTransformHandle>(sources.Length, Allocator.Persistent, NativeArrayOptions.UninitializedMemory);
|
||||
job.offsetTx = new NativeArray<AffineTransform>(sources.Length - 1, Allocator.Persistent, NativeArrayOptions.UninitializedMemory);
|
||||
|
||||
var sourceBindTx = new AffineTransform[sources.Length];
|
||||
|
||||
for (int i = 0; i < sources.Length; ++i)
|
||||
{
|
||||
job.sources[i] = ReadWriteTransformHandle.Bind(animator, sources[i].transform);
|
||||
sourceBindTx[i] = new AffineTransform(sources[i].position, sources[i].rotation);
|
||||
}
|
||||
|
||||
int offset = 0;
|
||||
var invDriverTx = sourceBindTx[0].Inverse();
|
||||
for (int i = 1; i < sourceBindTx.Length; ++i)
|
||||
{
|
||||
job.offsetTx[offset] = invDriverTx * sourceBindTx[i];
|
||||
offset++;
|
||||
}
|
||||
|
||||
return job;
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public override void Destroy(MultiReferentialInverseConstraintJob job)
|
||||
{
|
||||
job.sources.Dispose();
|
||||
job.offsetTx.Dispose();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 07e9ec99cb928a0428b3391e587dfa9c
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,120 @@
|
||||
using Unity.Collections;
|
||||
using UnityEngine;
|
||||
using UnityEngine.Animations;
|
||||
using UnityEngine.Animations.Rigging;
|
||||
|
||||
namespace UnityEditor.Animations.Rigging
|
||||
{
|
||||
/// <summary>
|
||||
/// The MultiRotation inverse constraint job.
|
||||
/// </summary>
|
||||
[Unity.Burst.BurstCompile]
|
||||
public struct MultiRotationInverseConstraintJob : IWeightedAnimationJob
|
||||
{
|
||||
const float k_Epsilon = 1e-5f;
|
||||
|
||||
/// <summary>The Transform handle for the constrained object Transform.</summary>
|
||||
public ReadOnlyTransformHandle driven;
|
||||
/// <summary>The Transform handle for the constrained object parent Transform.</summary>
|
||||
public ReadOnlyTransformHandle drivenParent;
|
||||
/// <summary>The post-rotation offset applied to the constrained object.</summary>
|
||||
public Vector3Property drivenOffset;
|
||||
|
||||
/// <summary>List of Transform handles for the source objects.</summary>
|
||||
public NativeArray<ReadWriteTransformHandle> sourceTransforms;
|
||||
/// <summary>List of weights for the source objects.</summary>
|
||||
public NativeArray<PropertyStreamHandle> sourceWeights;
|
||||
/// <summary>List of offsets to apply to source rotations if maintainOffset is enabled.</summary>
|
||||
public NativeArray<Quaternion> sourceOffsets;
|
||||
|
||||
/// <summary>Buffer used to store weights during job execution.</summary>
|
||||
public NativeArray<float> weightBuffer;
|
||||
|
||||
/// <inheritdoc />
|
||||
public FloatProperty jobWeight { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Defines what to do when processing the root motion.
|
||||
/// </summary>
|
||||
/// <param name="stream">The animation stream to work on.</param>
|
||||
public void ProcessRootMotion(AnimationStream stream) { }
|
||||
|
||||
/// <summary>
|
||||
/// Defines what to do when processing the animation.
|
||||
/// </summary>
|
||||
/// <param name="stream">The animation stream to work on.</param>
|
||||
public void ProcessAnimation(AnimationStream stream)
|
||||
{
|
||||
jobWeight.Set(stream, 1f);
|
||||
|
||||
var lRot = driven.GetLocalRotation(stream);
|
||||
var offset = drivenOffset.Get(stream);
|
||||
|
||||
if (Vector3.Dot(offset, offset) > 0f)
|
||||
lRot *= Quaternion.Inverse(Quaternion.Euler(offset));
|
||||
|
||||
var wRot = lRot;
|
||||
if (drivenParent.IsValid(stream))
|
||||
{
|
||||
wRot = drivenParent.GetRotation(stream) * wRot;
|
||||
}
|
||||
|
||||
for (int i = 0; i < sourceTransforms.Length; ++i)
|
||||
{
|
||||
sourceWeights[i].SetFloat(stream, 1f);
|
||||
|
||||
ReadWriteTransformHandle sourceTransform = sourceTransforms[i];
|
||||
|
||||
sourceTransform.SetRotation(stream, wRot * sourceOffsets[i]);
|
||||
|
||||
// Required to update handles with binding info.
|
||||
sourceTransforms[i] = sourceTransform;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// The MultiRotation inverse constraint job binder.
|
||||
/// </summary>
|
||||
/// <typeparam name="T">The constraint data type</typeparam>
|
||||
public class MultiRotationInverseConstraintJobBinder<T> : AnimationJobBinder<MultiRotationInverseConstraintJob, T>
|
||||
where T : struct, IAnimationJobData, IMultiRotationConstraintData
|
||||
{
|
||||
/// <inheritdoc />
|
||||
public override MultiRotationInverseConstraintJob Create(Animator animator, ref T data, Component component)
|
||||
{
|
||||
var job = new MultiRotationInverseConstraintJob();
|
||||
|
||||
job.driven = ReadOnlyTransformHandle.Bind(animator, data.constrainedObject);
|
||||
job.drivenParent = ReadOnlyTransformHandle.Bind(animator, data.constrainedObject.parent);
|
||||
job.drivenOffset = Vector3Property.Bind(animator, component, data.offsetVector3Property);
|
||||
|
||||
WeightedTransformArray sourceObjects = data.sourceObjects;
|
||||
|
||||
WeightedTransformArrayBinder.BindReadWriteTransforms(animator, component, sourceObjects, out job.sourceTransforms);
|
||||
WeightedTransformArrayBinder.BindWeights(animator, component, sourceObjects, data.sourceObjectsProperty, out job.sourceWeights);
|
||||
|
||||
job.sourceOffsets = new NativeArray<Quaternion>(sourceObjects.Count, Allocator.Persistent, NativeArrayOptions.UninitializedMemory);
|
||||
|
||||
job.weightBuffer = new NativeArray<float>(sourceObjects.Count, Allocator.Persistent, NativeArrayOptions.UninitializedMemory);
|
||||
|
||||
Quaternion drivenRotInv = Quaternion.Inverse(data.constrainedObject.rotation);
|
||||
for (int i = 0; i < sourceObjects.Count; ++i)
|
||||
{
|
||||
job.sourceOffsets[i] = data.maintainOffset ?
|
||||
(drivenRotInv * sourceObjects[i].transform.rotation) : Quaternion.identity;
|
||||
}
|
||||
|
||||
return job;
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public override void Destroy(MultiRotationInverseConstraintJob job)
|
||||
{
|
||||
job.sourceTransforms.Dispose();
|
||||
job.sourceWeights.Dispose();
|
||||
job.sourceOffsets.Dispose();
|
||||
job.weightBuffer.Dispose();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: e68f0e2daa979074da79ea4fa6e40660
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,74 @@
|
||||
using UnityEngine;
|
||||
using UnityEngine.Animations;
|
||||
using UnityEngine.Animations.Rigging;
|
||||
|
||||
namespace UnityEditor.Animations.Rigging
|
||||
{
|
||||
/// <summary>
|
||||
/// The TwistChain inverse constraint job.
|
||||
/// </summary>
|
||||
[Unity.Burst.BurstCompile]
|
||||
public struct TwistChainInverseConstraintJob : IWeightedAnimationJob
|
||||
{
|
||||
/// <summary>The Transform handle for the root Transform of the chain.</summary>
|
||||
public ReadOnlyTransformHandle root;
|
||||
/// <summary>The Transform handle for the tip Transform of the chain.</summary>
|
||||
public ReadOnlyTransformHandle tip;
|
||||
|
||||
/// <summary>The Transform handle for the root target Transform.</summary>
|
||||
public ReadWriteTransformHandle rootTarget;
|
||||
/// <summary>The Transform handle for the tip target Transform.</summary>
|
||||
public ReadWriteTransformHandle tipTarget;
|
||||
|
||||
/// <inheritdoc />
|
||||
public FloatProperty jobWeight { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Defines what to do when processing the root motion.
|
||||
/// </summary>
|
||||
/// <param name="stream">The animation stream to work on.</param>
|
||||
public void ProcessRootMotion(AnimationStream stream) { }
|
||||
|
||||
/// <summary>
|
||||
/// Defines what to do when processing the animation.
|
||||
/// </summary>
|
||||
/// <param name="stream">The animation stream to work on.</param>
|
||||
public void ProcessAnimation(AnimationStream stream)
|
||||
{
|
||||
jobWeight.Set(stream, 1f);
|
||||
|
||||
rootTarget.SetPosition(stream, root.GetPosition(stream));
|
||||
rootTarget.SetRotation(stream, root.GetRotation(stream));
|
||||
|
||||
tipTarget.SetPosition(stream, tip.GetPosition(stream));
|
||||
tipTarget.SetRotation(stream, tip.GetRotation(stream));
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// The TwistChain inverse constraint job binder.
|
||||
/// </summary>
|
||||
/// <typeparam name="T">The constraint data type</typeparam>
|
||||
public class TwistChainInverseConstraintJobBinder<T> : AnimationJobBinder<TwistChainInverseConstraintJob, T>
|
||||
where T : struct, IAnimationJobData, ITwistChainConstraintData
|
||||
{
|
||||
/// <inheritdoc />
|
||||
public override TwistChainInverseConstraintJob Create(Animator animator, ref T data, Component component)
|
||||
{
|
||||
var job = new TwistChainInverseConstraintJob();
|
||||
|
||||
job.root = ReadOnlyTransformHandle.Bind(animator, data.root);
|
||||
job.tip = ReadOnlyTransformHandle.Bind(animator, data.tip);
|
||||
|
||||
job.rootTarget = ReadWriteTransformHandle.Bind(animator, data.rootTarget);
|
||||
job.tipTarget = ReadWriteTransformHandle.Bind(animator, data.tipTarget);
|
||||
|
||||
return job;
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public override void Destroy(TwistChainInverseConstraintJob job)
|
||||
{
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 2c669908f1bcf4a829cb78b6398d008f
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,99 @@
|
||||
using UnityEngine;
|
||||
using UnityEngine.Animations;
|
||||
using UnityEngine.Animations.Rigging;
|
||||
|
||||
namespace UnityEditor.Animations.Rigging
|
||||
{
|
||||
/// <summary>
|
||||
/// The TwoBoneIK inverse constraint job.
|
||||
/// </summary>
|
||||
[Unity.Burst.BurstCompile]
|
||||
public struct TwoBoneIKInverseConstraintJob : IWeightedAnimationJob
|
||||
{
|
||||
const float k_SqrEpsilon = 1e-8f;
|
||||
|
||||
/// <summary>The transform handle for the root transform.</summary>
|
||||
public ReadOnlyTransformHandle root;
|
||||
/// <summary>The transform handle for the mid transform.</summary>
|
||||
public ReadOnlyTransformHandle mid;
|
||||
/// <summary>The transform handle for the tip transform.</summary>
|
||||
public ReadOnlyTransformHandle tip;
|
||||
|
||||
/// <summary>The transform handle for the hint transform.</summary>
|
||||
public ReadWriteTransformHandle hint;
|
||||
/// <summary>The transform handle for the target transform.</summary>
|
||||
public ReadWriteTransformHandle target;
|
||||
|
||||
/// <summary>The offset applied to the target transform if maintainTargetPositionOffset or maintainTargetRotationOffset is enabled.</summary>
|
||||
public AffineTransform targetOffset;
|
||||
|
||||
/// <summary>The weight for which target position has an effect on IK calculations. This is a value in between 0 and 1.</summary>
|
||||
public FloatProperty targetPositionWeight;
|
||||
/// <summary>The weight for which target rotation has an effect on IK calculations. This is a value in between 0 and 1.</summary>
|
||||
public FloatProperty targetRotationWeight;
|
||||
/// <summary>The weight for which hint transform has an effect on IK calculations. This is a value in between 0 and 1.</summary>
|
||||
public FloatProperty hintWeight;
|
||||
|
||||
/// <inheritdoc />
|
||||
public FloatProperty jobWeight { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Defines what to do when processing the root motion.
|
||||
/// </summary>
|
||||
/// <param name="stream">The animation stream to work on.</param>
|
||||
public void ProcessRootMotion(AnimationStream stream) { }
|
||||
|
||||
/// <summary>
|
||||
/// Defines what to do when processing the animation.
|
||||
/// </summary>
|
||||
/// <param name="stream">The animation stream to work on.</param>
|
||||
public void ProcessAnimation(AnimationStream stream)
|
||||
{
|
||||
jobWeight.Set(stream, 1f);
|
||||
|
||||
AnimationRuntimeUtils.InverseSolveTwoBoneIK(stream, root, mid, tip, target, hint,
|
||||
targetPositionWeight.Get(stream),
|
||||
targetRotationWeight.Get(stream),
|
||||
hintWeight.Get(stream), targetOffset);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// The TwoBoneIK inverse constraint job binder.
|
||||
/// </summary>
|
||||
/// <typeparam name="T">The constraint data type</typeparam>
|
||||
public class TwoBoneIKInverseConstraintJobBinder<T> : AnimationJobBinder<TwoBoneIKInverseConstraintJob, T>
|
||||
where T : struct, IAnimationJobData, ITwoBoneIKConstraintData
|
||||
{
|
||||
/// <inheritdoc />
|
||||
public override TwoBoneIKInverseConstraintJob Create(Animator animator, ref T data, Component component)
|
||||
{
|
||||
var job = new TwoBoneIKInverseConstraintJob();
|
||||
|
||||
job.root = ReadOnlyTransformHandle.Bind(animator, data.root);
|
||||
job.mid = ReadOnlyTransformHandle.Bind(animator, data.mid);
|
||||
job.tip = ReadOnlyTransformHandle.Bind(animator, data.tip);
|
||||
job.target = ReadWriteTransformHandle.Bind(animator, data.target);
|
||||
|
||||
if (data.hint != null)
|
||||
job.hint = ReadWriteTransformHandle.Bind(animator, data.hint);
|
||||
|
||||
job.targetOffset = AffineTransform.identity;
|
||||
if (data.maintainTargetPositionOffset)
|
||||
job.targetOffset.translation = -(data.tip.position - data.target.position);
|
||||
if (data.maintainTargetRotationOffset)
|
||||
job.targetOffset.rotation = Quaternion.Inverse(data.tip.rotation) * data.target.rotation;
|
||||
|
||||
job.targetPositionWeight = FloatProperty.Bind(animator, component, data.targetPositionWeightFloatProperty);
|
||||
job.targetRotationWeight = FloatProperty.Bind(animator, component, data.targetRotationWeightFloatProperty);
|
||||
job.hintWeight = FloatProperty.Bind(animator, component, data.hintWeightFloatProperty);
|
||||
|
||||
return job;
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public override void Destroy(TwoBoneIKInverseConstraintJob job)
|
||||
{
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 97b56b4e0dccdff47b19d995fcc12954
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,8 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 63607c45d964e47a18e3197ffb465217
|
||||
folderAsset: yes
|
||||
DefaultImporter:
|
||||
externalObjects: {}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,24 @@
|
||||
using UnityEngine.Animations.Rigging;
|
||||
|
||||
namespace UnityEditor.Animations.Rigging
|
||||
{
|
||||
/// <summary>
|
||||
/// MultiAim inverse constraint.
|
||||
/// </summary>
|
||||
/// <seealso cref="MultiAimConstraint"/>
|
||||
[InverseRigConstraint(typeof(MultiAimConstraint))]
|
||||
public class MultiAimInverseConstraint : OverrideRigConstraint<
|
||||
MultiAimConstraint,
|
||||
MultiAimInverseConstraintJob,
|
||||
MultiAimConstraintData,
|
||||
MultiAimInverseConstraintJobBinder<MultiAimConstraintData>
|
||||
>
|
||||
{
|
||||
/// <summary>
|
||||
/// Constructor.
|
||||
/// </summary>
|
||||
/// <param name="baseConstraint">Base constraint to override.</param>
|
||||
public MultiAimInverseConstraint(MultiAimConstraint baseConstraint) : base(baseConstraint) {}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 55179714ce28f4fad97dbe8831d7b7b5
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,25 @@
|
||||
using UnityEngine;
|
||||
using UnityEngine.Animations;
|
||||
using UnityEngine.Animations.Rigging;
|
||||
|
||||
namespace UnityEditor.Animations.Rigging
|
||||
{
|
||||
/// <summary>
|
||||
/// MultiParent inverse constraint.
|
||||
/// </summary>
|
||||
/// <seealso cref="MultiParentConstraint"/>
|
||||
[InverseRigConstraint(typeof(MultiParentConstraint))]
|
||||
public class MultiParentInverseConstraint : OverrideRigConstraint<
|
||||
MultiParentConstraint,
|
||||
MultiParentInverseConstraintJob,
|
||||
MultiParentConstraintData,
|
||||
MultiParentInverseConstraintJobBinder<MultiParentConstraintData>
|
||||
>
|
||||
{
|
||||
/// <summary>
|
||||
/// Constructor.
|
||||
/// </summary>
|
||||
/// <param name="baseConstraint">Base constraint to override.</param>
|
||||
public MultiParentInverseConstraint(MultiParentConstraint baseConstraint) : base(baseConstraint) { }
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: b0bc68cc00b8ce547b1cc869a707c8b9
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {fileID: 2800000, guid: ca41524ec86f0d84ab5675c9622cc1a2, type: 3}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,24 @@
|
||||
using UnityEngine.Animations.Rigging;
|
||||
|
||||
namespace UnityEditor.Animations.Rigging
|
||||
{
|
||||
/// <summary>
|
||||
/// MultiPosition inverse constraint.
|
||||
/// </summary>
|
||||
/// <seealso cref="MultiPositionConstraint"/>
|
||||
[InverseRigConstraint(typeof(MultiPositionConstraint))]
|
||||
public class MultiPositionInverseConstraint : OverrideRigConstraint<
|
||||
MultiPositionConstraint,
|
||||
MultiPositionInverseConstraintJob,
|
||||
MultiPositionConstraintData,
|
||||
MultiPositionInverseConstraintJobBinder<MultiPositionConstraintData>
|
||||
>
|
||||
{
|
||||
/// <summary>
|
||||
/// Constructor.
|
||||
/// </summary>
|
||||
/// <param name="baseConstraint">Base constraint to override.</param>
|
||||
public MultiPositionInverseConstraint(MultiPositionConstraint baseConstraint) : base(baseConstraint) {}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: f565b137dff19490c925f69f8fbfb243
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,23 @@
|
||||
using UnityEngine.Animations.Rigging;
|
||||
|
||||
namespace UnityEditor.Animations.Rigging
|
||||
{
|
||||
/// <summary>
|
||||
/// MultiReferential inverse constraint.
|
||||
/// </summary>
|
||||
[InverseRigConstraint(typeof(MultiReferentialConstraint))]
|
||||
public class MultiReferentialInverseConstraint : OverrideRigConstraint<
|
||||
MultiReferentialConstraint,
|
||||
MultiReferentialInverseConstraintJob,
|
||||
MultiReferentialConstraintData,
|
||||
MultiReferentialInverseConstraintJobBinder<MultiReferentialConstraintData>
|
||||
>
|
||||
{
|
||||
/// <summary>
|
||||
/// Constructor.
|
||||
/// </summary>
|
||||
/// <param name="baseConstraint">Base constraint to override.</param>
|
||||
public MultiReferentialInverseConstraint(MultiReferentialConstraint baseConstraint) : base(baseConstraint) {}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 246edcdada8bcb14cb045a083c910774
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,24 @@
|
||||
using UnityEngine.Animations.Rigging;
|
||||
|
||||
namespace UnityEditor.Animations.Rigging
|
||||
{
|
||||
/// <summary>
|
||||
/// MultiRotation inverse constraint.
|
||||
/// </summary>
|
||||
/// <seealso cref="MultiRotationConstraint"/>
|
||||
[InverseRigConstraint(typeof(MultiRotationConstraint))]
|
||||
public class MultiRotationInverseConstraint : OverrideRigConstraint<
|
||||
MultiRotationConstraint,
|
||||
MultiRotationInverseConstraintJob,
|
||||
MultiRotationConstraintData,
|
||||
MultiRotationInverseConstraintJobBinder<MultiRotationConstraintData>
|
||||
>
|
||||
{
|
||||
/// <summary>
|
||||
/// Constructor.
|
||||
/// </summary>
|
||||
/// <param name="baseConstraint">Base constraint to override.</param>
|
||||
public MultiRotationInverseConstraint(MultiRotationConstraint baseConstraint) : base(baseConstraint) {}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 34672f6d93a624041a3e076be94601e6
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,24 @@
|
||||
using UnityEngine.Animations.Rigging;
|
||||
|
||||
namespace UnityEditor.Animations.Rigging
|
||||
{
|
||||
/// <summary>
|
||||
/// TwistChain inverse constraint.
|
||||
/// </summary>
|
||||
/// <seealso cref="TwistChainConstraint"/>
|
||||
[InverseRigConstraint(typeof(TwistChainConstraint))]
|
||||
public class TwistChainInverseConstraint : OverrideRigConstraint<
|
||||
TwistChainConstraint,
|
||||
TwistChainInverseConstraintJob,
|
||||
TwistChainConstraintData,
|
||||
TwistChainInverseConstraintJobBinder<TwistChainConstraintData>
|
||||
>
|
||||
{
|
||||
/// <summary>
|
||||
/// Constructor.
|
||||
/// </summary>
|
||||
/// <param name="baseConstraint">Base constraint to override.</param>
|
||||
public TwistChainInverseConstraint(TwistChainConstraint baseConstraint) : base(baseConstraint) {}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 84300ca1d515442388c563e2508c8745
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,24 @@
|
||||
using UnityEngine.Animations.Rigging;
|
||||
|
||||
namespace UnityEditor.Animations.Rigging
|
||||
{
|
||||
/// <summary>
|
||||
/// TwoBone IK inverse constraint.
|
||||
/// </summary>
|
||||
/// <seealso cref="TwoBoneIKConstraint"/>
|
||||
[InverseRigConstraint(typeof(TwoBoneIKConstraint))]
|
||||
public class TwoBoneIKInverseConstraint : OverrideRigConstraint<
|
||||
TwoBoneIKConstraint,
|
||||
TwoBoneIKInverseConstraintJob,
|
||||
TwoBoneIKConstraintData,
|
||||
TwoBoneIKInverseConstraintJobBinder<TwoBoneIKConstraintData>
|
||||
>
|
||||
{
|
||||
/// <summary>
|
||||
/// Constructor.
|
||||
/// </summary>
|
||||
/// <param name="baseConstraint">Base constraint to override.</param>
|
||||
public TwoBoneIKInverseConstraint(TwoBoneIKConstraint baseConstraint) : base(baseConstraint) {}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 62e695bb417d14bdf9e0b26e15e8617c
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,8 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 6549b8b30f0b56746bf9d9a2f6061663
|
||||
folderAsset: yes
|
||||
DefaultImporter:
|
||||
externalObjects: {}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,67 @@
|
||||
Shader "Hidden/BoneHandles"
|
||||
{
|
||||
Properties
|
||||
{
|
||||
_Color ("Color", Color) = (1,1,1,1)
|
||||
}
|
||||
SubShader
|
||||
{
|
||||
Tags { "Queue" = "Transparent" "RenderType"="Transparent" "ForceSupported" = "True" }
|
||||
|
||||
Lighting Off
|
||||
Blend SrcAlpha OneMinusSrcAlpha
|
||||
ZWrite Off
|
||||
Cull Back
|
||||
Fog { Mode Off }
|
||||
ZTest Always
|
||||
|
||||
Pass
|
||||
{
|
||||
CGPROGRAM
|
||||
#pragma vertex vert
|
||||
#pragma fragment frag
|
||||
#pragma multi_compile_instancing
|
||||
#pragma multi_compile __ WIRE_ON
|
||||
|
||||
#include "UnityCG.cginc"
|
||||
|
||||
struct appdata
|
||||
{
|
||||
float4 vertex : POSITION;
|
||||
UNITY_VERTEX_INPUT_INSTANCE_ID
|
||||
};
|
||||
|
||||
struct v2f
|
||||
{
|
||||
float4 vertex : SV_POSITION;
|
||||
UNITY_VERTEX_INPUT_INSTANCE_ID
|
||||
};
|
||||
|
||||
UNITY_INSTANCING_BUFFER_START(Props)
|
||||
UNITY_DEFINE_INSTANCED_PROP(float4, _Color)
|
||||
UNITY_INSTANCING_BUFFER_END(Props)
|
||||
|
||||
v2f vert (appdata v)
|
||||
{
|
||||
v2f o;
|
||||
UNITY_SETUP_INSTANCE_ID(v);
|
||||
UNITY_TRANSFER_INSTANCE_ID(v, o);
|
||||
o.vertex = UnityObjectToClipPos(v.vertex);
|
||||
return o;
|
||||
}
|
||||
|
||||
fixed4 frag (v2f i) : SV_Target
|
||||
{
|
||||
UNITY_SETUP_INSTANCE_ID(i);
|
||||
fixed4 col = UNITY_ACCESS_INSTANCED_PROP(Props, _Color);
|
||||
|
||||
#ifdef WIRE_ON
|
||||
col.a = 1.0f;
|
||||
#endif
|
||||
|
||||
return col;
|
||||
}
|
||||
ENDCG
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,9 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 55fcd8cae15234dbeba59eb9603e7779
|
||||
ShaderImporter:
|
||||
externalObjects: {}
|
||||
defaultTextures: []
|
||||
nonModifiableTextures: []
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,66 @@
|
||||
Shader "Hidden/RigEffector"
|
||||
{
|
||||
Properties
|
||||
{
|
||||
_Color ("Color", Color) = (1,1,1,1)
|
||||
_Dither ("Dithering", float) = 0
|
||||
_HandleZTest ("_HandleZTest", Int) = 8
|
||||
}
|
||||
|
||||
SubShader
|
||||
{
|
||||
Tags
|
||||
{
|
||||
"IgnoreProjector"="True" "RenderType"="Transparent"
|
||||
}
|
||||
Lighting Off
|
||||
ZTest [_HandleZTest]
|
||||
ZWrite Off
|
||||
Cull Off
|
||||
Blend SrcAlpha OneMinusSrcAlpha
|
||||
|
||||
Pass
|
||||
{
|
||||
CGPROGRAM
|
||||
#pragma vertex vert
|
||||
#pragma fragment frag
|
||||
#include "UnityCG.cginc"
|
||||
|
||||
float4 _Color;
|
||||
float _Dither;
|
||||
|
||||
struct appdata
|
||||
{
|
||||
float4 vertex : POSITION;
|
||||
};
|
||||
|
||||
struct v2f
|
||||
{
|
||||
float4 pos : SV_POSITION;
|
||||
};
|
||||
|
||||
v2f vert (appdata v)
|
||||
{
|
||||
v2f o;
|
||||
|
||||
// https://www.opengl.org/discussion_boards/showthread.php/166719-Clean-Wireframe-Over-Solid-Mesh
|
||||
o.pos = float4(UnityObjectToViewPos(v.vertex.xyz), 1);
|
||||
o.pos.xyz *= .99;
|
||||
o.pos = mul(UNITY_MATRIX_P, o.pos);
|
||||
|
||||
return o;
|
||||
}
|
||||
|
||||
half4 frag (v2f i) : COLOR
|
||||
{
|
||||
i.pos.xy = floor(i.pos.xy * 1) * .5;
|
||||
float checker = -frac(i.pos.x + i.pos.y);
|
||||
clip(lerp(1, checker, _Dither));
|
||||
|
||||
return _Color;
|
||||
}
|
||||
|
||||
ENDCG
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,9 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 48843bad95d12480bb1ee7af0ef00b87
|
||||
ShaderImporter:
|
||||
externalObjects: {}
|
||||
defaultTextures: []
|
||||
nonModifiableTextures: []
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,8 @@
|
||||
fileFormatVersion: 2
|
||||
guid: d2ea9e88bb7d74ffd85330b997e5273c
|
||||
folderAsset: yes
|
||||
DefaultImporter:
|
||||
externalObjects: {}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user