Files
XRLib/Assets/HybridIK/Scripts/Main/Editor/HybridIKNodeInspector.cs

313 lines
13 KiB
C#
Raw Normal View History

2025-12-08 10:59:29 +09:00
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEditor;
[CustomEditor(typeof(HybridInverseKinematicsNode))]
public class HybridIKNodeInspector : Editor
{
private HybridInverseKinematicsNode hybridIKNode { get { return target as HybridInverseKinematicsNode; } }
List<string> boneHierarchy = new List<string>();
private int selectedIKNodeIndex = -1;
private int selectedIKKeyframe = -1;
public void DeletePoseKeyframe(int selectedPose)
{
foreach (HybridIKConstraint c in hybridIKNode.constraints)
{
if (c.positionKeys.Count > 0)
{
c.positionKeys.RemoveAt(selectedPose);
}
}
foreach (HybridIKJoint node in hybridIKNode.nodes)
{
node.keyedPositions.RemoveAt(selectedPose);
node.keyedLocalPositions.RemoveAt(selectedPose);
node.keyedRotations.RemoveAt(selectedPose);
}
selectedIKKeyframe = -1;
hybridIKNode.ResetToZeroPose();
}
public override void OnInspectorGUI()
{
if (selectedIKKeyframe >= 0)
{
if (GUILayout.Button("Select Full Chain"))
{
selectedIKKeyframe = -1;
}
if (selectedIKKeyframe >= 0)
{
GUILayout.Label("IK Keyframe " + selectedIKKeyframe.ToString() + " selected");
if (GUILayout.Button("Delete Pose Keyframe"))
{
DeletePoseKeyframe(selectedIKKeyframe);
}
return;
}
}
if (selectedIKNodeIndex >= 0)
{
HybridIKJoint selectedNode = hybridIKNode.nodes[selectedIKNodeIndex];
GUILayout.BeginHorizontal();
if (selectedNode.jointTransform != null)
{
if (GUILayout.Button("Select Joint GameObject"))
{
Selection.activeGameObject = selectedNode.jointTransform.gameObject;
}
}
if (GUILayout.Button("Select Full Chain"))
{
selectedIKNodeIndex = -1;
}
GUILayout.EndHorizontal();
if (selectedIKNodeIndex >= 0)
{
GUILayout.Label("IK Node " + selectedIKNodeIndex.ToString() + " selected");
selectedNode.jointRadius = EditorGUILayout.FloatField("Node Radius", selectedNode.jointRadius);
var oldColor = GUI.backgroundColor;
GUILayout.Label("CONSTRAINTS MODE");
GUILayout.BeginHorizontal();
if (selectedNode.enableKeyframeConstraints && !selectedNode.overrideConstraint) GUI.backgroundColor = Color.green;
if (GUILayout.Button("KEYFRAMED"))
{
selectedNode.enableKeyframeConstraints = true;
selectedNode.overrideConstraint = false;
hybridIKNode.ReprocessJoints();
}
GUI.backgroundColor = oldColor;
if (selectedNode.overrideConstraint) GUI.backgroundColor = Color.green;
if (GUILayout.Button("MANUAL CONSTRAINT"))
{
selectedNode.enableKeyframeConstraints = false;
selectedNode.overrideConstraint = true;
hybridIKNode.ReprocessJoints();
}
GUI.backgroundColor = oldColor;
if (!selectedNode.enableKeyframeConstraints && !selectedNode.overrideConstraint) GUI.backgroundColor = Color.green;
if (GUILayout.Button("NONE"))
{
selectedNode.enableKeyframeConstraints = false;
selectedNode.overrideConstraint = false;
hybridIKNode.ReprocessJoints();
}
GUILayout.EndHorizontal();
GUI.backgroundColor = oldColor;
if (selectedNode.overrideConstraint)
{
//n.position = EditorGUILayout.Vector3Field("Target Position", node.position);
selectedNode.constraint.jointTransform = selectedNode.jointTransform;
selectedNode.constraint.targetTransform = EditorGUILayout.ObjectField("Target Transform", selectedNode.constraint.targetTransform, typeof(Transform), true) as Transform;
selectedNode.constraint.constrainPosition = EditorGUILayout.Toggle("Constrain Position", selectedNode.constraint.constrainPosition);
selectedNode.constraint.constrainRotation = EditorGUILayout.Toggle("Constrain Orientation", selectedNode.constraint.constrainRotation);
}
selectedNode.enableStretch = EditorGUILayout.Toggle("Enable Stretch", selectedNode.enableStretch);
if (selectedNode.enableStretch)
{
if (selectedNode.stretchLimits == null)
{
selectedNode.stretchLimits = new HybridIKNodeStretchLimits();
}
selectedNode.stretchLimits.targetSpace = EditorGUILayout.ObjectField("Target Transform", selectedNode.stretchLimits.targetSpace, typeof(Transform), true) as Transform;
selectedNode.stretchLimits.minStretchLimits = EditorGUILayout.Vector3Field("Min Stretch Limits", selectedNode.stretchLimits.minStretchLimits);
selectedNode.stretchLimits.maxStretchLimits = EditorGUILayout.Vector3Field("Max Stretch Limits", selectedNode.stretchLimits.maxStretchLimits);
}
if (GUI.changed) EditorUtility.SetDirty(hybridIKNode);
return;
}
}
if (GUILayout.Button("Process IK Joint Chain"))
{
hybridIKNode.ResetAll();
hybridIKNode.ProcessChain();
}
if (hybridIKNode.nodes != null)
{
if (GUILayout.Button("Set Zero Rotations to Current Pose"))
{
foreach (HybridIKJoint node in hybridIKNode.nodes)
{
node.zeroRotation = node.jointTransform.localRotation;
node.zeroPosition = node.jointTransform.localPosition;
}
}
}
base.OnInspectorGUI();
if (hybridIKNode.nodes == null) return;
if (hybridIKNode.constraints == null || hybridIKNode.constraints.Count == 0)
{
hybridIKNode.constraints = new List<HybridIKConstraint>();
foreach (HybridIKJoint node in hybridIKNode.nodes)
{
node.keyedLocalPositions = new List<Vector3>();
node.keyedPositions = new List<Vector3>();
node.keyedRotations = new List<Quaternion>();
}
}
if (hybridIKNode.constraints != null)// && hybridIKNode.constraints.Count > 0)
{
//EditorGUILayout.LabelField("Keyframe Constraints", EditorStyles.boldLabel);
if (GUILayout.Button("Add Joints Pose Keyframe"))
{
List<int> keyframeState = new List<int>();
foreach(HybridIKJoint j in hybridIKNode.nodes)
{
keyframeState.Add(j.enableKeyframeConstraints ? 0 : j.overrideConstraint ? 1 : 2);
j.enableKeyframeConstraints = true; j.overrideConstraint = false;
}
hybridIKNode.ReprocessJoints();
HybridIKJoint root = hybridIKNode.nodes[0];
Transform parent = root.jointTransform.parent;
foreach (HybridIKJoint node in hybridIKNode.nodes)
{
// encode rotation
if (node.keyedRotations == null)
node.keyedRotations = new List<Quaternion>();
node.keyedRotations.Add(node.jointTransform.localRotation);
//encode local positions used for stretch
if (node.keyedLocalPositions == null)
node.keyedLocalPositions = new List<Vector3>();
node.keyedLocalPositions.Add(node.jointTransform.localPosition);
// encode position in parent space
if (node.keyedPositions == null)
node.keyedPositions = new List<Vector3>();
node.keyedPositions.Add(parent != null ? parent.InverseTransformPoint(node.GetCurrentPositionWorld()) : node.GetCurrentPositionWorld());
HybridIKConstraint constraint = hybridIKNode.constraints.Find(c => c.jointTransform == node.jointTransform);
if (constraint == null)
{
constraint = new HybridIKConstraint();
constraint.jointTransform = node.jointTransform;
constraint.constrainPosition = true;
hybridIKNode.constraints.Add(constraint);
}
}
foreach (HybridIKConstraint c in hybridIKNode.constraints)
{
ConstraintPositionKey key = new ConstraintPositionKey();
if (c.positionKeys == null) c.positionKeys = new List<ConstraintPositionKey>();
key.constraintPositionValue = c.jointTransform.position;
Vector3 endPos = parent != null ? parent.InverseTransformPoint(hybridIKNode.endNode.position) : hybridIKNode.endNode.position;
key.SetEndTargetPosition(hybridIKNode.endNode.position, parent);
c.positionKeys.Add(key);
}
hybridIKNode.ResetToZeroPose();
}
if (hybridIKNode.nodes != null && hybridIKNode.nodes.Count > 0 && hybridIKNode.nodes[0] != null && hybridIKNode.nodes[0].keyedPositions != null)
{
for (int p = 0; p < hybridIKNode.nodes[0].keyedPositions.Count; ++p)
{
GUILayout.BeginHorizontal();
GUILayout.Label("Key Pose " + (p + 1).ToString());
if (GUILayout.Button("Select"))
{
//selectedIKKeyframe = p;
hybridIKNode.PoseToKeyframe(p);
Repaint();
}
if (GUILayout.Button("Delete Key"))
{
DeletePoseKeyframe(p);
}
GUILayout.EndHorizontal();
}
}
}
if (GUI.changed) EditorUtility.SetDirty(hybridIKNode);
}
private void OnDestroy()
{
if (!Application.isPlaying)
hybridIKNode.ResetToZeroPose();
}
public void OnSceneGUI()
{
if (hybridIKNode.nodes == null || hybridIKNode.nodes.Count == 0) return;
Color originalColor = Handles.color;
if (hybridIKNode.IsInitialized())
{
for (int i = 0; i < hybridIKNode.nodes.Count; ++i)
//foreach (SweepIKNode n in hybridIKNode.nodes)
{
HybridIKJoint n = hybridIKNode.nodes[i];
Color c = n.enableKeyframeConstraints ? Color.blue : n.overrideConstraint ? Color.cyan : originalColor;
Handles.color = selectedIKNodeIndex == i ? Color.green : c;
float nRadius = Mathf.Max(n.jointRadius, 0.05f, n.jointRadius);
if (Handles.Button(n.GetCurrentPositionWorld(), Quaternion.identity, nRadius, nRadius,Handles.SphereHandleCap))
{
selectedIKNodeIndex = i;
selectedIKKeyframe = -1;
if (!Application.isPlaying)
hybridIKNode.ResetToZeroPose();
Repaint();
}
}
HybridIKJoint root = hybridIKNode.GetRootIKNode();
HybridIKJoint endIKNode = hybridIKNode.GetEndIKNode();
Transform parentSpace = root.jointTransform.parent;
foreach (HybridIKConstraint c in hybridIKNode.constraints)
{
if (c.positionKeys.Count > 0)
{
for (int i = 0; i < c.positionKeys.Count; ++i)
{
ConstraintPositionKey k = c.positionKeys[i];
Handles.color = selectedIKKeyframe == i ? Color.green : originalColor;
if (i % 4 == 0) Handles.color = Color.green;
if (i % 4 == 1) Handles.color = Color.blue;
if (i % 4 == 2) Handles.color = Color.yellow;
if (i % 4 == 3) Handles.color = Color.magenta;
Vector3 buttonPos = k.GetEndTargetPosition(endIKNode.targetIKSpace != null ? endIKNode.targetIKSpace : parentSpace);
if (Handles.Button(buttonPos, Quaternion.identity, endIKNode.jointRadius, endIKNode.jointRadius, Handles.SphereHandleCap))
{
selectedIKKeyframe = i;
selectedIKNodeIndex = -1;
hybridIKNode.PoseToKeyframe(selectedIKKeyframe);
Repaint();
}
}
}
}
}
Handles.color = originalColor;
}
}