Unity Udexreal开发插件包
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

334 lines
12 KiB

using System;
using System.Collections.Generic;
using UnityEditor;
using UnityEngine;
namespace UDE_HAND_INTERACTION
{
[CustomEditor(typeof(HandInteraction))]
public class HandInteractionEditor : Editor
{
private HandInteraction _handInteraction;
private VirtualHand virtualHand;
public HandPerfabResource _HPResource;
private Handedness _lastHandedness;
private const float GIZMO_SCALE = 0.007f;
private void Awake()
{
_handInteraction = target as HandInteraction;
}
private void OnEnable()
{
AssignMissingGhostProvider();
}
private void OnDisable()
{
DestroyGhost();
}
public override void OnInspectorGUI()
{
base.OnInspectorGUI();
_handInteraction._relativeTo = _handInteraction.transform.parent;
DrawGhostMenu(_handInteraction.HandPose);
serializedObject.ApplyModifiedProperties();
}
public void OnSceneGUI()
{
if (SceneView.currentDrawingSceneView == null)
{
return;
}
if (virtualHand == null)
{
return;
}
EditFingers();
}
private void DrawGhostMenu(HandPose handPose)
{
HandPerfabResource resource = _handInteraction._HPResource; //EditorGUILayout.ObjectField("Ghost Provider", _HPResource, typeof(HandPerfabResource), false) as HandPerfabResource;
if (virtualHand == null || _HPResource != resource || _lastHandedness != handPose.Handedness)
{
RegenerateGhost();
}
_HPResource = resource;
_lastHandedness = handPose.Handedness;
}
private void EditFingers()
{
DollHand puppet = virtualHand.GetComponent<DollHand>();
if (puppet != null && puppet.JointSets != null)
{
DrawBonesRotator(puppet.JointSets);
}
}
private void DrawBonesRotator(List<HandJointsSet> bones)
{
bool anyChanged = false;
for (int i = 0; i < FingersData.HAND_JOINT_IDS.Length; i++)
{
bool changed = false;
HandJointId joint = FingersData.HAND_JOINT_IDS[i];
HandFinger finger = FingersData.JOINT_TO_FINGER[(int)joint];
if (_handInteraction.HandPose.FingersFreedom[(int)finger] == JointFreedom.Free)
{
continue;
}
HandJointsSet jointSet = bones.Find(b => b.id == joint);
if (jointSet == null)
{
continue;
}
Transform transform = jointSet.transform;
transform.localRotation = jointSet.RotationOffset * _handInteraction.HandPose.JointRotations[i];
float scale = GIZMO_SCALE * _handInteraction.transform.lossyScale.x;
Handles.color = EditorConstants.PRIMARY_COLOR;
Quaternion entryRotation = transform.rotation;
Quaternion rotation = Handles.Disc(entryRotation, transform.position,
transform.forward, scale, false, 0);
if (rotation != entryRotation)
{
changed = true;
}
if (FingersData.HAND_JOINT_CAN_SPREAD[i])
{
Handles.color = EditorConstants.SECONDARY_COLOR;
Quaternion curlRotation = rotation;
rotation = Handles.Disc(curlRotation, transform.position,
transform.up, scale, false, 0);
if (rotation != curlRotation)
{
changed = true;
}
}
if (!changed)
{
continue;
}
transform.rotation = rotation;
Undo.RecordObject(_handInteraction, "Bone Rotation");
_handInteraction.HandPose.JointRotations[i] = jointSet.TrackedRotation;
anyChanged = true;
}
if (anyChanged)
{
EditorUtility.SetDirty(_handInteraction);
}
}
private void RegenerateGhost()
{
DestroyGhost();
CreateGhost();
}
private void CreateGhost()
{
if (_HPResource == null)
{
return;
}
Transform relativeTo = _handInteraction.RelativeTo;
VirtualHand ghostPrototype = _HPResource.GetHand(_handInteraction.HandPose.Handedness);
if(relativeTo != null)
{
virtualHand = Instantiate(ghostPrototype, _handInteraction.transform);
}
else
{
virtualHand = Instantiate(ghostPrototype);
}
virtualHand.gameObject.hideFlags = HideFlags.HideAndDontSave;
Pose relativePose = _handInteraction.RelativePose;
Pose pose = PoseManager.GlobalPoseScaled(relativeTo, relativePose);
virtualHand.SetPose(_handInteraction.HandPose, pose);
}
private void DestroyGhost()
{
if (virtualHand == null)
{
return;
}
DestroyImmediate(virtualHand.gameObject);
}
void AssignMissingGhostProvider()
{
if (_HPResource != null)
{
return;
}
TryGetDefaultResProvider(out _HPResource);
}
bool TryGetDefaultResProvider(out HandPerfabResource provider)
{
provider = null;
HandPerfabResource[] providers = Resources.FindObjectsOfTypeAll<HandPerfabResource>();
if (providers != null && providers.Length > 0)
{
provider = providers[0];
return true;
}
string[] assets = AssetDatabase.FindAssets($"t:{nameof(HandPerfabResource)}");
if (assets != null && assets.Length > 0)
{
string pathPath = AssetDatabase.GUIDToAssetPath(assets[0]);
provider = AssetDatabase.LoadAssetAtPath<HandPerfabResource>(pathPath);
}
return provider != null;
}
[MenuItem("UDE Interaction/Clear All Redundant Virtual Hand")]
static void Clear()
{
var VirtualHands = FindObjectsOfType<SkinnedMeshRenderer>();
foreach (var VirtualHand in VirtualHands)
{
if (VirtualHand.name.Split("_")[0] == "vr" && VirtualHand.transform.parent.name.Contains("(Clone)"))
{
DestroyImmediate(VirtualHand);
}
}
}
}
public class EditorConstants
{
public static readonly Color PRIMARY_COLOR = new Color(0f, 1f, 1f, 0.5f);
public static readonly Color PRIMARY_COLOR_DISABLED = new Color(0f, 1f, 1f, 0.1f);
public static readonly Color RED_COLOR = new Color(1f, 0f, 0f, 1f);
public static readonly Color YELLOW_COLOR = new Color(1f, 1f, 0f, 1f);
public static readonly Color SECONDARY_COLOR = new Color(0.5f, 0.3f, 1f, 0.5f);
public static readonly Color SECONDARY_COLOR_DISABLED = new Color(0.5f, 0.3f, 1f, 0.1f);
public static readonly float LINE_THICKNESS = 2f;
public static readonly float ROW_HEIGHT = 20f;
}
[CustomPropertyDrawer(typeof(HandPose))]
public class HandPoseEditor : PropertyDrawer
{
private bool _foldedFreedom = true;
private bool _foldedRotations = false;
public override float GetPropertyHeight(SerializedProperty property, GUIContent label)
{
float multiplier = 4;
if (_foldedFreedom)
{
multiplier += Constants.NUM_FINGERS;
}
if (_foldedRotations)
{
multiplier += FingersData.HAND_JOINT_IDS.Length;
}
return EditorConstants.ROW_HEIGHT * multiplier;
}
public override void OnGUI(Rect position, SerializedProperty property, GUIContent label)
{
EditorGUI.BeginProperty(position, label, property);
Rect labelPos = EditorGUI.PrefixLabel(position, GUIUtility.GetControlID(FocusType.Passive), label);
EditorGUI.indentLevel++;
Rect rowRect = new Rect(position.x, labelPos.y + EditorConstants.ROW_HEIGHT, position.width, EditorConstants.ROW_HEIGHT);
DrawFlagProperty<Handedness>(property, rowRect, "Handedness:", "_handedness", false);
rowRect.y += EditorConstants.ROW_HEIGHT;
rowRect = DrawFingersFreedomMenu(property, rowRect);
rowRect = DrawJointAngles(property, rowRect);
EditorGUI.indentLevel--;
EditorGUI.EndProperty();
}
private Rect DrawFingersFreedomMenu(SerializedProperty property, Rect position)
{
_foldedFreedom = EditorGUI.Foldout(position, _foldedFreedom, "Fingers Freedom", true);
position.y += EditorConstants.ROW_HEIGHT;
if (_foldedFreedom)
{
SerializedProperty fingersFreedom = property.FindPropertyRelative("_fingersFreedom");
EditorGUI.indentLevel++;
for (int i = 0; i < Constants.NUM_FINGERS; i++)
{
SerializedProperty finger = fingersFreedom.GetArrayElementAtIndex(i);
HandFinger fingerID = (HandFinger)i;
JointFreedom current = (JointFreedom)finger.intValue;
JointFreedom selected = (JointFreedom)EditorGUI.EnumPopup(position, $"{fingerID}", current);
finger.intValue = (int)selected;
position.y += EditorConstants.ROW_HEIGHT;
}
EditorGUI.indentLevel--;
}
return position;
}
private Rect DrawJointAngles(SerializedProperty property, Rect position)
{
_foldedRotations = EditorGUI.Foldout(position, _foldedRotations, "Joint Angles", true);
position.y += EditorConstants.ROW_HEIGHT;
if (_foldedRotations)
{
SerializedProperty jointRotations = property.FindPropertyRelative("_jointRotations");
EditorGUI.indentLevel++;
for (int i = 0; i < FingersData.HAND_JOINT_IDS.Length; i++)
{
SerializedProperty finger = jointRotations.GetArrayElementAtIndex(i);
HandJointId jointID = FingersData.HAND_JOINT_IDS[i];
Vector3 current = finger.quaternionValue.eulerAngles;
Vector3 rotation = EditorGUI.Vector3Field(position, $"{jointID}", current);
finger.quaternionValue = Quaternion.Euler(rotation);
position.y += EditorConstants.ROW_HEIGHT;
}
EditorGUI.indentLevel--;
}
return position;
}
private void DrawFlagProperty<TEnum>(SerializedProperty parentProperty, Rect position, string title, string fieldName, bool isFlags) where TEnum : Enum
{
SerializedProperty fieldProperty = parentProperty.FindPropertyRelative(fieldName);
TEnum value = (TEnum)Enum.ToObject(typeof(TEnum), fieldProperty.intValue);
Enum selectedValue = isFlags ?
EditorGUI.EnumFlagsField(position, title, value)
: EditorGUI.EnumPopup(position, title, value);
fieldProperty.intValue = (int)Enum.ToObject(typeof(TEnum), selectedValue);
}
}
}