Add ultimate xr
This commit is contained in:
138
Assets/UltimateXR/Editor/Animation/IK/UxrCcdIKSolverEditor.cs
Normal file
138
Assets/UltimateXR/Editor/Animation/IK/UxrCcdIKSolverEditor.cs
Normal file
@@ -0,0 +1,138 @@
|
||||
// --------------------------------------------------------------------------------------------------------------------
|
||||
// <copyright file="UxrCcdIKSolverEditor.cs" company="VRMADA">
|
||||
// Copyright (c) VRMADA, All rights reserved.
|
||||
// </copyright>
|
||||
// --------------------------------------------------------------------------------------------------------------------
|
||||
using UltimateXR.Animation.IK;
|
||||
using UnityEditor;
|
||||
using UnityEngine;
|
||||
|
||||
namespace UltimateXR.Editor.Animation.IK
|
||||
{
|
||||
/// <summary>
|
||||
/// Custom inspector for <see cref="UxrCcdIKSolver" />. Also draws handles in the scene window.
|
||||
/// </summary>
|
||||
[CustomEditor(typeof(UxrCcdIKSolver))]
|
||||
public class UxrCcdIKSolverEditor : UnityEditor.Editor
|
||||
{
|
||||
#region Unity
|
||||
|
||||
/// <summary>
|
||||
/// Initializes the link count variable and hooks the Update() method to monitor changes on the component's link count.
|
||||
/// </summary>
|
||||
private void OnEnable()
|
||||
{
|
||||
_linkCount = ((UxrCcdIKSolver)serializedObject.targetObject).Links.Count;
|
||||
EditorApplication.update += EditorApplication_Updated;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Removes the Update hook.
|
||||
/// </summary>
|
||||
private void OnDisable()
|
||||
{
|
||||
EditorApplication.update -= EditorApplication_Updated;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Draws the IK scene handles.
|
||||
/// </summary>
|
||||
private void OnSceneGUI()
|
||||
{
|
||||
UxrCcdIKSolver solverCcd = target as UxrCcdIKSolver;
|
||||
|
||||
if (solverCcd == null || solverCcd.Links == null)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
if (Application.isPlaying == false)
|
||||
{
|
||||
solverCcd.ComputeLinkData();
|
||||
}
|
||||
|
||||
int index = 0;
|
||||
|
||||
foreach (UxrCcdLink link in solverCcd.Links)
|
||||
{
|
||||
if (link.Bone == null)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
Vector3 normal = link.Bone.TransformDirection(link.RotationAxis1);
|
||||
Handles.color = new Color(Mathf.Abs(link.RotationAxis1.x), Mathf.Abs(link.RotationAxis1.y), Mathf.Abs(link.RotationAxis1.z), 0.3f);
|
||||
|
||||
float angle1Min = link.Axis1HasLimits ? link.Axis1AngleMin : -180.0f;
|
||||
float angle1Max = link.Axis1HasLimits ? link.Axis1AngleMax : 180.0f;
|
||||
|
||||
Handles.DrawSolidArc(link.Bone.position,
|
||||
normal,
|
||||
Quaternion.AngleAxis(angle1Min - link.Angle1, normal) * link.Bone.TransformDirection(link.LocalSpaceAxis1ZeroAngleVector),
|
||||
angle1Max - angle1Min,
|
||||
link.LinkLength * 0.5f);
|
||||
Handles.color = new Color(Mathf.Abs(link.RotationAxis1.x), Mathf.Abs(link.RotationAxis1.y), Mathf.Abs(link.RotationAxis1.z), 1.0f);
|
||||
Handles.DrawLine(link.Bone.position, link.Bone.position + 0.6f * link.LinkLength * link.Bone.TransformDirection(link.LocalSpaceAxis1ZeroAngleVector));
|
||||
|
||||
if (link.Constraint == UxrCcdConstraintType.TwoAxes)
|
||||
{
|
||||
float angle2Min = link.Axis2HasLimits ? link.Axis2AngleMin : -180.0f;
|
||||
float angle2Max = link.Axis2HasLimits ? link.Axis2AngleMax : 180.0f;
|
||||
|
||||
normal = link.Bone.TransformDirection(link.RotationAxis2);
|
||||
Handles.color = new Color(Mathf.Abs(link.RotationAxis2.x), Mathf.Abs(link.RotationAxis2.y), Mathf.Abs(link.RotationAxis2.z), 0.3f);
|
||||
Handles.DrawSolidArc(link.Bone.position,
|
||||
normal,
|
||||
Quaternion.AngleAxis(angle2Min + link.Angle2, normal) * link.Bone.TransformDirection(link.LocalSpaceAxis2ZeroAngleVector),
|
||||
angle2Max - angle2Min,
|
||||
link.LinkLength * 0.5f);
|
||||
Handles.color = new Color(Mathf.Abs(link.RotationAxis2.x), Mathf.Abs(link.RotationAxis2.y), Mathf.Abs(link.RotationAxis2.z), 1.0f);
|
||||
Handles.DrawLine(link.Bone.position, link.Bone.position + 0.6f * link.LinkLength * link.Bone.TransformDirection(link.LocalSpaceAxis2ZeroAngleVector));
|
||||
}
|
||||
|
||||
if (index == 0 && link.Bone != null && solverCcd.EndEffector != null && solverCcd.Goal != null)
|
||||
{
|
||||
Handles.color = Color.magenta;
|
||||
Handles.DrawLine(link.Bone.position, solverCcd.EndEffector.position);
|
||||
Handles.DrawLine(solverCcd.EndEffector.position, solverCcd.Goal.position);
|
||||
}
|
||||
|
||||
index++;
|
||||
}
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region Event Handling Methods
|
||||
|
||||
/// <summary>
|
||||
/// Monitors for changes in the link count so that if new ones are added they are assigned default parameters.
|
||||
/// Unity does not support assigning default values to new elements added. This is the reason we need to do this.
|
||||
/// </summary>
|
||||
private void EditorApplication_Updated()
|
||||
{
|
||||
UxrCcdIKSolver solverCcd = target as UxrCcdIKSolver;
|
||||
|
||||
if (solverCcd != null && solverCcd.Links.Count != _linkCount)
|
||||
{
|
||||
if (solverCcd.Links.Count > _linkCount)
|
||||
{
|
||||
for (int i = _linkCount; i < solverCcd.Links.Count; ++i)
|
||||
{
|
||||
solverCcd.SetLinkDefaultValues(i);
|
||||
}
|
||||
}
|
||||
|
||||
_linkCount = solverCcd.Links.Count;
|
||||
}
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region Private Types & Data
|
||||
|
||||
private int _linkCount;
|
||||
|
||||
#endregion
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,13 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 3af81a625b57a0747b423d4b3523c429
|
||||
timeCreated: 1511875957
|
||||
licenseType: Pro
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
210
Assets/UltimateXR/Editor/Animation/IK/UxrIKBodySettingsDrawer.cs
Normal file
210
Assets/UltimateXR/Editor/Animation/IK/UxrIKBodySettingsDrawer.cs
Normal file
@@ -0,0 +1,210 @@
|
||||
// --------------------------------------------------------------------------------------------------------------------
|
||||
// <copyright file="UxrIKBodySettingsDrawer.cs" company="VRMADA">
|
||||
// Copyright (c) VRMADA, All rights reserved.
|
||||
// </copyright>
|
||||
// --------------------------------------------------------------------------------------------------------------------
|
||||
using UltimateXR.Animation.IK;
|
||||
using UltimateXR.Avatar;
|
||||
using UltimateXR.Avatar.Controllers;
|
||||
using UltimateXR.Core;
|
||||
using UnityEditor;
|
||||
using UnityEngine;
|
||||
|
||||
namespace UltimateXR.Editor.Animation.IK
|
||||
{
|
||||
/// <summary>
|
||||
/// Custom inspector for <see cref="UxrBodyIKSettings" />.
|
||||
/// </summary>
|
||||
[CustomPropertyDrawer(typeof(UxrBodyIKSettings))]
|
||||
public class UxrIKBodySettingsDrawer : PropertyDrawer
|
||||
{
|
||||
#region Public Types & Data
|
||||
|
||||
public const string PropertyLockBodyPivot = "_lockBodyPivot";
|
||||
public const string PropertyBodyPivotRotationSpeed = "_bodyPivotRotationSpeed";
|
||||
public const string PropertyHeadFreeRangeBend = "_headFreeRangeBend";
|
||||
public const string PropertyHeadFreeRangeTorsion = "_headFreeRangeTorsion";
|
||||
public const string PropertyNeckHeadBalance = "_neckHeadBalance";
|
||||
public const string PropertySpineBend = "_spineBend";
|
||||
public const string PropertySpineTorsion = "_spineTorsion";
|
||||
public const string PropertyChestBend = "_chestBend";
|
||||
public const string PropertyChestTorsion = "_chestTorsion";
|
||||
public const string PropertyUpperChestBend = "_upperChestBend";
|
||||
public const string PropertyUpperChestTorsion = "_upperChestTorsion";
|
||||
public const string PropertyNeckBaseHeight = "_neckBaseHeight";
|
||||
public const string PropertyNeckForwardOffset = "_neckForwardOffset";
|
||||
public const string PropertyEyesBaseHeight = "_eyesBaseHeight";
|
||||
public const string PropertyEyesForwardOffset = "_eyesForwardOffset";
|
||||
|
||||
#endregion
|
||||
|
||||
#region Public Overrides PropertyDrawer
|
||||
|
||||
/// <summary>
|
||||
/// Gets the height in pixels for the given serialized property targeting a <see cref="UxrBodyIKSettings" />.
|
||||
/// </summary>
|
||||
/// <param name="property">Serialized property</param>
|
||||
/// <param name="label">UI label</param>
|
||||
/// <returns>Height in pixels</returns>
|
||||
public override float GetPropertyHeight(SerializedProperty property, GUIContent label)
|
||||
{
|
||||
if (ShowNeckProperties(property))
|
||||
{
|
||||
return 15 * EditorGUIUtility.singleLineHeight;
|
||||
}
|
||||
return 13 * EditorGUIUtility.singleLineHeight;
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region Unity
|
||||
|
||||
/// <summary>
|
||||
/// Draws an <see cref="UxrBodyIKSettings" /> serialized property and handles input.
|
||||
/// </summary>
|
||||
/// <param name="position">Position where to draw the property</param>
|
||||
/// <param name="property">Serialized property</param>
|
||||
/// <param name="label">UI label</param>
|
||||
public override void OnGUI(Rect position, SerializedProperty property, GUIContent label)
|
||||
{
|
||||
EditorGUI.BeginProperty(position, label, property);
|
||||
|
||||
int line = 0;
|
||||
|
||||
UxrAvatar avatar = ((MonoBehaviour)property.serializedObject.targetObject).GetComponent<UxrAvatar>();
|
||||
property.FindPropertyRelative(PropertyLockBodyPivot).boolValue = EditorGUI.Toggle(GetRect(position, line++, -1), ContentLockBodyPivot, property.FindPropertyRelative(PropertyLockBodyPivot).boolValue);
|
||||
EditorGUI.Slider(GetRect(position, line++, -1), property.FindPropertyRelative(PropertyBodyPivotRotationSpeed), 0.0f, 1.0f, ContentBodyPivotRotationSpeed);
|
||||
EditorGUI.Slider(GetRect(position, line++, -1), property.FindPropertyRelative(PropertyHeadFreeRangeBend), 0.0f, 180.0f, ContentHeadFreeRangeBend);
|
||||
EditorGUI.Slider(GetRect(position, line++, -1), property.FindPropertyRelative(PropertyHeadFreeRangeTorsion), 0.0f, 180.0f, ContentHeadFreeRangeTorsion);
|
||||
EditorGUI.Slider(GetRect(position, line++, -1), property.FindPropertyRelative(PropertyNeckHeadBalance), 0.0f, 1.0f, ContentNeckHeadBalance);
|
||||
EditorGUI.Slider(GetRect(position, line++, -1), property.FindPropertyRelative(PropertySpineBend), 0.0f, 1.0f, ContentSpineBend);
|
||||
EditorGUI.Slider(GetRect(position, line++, -1), property.FindPropertyRelative(PropertySpineTorsion), 0.0f, 1.0f, ContentSpineTorsion);
|
||||
EditorGUI.Slider(GetRect(position, line++, -1), property.FindPropertyRelative(PropertyChestBend), 0.0f, 1.0f, ContentChestBend);
|
||||
EditorGUI.Slider(GetRect(position, line++, -1), property.FindPropertyRelative(PropertyChestTorsion), 0.0f, 1.0f, ContentChestTorsion);
|
||||
EditorGUI.Slider(GetRect(position, line++, -1), property.FindPropertyRelative(PropertyUpperChestBend), 0.0f, 1.0f, ContentUpperChestBend);
|
||||
EditorGUI.Slider(GetRect(position, line++, -1), property.FindPropertyRelative(PropertyUpperChestTorsion), 0.0f, 1.0f, ContentUpperChestTorsion);
|
||||
|
||||
if (ShowNeckProperties(property))
|
||||
{
|
||||
EditorGUILayout.BeginHorizontal();
|
||||
EditorGUI.PropertyField(GetRect(position, line++, 0), property.FindPropertyRelative(PropertyNeckBaseHeight), ContentNeckBaseHeight);
|
||||
EditorGUILayout.EndHorizontal();
|
||||
|
||||
EditorGUILayout.BeginHorizontal();
|
||||
EditorGUI.PropertyField(GetRect(position, line++, 0), property.FindPropertyRelative(PropertyNeckForwardOffset), ContentNeckForwardOffset);
|
||||
EditorGUILayout.EndHorizontal();
|
||||
}
|
||||
|
||||
EditorGUILayout.BeginHorizontal();
|
||||
EditorGUI.PropertyField(GetRect(position, line, 0), property.FindPropertyRelative(PropertyEyesBaseHeight), ContentEyesBaseHeight);
|
||||
bool useAvatarEyesPressedBaseHeight = GUI.Button(GetRect(position, line, 1), new GUIContent("Use Avatar Eyes"));
|
||||
EditorGUILayout.EndHorizontal();
|
||||
|
||||
if (useAvatarEyesPressedBaseHeight)
|
||||
{
|
||||
if (avatar.AvatarRig.Head.LeftEye == null || avatar.AvatarRig.Head.RightEye == null)
|
||||
{
|
||||
EditorUtility.DisplayDialog("Assign field first", "The avatar component Rig field has eye(s) missing. Try to assign the value manually and use the eye gizmos for guidance.", UxrConstants.Editor.Ok);
|
||||
GUIUtility.ExitGUI();
|
||||
}
|
||||
else
|
||||
{
|
||||
property.FindPropertyRelative(PropertyEyesBaseHeight).floatValue = (avatar.AvatarRig.Head.LeftEye.position.y + avatar.AvatarRig.Head.RightEye.position.y) * 0.5f - avatar.transform.position.y;
|
||||
}
|
||||
}
|
||||
|
||||
line++;
|
||||
|
||||
EditorGUILayout.BeginHorizontal();
|
||||
EditorGUI.PropertyField(GetRect(position, line, 0), property.FindPropertyRelative(PropertyEyesForwardOffset), ContentEyesForwardOffset);
|
||||
EditorGUILayout.EndHorizontal();
|
||||
|
||||
bool useAvatarEyesPressedForwardOffset = GUI.Button(GetRect(position, line, 1), new GUIContent("Use Avatar Eyes"));
|
||||
|
||||
if (useAvatarEyesPressedForwardOffset)
|
||||
{
|
||||
if (avatar.AvatarRig.Head.LeftEye == null || avatar.AvatarRig.Head.RightEye == null)
|
||||
{
|
||||
EditorUtility.DisplayDialog("Assign field first", "The avatar component Rig field has eye(s) missing. Try to assign the value manually and use the eye gizmos for guidance.", UxrConstants.Editor.Ok);
|
||||
GUIUtility.ExitGUI();
|
||||
}
|
||||
else
|
||||
{
|
||||
Vector3 eyeLeft = avatar.transform.InverseTransformPoint(avatar.AvatarRig.Head.LeftEye.position);
|
||||
Vector3 eyeRight = avatar.transform.InverseTransformPoint(avatar.AvatarRig.Head.RightEye.position);
|
||||
property.FindPropertyRelative(PropertyEyesForwardOffset).floatValue = (eyeLeft.z + eyeRight.z) * 0.5f + 0.02f;
|
||||
}
|
||||
}
|
||||
|
||||
EditorGUI.EndProperty();
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region Private Methods
|
||||
|
||||
/// <summary>
|
||||
/// Checks whether to show the neck properties of the serialized <see cref="UxrBodyIKSettings" />.
|
||||
/// </summary>
|
||||
/// <param name="property">Serialized property</param>
|
||||
/// <returns>Whether to show the neck properties</returns>
|
||||
private static bool ShowNeckProperties(SerializedProperty property)
|
||||
{
|
||||
UxrAvatarController controller = property.serializedObject.targetObject as UxrAvatarController;
|
||||
|
||||
if (controller == null)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
if (!controller.TryGetComponent<UxrAvatar>(out var avatar))
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
return avatar.AvatarRig.Head.Neck == null;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the rect for a given line in the property, since it will have multiple lines.
|
||||
/// </summary>
|
||||
/// <param name="position">Serialized property draw position</param>
|
||||
/// <param name="line">Line index</param>
|
||||
/// <param name="column">Column index</param>
|
||||
/// <returns>Rect to draw the given line in</returns>
|
||||
private static Rect GetRect(Rect position, int line, int column)
|
||||
{
|
||||
const int buttonWidth = 150;
|
||||
const int margin = 5;
|
||||
|
||||
return column switch
|
||||
{
|
||||
-1 => new Rect(position.x, position.y + EditorGUIUtility.singleLineHeight * line, position.width, EditorGUIUtility.singleLineHeight),
|
||||
0 => new Rect(position.x, position.y + EditorGUIUtility.singleLineHeight * line, position.width - buttonWidth - margin, EditorGUIUtility.singleLineHeight),
|
||||
_ => new Rect(position.x + position.width - buttonWidth, position.y + EditorGUIUtility.singleLineHeight * line, buttonWidth, EditorGUIUtility.singleLineHeight)
|
||||
};
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region Private Types & Data
|
||||
|
||||
private GUIContent ContentLockBodyPivot { get; } = new GUIContent("Lock Body Pivot", "For applications that require the avatar to remain in a fixed position");
|
||||
private GUIContent ContentBodyPivotRotationSpeed { get; } = new GUIContent("Body Pivot Rotation Speed", "The speed the body will twist to keep up with the head orientation");
|
||||
private GUIContent ContentHeadFreeRangeBend { get; } = new GUIContent("Head Free Range Bend", "The amount of degrees the head can rotate up and down without requiring support from the neck and bones below");
|
||||
private GUIContent ContentHeadFreeRangeTorsion { get; } = new GUIContent("Head Free Range Torsion", "The amount of degrees the head can rotate left and right without requiring support from the neck and bones below");
|
||||
private GUIContent ContentNeckHeadBalance { get; } = new GUIContent("Neck-Head Balance", "The balance between the neck and the head when solving the head orientation. Lower values will have the neck play a bigger role, while higher values will make the head play a bigger role");
|
||||
private GUIContent ContentSpineBend { get; } = new GUIContent("Spine Bend", "The amount of weight the spine will apply to solve up/down rotations");
|
||||
private GUIContent ContentSpineTorsion { get; } = new GUIContent("Spine Torsion", "The amount of weight the spine will apply to solve left/right rotations");
|
||||
private GUIContent ContentChestBend { get; } = new GUIContent("Chest Bend", "The amount of weight the chest will apply to solve up/down rotations");
|
||||
private GUIContent ContentChestTorsion { get; } = new GUIContent("Chest Torsion", "The amount of weight the chest will apply to solve left/right rotations");
|
||||
private GUIContent ContentUpperChestBend { get; } = new GUIContent("Upper Chest Bend", "The amount of weight the upper chest will apply to solve up/down rotations");
|
||||
private GUIContent ContentUpperChestTorsion { get; } = new GUIContent("Upper Chest Torsion", "The amount of weight the upper chest will apply to solve left/right rotations");
|
||||
private GUIContent ContentNeckBaseHeight { get; } = new GUIContent("Neck Base Height", "The height on the avatar where the base of the neck is located. The neck base will be drawn on the scene window as a white disc gizmo");
|
||||
private GUIContent ContentNeckForwardOffset { get; } = new GUIContent("Neck Forward Offset", "The forward offset from the avatar pivot where the neck is located. The neck base will be drawn on the scene window as a white disc gizmo");
|
||||
private GUIContent ContentEyesBaseHeight { get; } = new GUIContent("Eyes Base Height", "The height on the avatar where the eyes are located. The eye positions will be drawn on the scene window as white disc gizmos");
|
||||
private GUIContent ContentEyesForwardOffset { get; } = new GUIContent("Eyes Forward Offset", "The forward offset from the avatar pivot where the eyes are located. The eye positions will be drawn on the scene window as white disc gizmos");
|
||||
|
||||
#endregion
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,13 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 2121affa9bada5149845f3cfef8e8d4a
|
||||
timeCreated: 1512027976
|
||||
licenseType: Pro
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,141 @@
|
||||
// --------------------------------------------------------------------------------------------------------------------
|
||||
// <copyright file="UxrIKSolverCcdLinkDrawer.cs" company="VRMADA">
|
||||
// Copyright (c) VRMADA, All rights reserved.
|
||||
// </copyright>
|
||||
// --------------------------------------------------------------------------------------------------------------------
|
||||
using UltimateXR.Animation.IK;
|
||||
using UnityEditor;
|
||||
using UnityEngine;
|
||||
|
||||
namespace UltimateXR.Editor.Animation.IK
|
||||
{
|
||||
/// <summary>
|
||||
/// Custom property drawer for <see cref="UxrCcdLink" />.
|
||||
/// </summary>
|
||||
[CustomPropertyDrawer(typeof(UxrCcdLink))]
|
||||
public class UxrIKSolverCcdLinkDrawer : PropertyDrawer
|
||||
{
|
||||
#region Public Overrides PropertyDrawer
|
||||
|
||||
/// <summary>
|
||||
/// Returns the height in pixels required to draw the property.
|
||||
/// </summary>
|
||||
/// <param name="property">Serialized property to draw</param>
|
||||
/// <param name="label">UI label</param>
|
||||
/// <returns>Height in pixels</returns>
|
||||
public override float GetPropertyHeight(SerializedProperty property, GUIContent label)
|
||||
{
|
||||
int lines = 7;
|
||||
|
||||
if (property.FindPropertyRelative(PropertyAxis1HasLimits).boolValue)
|
||||
{
|
||||
lines += 2;
|
||||
}
|
||||
|
||||
int enumIndex = property.FindPropertyRelative(PropertyConstraint).enumValueIndex;
|
||||
|
||||
if (enumIndex == (int)UxrCcdConstraintType.TwoAxes)
|
||||
{
|
||||
if (property.FindPropertyRelative(PropertyAxis2HasLimits).boolValue)
|
||||
{
|
||||
lines += 4;
|
||||
}
|
||||
else
|
||||
{
|
||||
lines += 2;
|
||||
}
|
||||
}
|
||||
|
||||
return lines * EditorGUIUtility.singleLineHeight;
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region Unity
|
||||
|
||||
/// <summary>
|
||||
/// Draws the inspector and handles input.
|
||||
/// </summary>
|
||||
/// <param name="position">Position where to draw the serialized property</param>
|
||||
/// <param name="property">Serialized property</param>
|
||||
/// <param name="label">UI label</param>
|
||||
public override void OnGUI(Rect position, SerializedProperty property, GUIContent label)
|
||||
{
|
||||
EditorGUI.BeginProperty(position, label, property);
|
||||
|
||||
EditorGUI.PrefixLabel(position, GUIUtility.GetControlID(FocusType.Passive), label);
|
||||
EditorGUI.indentLevel += 1;
|
||||
|
||||
int line = 1;
|
||||
|
||||
property.FindPropertyRelative(PropertyWeight).floatValue = EditorGUI.Slider(UxrEditorUtils.GetRect(position, line++),
|
||||
ContentWeight,
|
||||
property.FindPropertyRelative(PropertyWeight).floatValue,
|
||||
0.0f,
|
||||
1.0f);
|
||||
|
||||
EditorGUI.PropertyField(UxrEditorUtils.GetRect(position, line++), property.FindPropertyRelative(PropertyBone), ContentBone);
|
||||
|
||||
EditorGUI.PropertyField(UxrEditorUtils.GetRect(position, line++), property.FindPropertyRelative(PropertyConstraint), ContentConstraint);
|
||||
EditorGUI.PropertyField(UxrEditorUtils.GetRect(position, line++), property.FindPropertyRelative(PropertyRotationAxis1), ContentRotationAxis1);
|
||||
EditorGUI.PropertyField(UxrEditorUtils.GetRect(position, line++), property.FindPropertyRelative(PropertyAxis1HasLimits), ContentAxis1HasLimits);
|
||||
|
||||
if (property.FindPropertyRelative(PropertyAxis1HasLimits).boolValue)
|
||||
{
|
||||
EditorGUI.PropertyField(UxrEditorUtils.GetRect(position, line++), property.FindPropertyRelative(PropertyAxis1AngleMin), ContentAxis1AngleMin);
|
||||
EditorGUI.PropertyField(UxrEditorUtils.GetRect(position, line++), property.FindPropertyRelative(PropertyAxis1AngleMax), ContentAxis1AngleMax);
|
||||
}
|
||||
|
||||
int enumIndex = property.FindPropertyRelative(PropertyConstraint).enumValueIndex;
|
||||
|
||||
if (enumIndex == (int)UxrCcdConstraintType.TwoAxes)
|
||||
{
|
||||
EditorGUI.PropertyField(UxrEditorUtils.GetRect(position, line++), property.FindPropertyRelative(PropertyRotationAxis2), ContentRotationAxis2);
|
||||
EditorGUI.PropertyField(UxrEditorUtils.GetRect(position, line++), property.FindPropertyRelative(PropertyAxis2HasLimits), ContentAxis2HasLimits);
|
||||
|
||||
if (property.FindPropertyRelative(PropertyAxis2HasLimits).boolValue)
|
||||
{
|
||||
EditorGUI.PropertyField(UxrEditorUtils.GetRect(position, line++), property.FindPropertyRelative(PropertyAxis2AngleMin), ContentAxis2AngleMin);
|
||||
EditorGUI.PropertyField(UxrEditorUtils.GetRect(position, line++), property.FindPropertyRelative(PropertyAxis2AngleMax), ContentAxis2AngleMax);
|
||||
}
|
||||
}
|
||||
|
||||
EditorGUI.PropertyField(UxrEditorUtils.GetRect(position, line++), property.FindPropertyRelative(PropertyAlignToGoal), ContentAlignToGoal);
|
||||
|
||||
EditorGUI.indentLevel -= 1;
|
||||
EditorGUI.EndProperty();
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region Private Types & Data
|
||||
|
||||
private GUIContent ContentBone { get; } = new GUIContent("Bone", "");
|
||||
private GUIContent ContentWeight { get; } = new GUIContent("Weight", "");
|
||||
private GUIContent ContentConstraint { get; } = new GUIContent("Constraint", "");
|
||||
private GUIContent ContentRotationAxis1 { get; } = new GUIContent("Rotation Axis1", "");
|
||||
private GUIContent ContentRotationAxis2 { get; } = new GUIContent("Rotation Axis2", "");
|
||||
private GUIContent ContentAxis1HasLimits { get; } = new GUIContent("Axis1 Has Angle Limits", "");
|
||||
private GUIContent ContentAxis1AngleMin { get; } = new GUIContent("Axis1 Angle Min", "");
|
||||
private GUIContent ContentAxis1AngleMax { get; } = new GUIContent("Axis1 Angle Max", "");
|
||||
private GUIContent ContentAxis2HasLimits { get; } = new GUIContent("Axis2 Has Angle Limits", "");
|
||||
private GUIContent ContentAxis2AngleMin { get; } = new GUIContent("Axis2 Angle Min", "");
|
||||
private GUIContent ContentAxis2AngleMax { get; } = new GUIContent("Axis2 Angle Max", "");
|
||||
private GUIContent ContentAlignToGoal { get; } = new GUIContent("Align To Goal", "Tries to align this link to the same axes as the goal");
|
||||
|
||||
private const string PropertyBone = "_bone";
|
||||
private const string PropertyWeight = "_weight";
|
||||
private const string PropertyConstraint = "_constraint";
|
||||
private const string PropertyRotationAxis1 = "_rotationAxis1";
|
||||
private const string PropertyRotationAxis2 = "_rotationAxis2";
|
||||
private const string PropertyAxis1HasLimits = "_axis1HasLimits";
|
||||
private const string PropertyAxis1AngleMin = "_axis1AngleMin";
|
||||
private const string PropertyAxis1AngleMax = "_axis1AngleMax";
|
||||
private const string PropertyAxis2HasLimits = "_axis2HasLimits";
|
||||
private const string PropertyAxis2AngleMin = "_axis2AngleMin";
|
||||
private const string PropertyAxis2AngleMax = "_axis2AngleMax";
|
||||
private const string PropertyAlignToGoal = "_alignToGoal";
|
||||
|
||||
#endregion
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,13 @@
|
||||
fileFormatVersion: 2
|
||||
guid: f57588fb49769d4449e44e297f493eca
|
||||
timeCreated: 1512027976
|
||||
licenseType: Pro
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
Reference in New Issue
Block a user