holopy3/Assets/UniGLTF/UniHumanoid/Scripts/Editor/BoneMappingEditor.cs
Lena Biresch 490ef558ef CleanUp
2021-01-28 13:07:52 +01:00

419 lines
17 KiB
C#

using System.Collections;
using System.Collections.Generic;
using System.Linq;
using System.IO;
using UnityEditor;
using UnityEngine;
namespace UniHumanoid
{
[CustomEditor(typeof(BoneMapping))]
public class BoneMappingEditor : Editor
{
BoneMapping m_target;
void OnEnable()
{
m_target = (BoneMapping)target;
var animator = m_target.GetComponent<Animator>();
if (animator != null)
{
m_bones = EachBoneDefs.Select(x => new Bone(
animator.GetBoneTransform(x.Head), animator.GetBoneTransform(x.Tail)))
.Where(x => x.Head != null && x.Tail != null)
.ToArray();
}
}
static GameObject ObjectField(GameObject obj)
{
return (GameObject)EditorGUILayout.ObjectField(obj, typeof(GameObject), true);
}
static GameObject ObjectField(string label, GameObject obj)
{
return (GameObject)EditorGUILayout.ObjectField(label, obj, typeof(GameObject), true);
}
const int LABEL_WIDTH = 100;
static void BoneField(HumanBodyBones bone, GameObject[] bones)
{
EditorGUILayout.BeginHorizontal();
EditorGUILayout.LabelField(bone.ToString(), GUILayout.Width(LABEL_WIDTH));
bones[(int)bone] = ObjectField(bones[(int)bone]);
EditorGUILayout.EndHorizontal();
}
static void BoneField(HumanBodyBones left, HumanBodyBones right, GameObject[] bones)
{
EditorGUILayout.BeginHorizontal();
EditorGUILayout.LabelField(left.ToString().Substring(4), GUILayout.Width(LABEL_WIDTH)); // skip left
bones[(int)left] = ObjectField(bones[(int)left]);
bones[(int)right] = ObjectField(bones[(int)right]);
EditorGUILayout.EndHorizontal();
}
bool m_handFoldout;
bool m_settingsFoldout;
public override void OnInspectorGUI()
{
var bones = m_target.Bones;
if (bones == null)
{
return;
}
BoneField(HumanBodyBones.Hips, bones);
if (bones[(int)HumanBodyBones.Hips] == null)
{
EditorGUILayout.HelpBox(@"First, you set hips", MessageType.Warning);
}
else
{
if (GUILayout.Button("Guess bone mapping"))
{
m_target.GuessBoneMapping();
}
EditorGUILayout.HelpBox(@"Guess bones from hips", MessageType.Info);
if (GUILayout.Button("Ensure T-Pose"))
{
m_target.EnsureTPose();
}
EditorGUILayout.HelpBox(@"Arms to Horizontal", MessageType.Info);
if (GUILayout.Button("Create avatar"))
{
var description = AvatarDescription.Create(m_target.Description);
BoneMapping.SetBonesToDescription(m_target, description);
var avatar = description.CreateAvatarAndSetup(m_target.transform);
if (avatar != null)
{
avatar.name = "avatar";
#if UNITY_2018_2_OR_NEWER
var prefabRoot = PrefabUtility.GetCorrespondingObjectFromSource(m_target.gameObject);
#else
var prefabRoot = PrefabUtility.GetPrefabParent(m_target.gameObject);
#endif
var prefabPath = AssetDatabase.GetAssetPath(prefabRoot);
var path = (string.IsNullOrEmpty(prefabPath))
? string.Format("Assets/{0}.asset", avatar.name)
: string.Format("{0}/{1}.asset", Path.GetDirectoryName(prefabPath), Path.GetFileNameWithoutExtension(prefabPath))
;
path = EditorUtility.SaveFilePanel(
"Save avatar",
Path.GetDirectoryName(path),
string.Format("{0}.avatar.asset", serializedObject.targetObject.name),
"asset");
var assetPath = HumanPoseTransferEditor.ToAssetPath(path);
if (!string.IsNullOrEmpty(assetPath))
{
AssetDatabase.CreateAsset(description, assetPath); // overwrite
AssetDatabase.AddObjectToAsset(avatar, assetPath);
Debug.LogFormat("Create avatar {0}", path);
AssetDatabase.ImportAsset(assetPath);
Selection.activeObject = avatar;
}
else
{
Debug.LogWarning("fail to CreateAvatar");
}
}
}
EditorGUILayout.HelpBox(@"before create,
1. Model root transform should reset(origin without rotation)
2. Model forward to Z+(rotate child of model root)
3. Required bones filled
", MessageType.Info);
}
/*
m_settingsFoldout = EditorGUILayout.Foldout(m_settingsFoldout, "AvatarSettings");
if (m_settingsFoldout)
{
EditorGUILayout.FloatField("armStretch", m_target.armStretch);
EditorGUILayout.FloatField("legStretch", m_target.legStretch);
EditorGUILayout.FloatField("upperArmTwist", m_target.upperArmTwist);
EditorGUILayout.FloatField("lowerArmTwist", m_target.lowerArmTwist);
EditorGUILayout.FloatField("upperLegTwist", m_target.upperLegTwist);
EditorGUILayout.FloatField("lowerLegTwist", m_target.lowerLegTwist);
EditorGUILayout.FloatField("feetSpacing", m_target.feetSpacing);
EditorGUILayout.Toggle("hasTranslationDoF", m_target.hasTranslationDoF);
//public BoneLimit[] human;
}
*/
EditorGUILayout.BeginHorizontal();
EditorGUILayout.LabelField("Arm", EditorStyles.boldLabel, GUILayout.Width(LABEL_WIDTH));
EditorGUILayout.LabelField("Left", EditorStyles.boldLabel, GUILayout.Width(40));
EditorGUILayout.Space();
EditorGUILayout.LabelField("Right", EditorStyles.boldLabel, GUILayout.Width(40));
EditorGUILayout.EndHorizontal();
BoneField(HumanBodyBones.LeftShoulder, HumanBodyBones.RightShoulder, bones);
BoneField(HumanBodyBones.LeftUpperArm, HumanBodyBones.RightUpperArm, bones);
BoneField(HumanBodyBones.LeftLowerArm, HumanBodyBones.RightLowerArm, bones);
BoneField(HumanBodyBones.LeftHand, HumanBodyBones.RightHand, bones);
EditorGUILayout.LabelField("Body and Head", EditorStyles.boldLabel);
BoneField(HumanBodyBones.Spine, bones);
BoneField(HumanBodyBones.Chest, bones);
#if UNITY_5_6_OR_NEWER
BoneField(HumanBodyBones.UpperChest, bones);
#endif
BoneField(HumanBodyBones.Neck, bones);
BoneField(HumanBodyBones.Head, bones);
BoneField(HumanBodyBones.Jaw, bones);
BoneField(HumanBodyBones.LeftEye, HumanBodyBones.RightEye, bones);
EditorGUILayout.BeginHorizontal();
EditorGUILayout.LabelField("Leg", EditorStyles.boldLabel, GUILayout.Width(LABEL_WIDTH));
EditorGUILayout.LabelField("Left", EditorStyles.boldLabel, GUILayout.Width(40));
EditorGUILayout.Space();
EditorGUILayout.LabelField("Right", EditorStyles.boldLabel, GUILayout.Width(40));
EditorGUILayout.EndHorizontal();
BoneField(HumanBodyBones.LeftUpperLeg, HumanBodyBones.RightUpperLeg, bones);
BoneField(HumanBodyBones.LeftLowerLeg, HumanBodyBones.RightLowerLeg, bones);
BoneField(HumanBodyBones.LeftFoot, HumanBodyBones.RightFoot, bones);
BoneField(HumanBodyBones.LeftToes, HumanBodyBones.RightToes, bones);
m_handFoldout = EditorGUILayout.Foldout(m_handFoldout, "Hand");
if (m_handFoldout)
{
EditorGUILayout.BeginHorizontal();
EditorGUILayout.LabelField("Thumb", EditorStyles.boldLabel, GUILayout.Width(LABEL_WIDTH));
EditorGUILayout.LabelField("Left", EditorStyles.boldLabel, GUILayout.Width(40));
EditorGUILayout.Space();
EditorGUILayout.LabelField("Right", EditorStyles.boldLabel, GUILayout.Width(40));
EditorGUILayout.EndHorizontal();
BoneField(HumanBodyBones.LeftThumbProximal, HumanBodyBones.RightThumbProximal, bones);
BoneField(HumanBodyBones.LeftThumbIntermediate, HumanBodyBones.RightThumbIntermediate, bones);
BoneField(HumanBodyBones.LeftThumbDistal, HumanBodyBones.RightThumbDistal, bones);
EditorGUILayout.BeginHorizontal();
EditorGUILayout.LabelField("Index", EditorStyles.boldLabel, GUILayout.Width(LABEL_WIDTH));
EditorGUILayout.LabelField("Left", EditorStyles.boldLabel, GUILayout.Width(40));
EditorGUILayout.Space();
EditorGUILayout.LabelField("Right", EditorStyles.boldLabel, GUILayout.Width(40));
EditorGUILayout.EndHorizontal();
BoneField(HumanBodyBones.LeftIndexProximal, HumanBodyBones.RightIndexProximal, bones);
BoneField(HumanBodyBones.LeftIndexIntermediate, HumanBodyBones.RightIndexIntermediate, bones);
BoneField(HumanBodyBones.LeftIndexDistal, HumanBodyBones.RightIndexDistal, bones);
EditorGUILayout.BeginHorizontal();
EditorGUILayout.LabelField("Middle", EditorStyles.boldLabel, GUILayout.Width(LABEL_WIDTH));
EditorGUILayout.LabelField("Left", EditorStyles.boldLabel, GUILayout.Width(40));
EditorGUILayout.Space();
EditorGUILayout.LabelField("Right", EditorStyles.boldLabel, GUILayout.Width(40));
EditorGUILayout.EndHorizontal();
BoneField(HumanBodyBones.LeftMiddleProximal, HumanBodyBones.RightMiddleProximal, bones);
BoneField(HumanBodyBones.LeftMiddleIntermediate, HumanBodyBones.RightMiddleIntermediate, bones);
BoneField(HumanBodyBones.LeftMiddleDistal, HumanBodyBones.RightMiddleDistal, bones);
EditorGUILayout.BeginHorizontal();
EditorGUILayout.LabelField("Ring", EditorStyles.boldLabel, GUILayout.Width(LABEL_WIDTH));
EditorGUILayout.LabelField("Left", EditorStyles.boldLabel, GUILayout.Width(40));
EditorGUILayout.Space();
EditorGUILayout.LabelField("Right", EditorStyles.boldLabel, GUILayout.Width(40));
EditorGUILayout.EndHorizontal();
BoneField(HumanBodyBones.LeftRingProximal, HumanBodyBones.RightRingProximal, bones);
BoneField(HumanBodyBones.LeftRingIntermediate, HumanBodyBones.RightRingIntermediate, bones);
BoneField(HumanBodyBones.LeftRingDistal, HumanBodyBones.RightRingDistal, bones);
EditorGUILayout.BeginHorizontal();
EditorGUILayout.LabelField("Little", EditorStyles.boldLabel, GUILayout.Width(LABEL_WIDTH));
EditorGUILayout.LabelField("Left", EditorStyles.boldLabel, GUILayout.Width(40));
EditorGUILayout.Space();
EditorGUILayout.LabelField("Right", EditorStyles.boldLabel, GUILayout.Width(40));
EditorGUILayout.EndHorizontal();
BoneField(HumanBodyBones.LeftLittleProximal, HumanBodyBones.RightLittleProximal, bones);
BoneField(HumanBodyBones.LeftLittleIntermediate, HumanBodyBones.RightLittleIntermediate, bones);
BoneField(HumanBodyBones.LeftLittleDistal, HumanBodyBones.RightLittleDistal, bones);
}
EditorUtility.SetDirty(m_target);
}
struct Bone
{
public Transform Head;
public Transform Tail;
public Bone(Transform head, Transform tail)
{
Head = head;
Tail = tail;
}
public void Draw()
{
Handles.DrawLine(Head.transform.position, Tail.transform.position);
}
}
Bone[] m_bones;
struct BoneDef
{
public HumanBodyBones Head;
public HumanBodyBones Tail;
public BoneDef(HumanBodyBones head, HumanBodyBones tail)
{
Head = head;
Tail = tail;
}
}
static readonly HumanBodyBones[][] BoneDefs =
{
new HumanBodyBones[]
{
HumanBodyBones.Hips,
HumanBodyBones.Spine,
HumanBodyBones.Chest,
HumanBodyBones.Neck,
HumanBodyBones.Head,
},
new HumanBodyBones[]
{
HumanBodyBones.Chest,
HumanBodyBones.LeftShoulder,
HumanBodyBones.LeftUpperArm,
HumanBodyBones.LeftLowerArm,
HumanBodyBones.LeftHand,
},
new HumanBodyBones[]
{
HumanBodyBones.Chest,
HumanBodyBones.RightShoulder,
HumanBodyBones.RightUpperArm,
HumanBodyBones.RightLowerArm,
HumanBodyBones.RightHand,
},
new HumanBodyBones[]
{
HumanBodyBones.LeftThumbProximal,
HumanBodyBones.LeftThumbIntermediate,
HumanBodyBones.LeftThumbDistal,
},
new HumanBodyBones[]
{
HumanBodyBones.LeftIndexProximal,
HumanBodyBones.LeftIndexIntermediate,
HumanBodyBones.LeftIndexDistal,
},
new HumanBodyBones[]
{
HumanBodyBones.LeftMiddleProximal,
HumanBodyBones.LeftMiddleIntermediate,
HumanBodyBones.LeftMiddleDistal,
},
new HumanBodyBones[]
{
HumanBodyBones.LeftRingProximal,
HumanBodyBones.LeftRingIntermediate,
HumanBodyBones.LeftRingDistal,
},
new HumanBodyBones[]
{
HumanBodyBones.LeftLittleProximal,
HumanBodyBones.LeftLittleIntermediate,
HumanBodyBones.LeftLittleDistal,
},
new HumanBodyBones[]
{
HumanBodyBones.RightThumbProximal,
HumanBodyBones.RightThumbIntermediate,
HumanBodyBones.RightThumbDistal,
},
new HumanBodyBones[]
{
HumanBodyBones.RightIndexProximal,
HumanBodyBones.RightIndexIntermediate,
HumanBodyBones.RightIndexDistal,
},
new HumanBodyBones[]
{
HumanBodyBones.RightMiddleProximal,
HumanBodyBones.RightMiddleIntermediate,
HumanBodyBones.RightMiddleDistal,
},
new HumanBodyBones[]
{
HumanBodyBones.RightRingProximal,
HumanBodyBones.RightRingIntermediate,
HumanBodyBones.RightRingDistal,
},
new HumanBodyBones[]
{
HumanBodyBones.RightLittleProximal,
HumanBodyBones.RightLittleIntermediate,
HumanBodyBones.RightLittleDistal,
},
new HumanBodyBones[]
{
HumanBodyBones.LeftUpperLeg,
HumanBodyBones.LeftLowerLeg,
HumanBodyBones.LeftFoot,
},
new HumanBodyBones[]
{
HumanBodyBones.RightUpperLeg,
HumanBodyBones.RightLowerLeg,
HumanBodyBones.RightFoot,
},
};
static IEnumerable<BoneDef> EachBoneDefs
{
get
{
foreach (var x in BoneDefs)
{
var count = x.Length - 1;
for (int i = 0; i < count; ++i)
{
yield return new BoneDef(x[i], x[i + 1]);
}
}
}
}
void DrawBone(HumanBodyBones bone, GameObject go)
{
if (go == null)
{
return;
}
Handles.Label(go.transform.position,
go.name + "\n(" + bone.ToString() + ")");
}
private void OnSceneGUI()
{
var bones = m_target.Bones;
if (bones != null)
{
for (int i = 0; i < bones.Length; ++i)
{
DrawBone((HumanBodyBones)i, bones[i]);
}
foreach(var x in m_bones)
{
x.Draw();
}
}
}
}
}