419 lines
17 KiB
C#
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();
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|