summaryrefslogtreecommitdiff
path: root/Assets/ThirdParty/VRM/MeshUtility/Editor
diff options
context:
space:
mode:
Diffstat (limited to 'Assets/ThirdParty/VRM/MeshUtility/Editor')
-rw-r--r--Assets/ThirdParty/VRM/MeshUtility/Editor/BoneMeshEraserWizard.cs200
-rw-r--r--Assets/ThirdParty/VRM/MeshUtility/Editor/BoneMeshEraserWizard.cs.meta13
-rw-r--r--Assets/ThirdParty/VRM/MeshUtility/Editor/HumanoidEditor.cs324
-rw-r--r--Assets/ThirdParty/VRM/MeshUtility/Editor/HumanoidEditor.cs.meta11
-rw-r--r--Assets/ThirdParty/VRM/MeshUtility/Editor/MeshUtility.Editor.asmdef16
-rw-r--r--Assets/ThirdParty/VRM/MeshUtility/Editor/MeshUtility.Editor.asmdef.meta7
-rw-r--r--Assets/ThirdParty/VRM/MeshUtility/Editor/MeshUtility.cs286
-rw-r--r--Assets/ThirdParty/VRM/MeshUtility/Editor/MeshUtility.cs.meta11
8 files changed, 868 insertions, 0 deletions
diff --git a/Assets/ThirdParty/VRM/MeshUtility/Editor/BoneMeshEraserWizard.cs b/Assets/ThirdParty/VRM/MeshUtility/Editor/BoneMeshEraserWizard.cs
new file mode 100644
index 00000000..63bf9045
--- /dev/null
+++ b/Assets/ThirdParty/VRM/MeshUtility/Editor/BoneMeshEraserWizard.cs
@@ -0,0 +1,200 @@
+using System;
+using System.Collections.Generic;
+using System.IO;
+using System.Linq;
+using UnityEditor;
+using UnityEngine;
+
+
+namespace MeshUtility
+{
+ [CustomPropertyDrawer(typeof(BoneMeshEraser.EraseBone))]
+ public class EraseBoneDrawer : PropertyDrawer
+ {
+ public override void OnGUI(Rect position, SerializedProperty property, GUIContent label)
+ {
+ //EditorGUI.BeginProperty(position, label, property);
+
+ var leftWidth = 0.6f;
+ var rightWidth = 1.0f - leftWidth;
+
+ var leftSide = new Rect(position.x, position.y, position.width * leftWidth, position.height);
+ var rightSide = new Rect(position.width * leftWidth, position.y, position.width * rightWidth, position.height);
+ {
+ EditorGUI.PropertyField(leftSide, property.FindPropertyRelative("Bone"), new GUIContent("", ""));
+ EditorGUI.PropertyField(rightSide, property.FindPropertyRelative("Erase"));
+ }
+
+ //EditorGUI.EndProperty();
+ }
+
+ public override float GetPropertyHeight(SerializedProperty property, GUIContent label)
+ {
+ var height = base.GetPropertyHeight(property, label);
+ return height;
+ }
+ }
+
+ public class BoneMeshEraserWizard : ScriptableWizard
+ {
+ const string ASSET_SUFFIX = ".asset";
+
+ [SerializeField]
+ SkinnedMeshRenderer m_skinnedMesh;
+
+ [SerializeField]
+ Animator m_animator;
+
+ [SerializeField]
+ Transform EraseRoot;
+
+ [SerializeField]
+ BoneMeshEraser.EraseBone[] m_eraseBones;
+
+ [MenuItem(MeshUtility.MENU_PARENT + "BoneMeshEraser Wizard", priority = 4)]
+ static void CreateWizard()
+ {
+ ScriptableWizard.DisplayWizard<BoneMeshEraserWizard>("BoneMeshEraser", "Erase triangles by bone", "Erase");
+ }
+
+ private void OnEnable()
+ {
+ var root = Selection.activeGameObject;
+ if (root != null)
+ {
+ m_animator = root.GetComponent<Animator>();
+ m_skinnedMesh = root.GetComponent<SkinnedMeshRenderer>();
+ OnValidate();
+ }
+ }
+
+ void OnValidate()
+ {
+ //Debug.Log("OnValidate");
+ if (m_skinnedMesh == null)
+ {
+ m_eraseBones = new BoneMeshEraser.EraseBone[] { };
+ return;
+ }
+
+ if (EraseRoot == null)
+ {
+ if (m_animator != null)
+ {
+ EraseRoot = m_animator.GetBoneTransform(HumanBodyBones.Head);
+ //Debug.LogFormat("head: {0}", EraseRoot);
+ }
+ }
+
+ m_eraseBones = m_skinnedMesh.bones.Select(x =>
+ {
+ var eb = new BoneMeshEraser.EraseBone
+ {
+ Bone = x,
+ };
+
+ if (EraseRoot != null)
+ {
+ // 首の子孫を消去
+ if (eb.Bone.Ancestor().Any(y => y == EraseRoot))
+ {
+ //Debug.LogFormat("erase {0}", x);
+ eb.Erase = true;
+ }
+ }
+
+ return eb;
+ })
+ .ToArray();
+ }
+
+ void OnWizardUpdate()
+ {
+ helpString = "select target skinnedMesh and animator";
+ }
+
+
+
+ static int IndexOf(Transform[] list, Transform target)
+ {
+ for (int i = 0; i < list.Length; ++i)
+ {
+ if (list[i] == target)
+ {
+ return i;
+ }
+ }
+ return -1;
+ }
+
+ SkinnedMeshRenderer _Erase(GameObject go)
+ {
+ if (go == null)
+ {
+ Debug.LogWarning("select root object in hierarchy");
+ return null;
+ }
+ if (m_skinnedMesh == null)
+ {
+ Debug.LogWarning("no skinnedmesh");
+ return null;
+ }
+
+ var bones = m_skinnedMesh.bones;
+ var eraseBones = m_eraseBones
+ .Where(x => x.Erase)
+ .Select(x => Array.IndexOf(bones, x.Bone))
+ .ToArray();
+
+ var meshNode = new GameObject("BoneMeshEraser");
+ meshNode.transform.SetParent(go.transform, false);
+
+ var erased = meshNode.AddComponent<SkinnedMeshRenderer>();
+ erased.sharedMesh = BoneMeshEraser.CreateErasedMesh(m_skinnedMesh.sharedMesh, eraseBones);
+ erased.sharedMaterials = m_skinnedMesh.sharedMaterials;
+ erased.bones = m_skinnedMesh.bones;
+
+ return erased;
+ }
+
+ void Erase()
+ {
+ var go = Selection.activeGameObject;
+ var renderer = _Erase(go);
+ if (renderer == null)
+ {
+ return;
+ }
+
+ // save mesh to Assets
+ var assetPath = string.Format("{0}{1}", go.name, ASSET_SUFFIX);
+ var prefab = MeshUtility.GetPrefab(go);
+ if (prefab != null)
+ {
+ var prefabPath = AssetDatabase.GetAssetPath(prefab);
+ assetPath = string.Format("{0}/{1}{2}",
+ Path.GetDirectoryName(prefabPath),
+ Path.GetFileNameWithoutExtension(prefabPath),
+ ASSET_SUFFIX
+ );
+ }
+
+ Debug.LogFormat("CreateAsset: {0}", assetPath);
+ AssetDatabase.CreateAsset(renderer.sharedMesh, assetPath);
+ }
+
+ void OnWizardCreate()
+ {
+ //Debug.Log("OnWizardCreate");
+ Erase();
+
+ // close
+ }
+
+ void OnWizardOtherButton()
+ {
+ //Debug.Log("OnWizardOtherButton");
+ Erase();
+ }
+ }
+}
diff --git a/Assets/ThirdParty/VRM/MeshUtility/Editor/BoneMeshEraserWizard.cs.meta b/Assets/ThirdParty/VRM/MeshUtility/Editor/BoneMeshEraserWizard.cs.meta
new file mode 100644
index 00000000..ef9f3976
--- /dev/null
+++ b/Assets/ThirdParty/VRM/MeshUtility/Editor/BoneMeshEraserWizard.cs.meta
@@ -0,0 +1,13 @@
+fileFormatVersion: 2
+guid: 881b00db73f639c48a3f043a775fa61a
+timeCreated: 1518503829
+licenseType: Free
+MonoImporter:
+ externalObjects: {}
+ serializedVersion: 2
+ defaultReferences: []
+ executionOrder: 0
+ icon: {instanceID: 0}
+ userData:
+ assetBundleName:
+ assetBundleVariant:
diff --git a/Assets/ThirdParty/VRM/MeshUtility/Editor/HumanoidEditor.cs b/Assets/ThirdParty/VRM/MeshUtility/Editor/HumanoidEditor.cs
new file mode 100644
index 00000000..f9a99cfc
--- /dev/null
+++ b/Assets/ThirdParty/VRM/MeshUtility/Editor/HumanoidEditor.cs
@@ -0,0 +1,324 @@
+using System.Collections;
+using System.Collections.Generic;
+using System.Linq;
+using System.IO;
+using UnityEditor;
+using UnityEngine;
+using System;
+
+namespace MeshUtility
+{
+ [CustomEditor(typeof(Humanoid))]
+ public class HumanoidEditor : Editor
+ {
+ const int LABEL_WIDTH = 100;
+
+ Humanoid m_target;
+
+ SerializedProperty m_Hips;
+ #region leg
+ SerializedProperty m_LeftUpperLeg;
+ SerializedProperty m_RightUpperLeg;
+ SerializedProperty m_LeftLowerLeg;
+ SerializedProperty m_RightLowerLeg;
+ SerializedProperty m_LeftFoot;
+ SerializedProperty m_RightFoot;
+ SerializedProperty m_LeftToes;
+ SerializedProperty m_RightToes;
+
+ #endregion
+
+ #region spine
+ SerializedProperty m_Spine;
+ SerializedProperty m_Chest;
+ SerializedProperty m_UpperChest;
+ SerializedProperty m_Neck;
+ SerializedProperty m_Head;
+ SerializedProperty m_LeftEye;
+ SerializedProperty m_RightEye;
+ SerializedProperty m_Jaw;
+
+ #endregion
+
+ #region arm
+ SerializedProperty m_LeftShoulder;
+ SerializedProperty m_RightShoulder;
+ SerializedProperty m_LeftUpperArm;
+ SerializedProperty m_RightUpperArm;
+ SerializedProperty m_LeftLowerArm;
+ SerializedProperty m_RightLowerArm;
+ SerializedProperty m_LeftHand;
+ SerializedProperty m_RightHand;
+
+ #endregion
+
+ #region fingers
+ SerializedProperty m_LeftThumbProximal;
+ SerializedProperty m_LeftThumbIntermediate;
+ SerializedProperty m_LeftThumbDistal;
+ SerializedProperty m_LeftIndexProximal;
+ SerializedProperty m_LeftIndexIntermediate;
+ SerializedProperty m_LeftIndexDistal;
+ SerializedProperty m_LeftMiddleProximal;
+ SerializedProperty m_LeftMiddleIntermediate;
+ SerializedProperty m_LeftMiddleDistal;
+ SerializedProperty m_LeftRingProximal;
+ SerializedProperty m_LeftRingIntermediate;
+ SerializedProperty m_LeftRingDistal;
+ SerializedProperty m_LeftLittleProximal;
+ SerializedProperty m_LeftLittleIntermediate;
+ SerializedProperty m_LeftLittleDistal;
+ SerializedProperty m_RightThumbProximal;
+ SerializedProperty m_RightThumbIntermediate;
+ SerializedProperty m_RightThumbDistal;
+ SerializedProperty m_RightIndexProximal;
+ SerializedProperty m_RightIndexIntermediate;
+ SerializedProperty m_RightIndexDistal;
+ SerializedProperty m_RightMiddleProximal;
+ SerializedProperty m_RightMiddleIntermediate;
+ SerializedProperty m_RightMiddleDistal;
+ SerializedProperty m_RightRingProximal;
+ SerializedProperty m_RightRingIntermediate;
+ SerializedProperty m_RightRingDistal;
+ SerializedProperty m_RightLittleProximal;
+ SerializedProperty m_RightLittleIntermediate;
+ SerializedProperty m_RightLittleDistal;
+
+ #endregion
+
+ void OnEnable()
+ {
+ m_target = target as Humanoid;
+ m_Hips = serializedObject.FindProperty($"m_{nameof(Humanoid.Hips)}");
+
+ #region legs
+ m_LeftUpperLeg = serializedObject.FindProperty($"m_{nameof(Humanoid.LeftUpperLeg)}");
+ m_RightUpperLeg = serializedObject.FindProperty($"m_{nameof(Humanoid.RightUpperLeg)}");
+ m_LeftLowerLeg = serializedObject.FindProperty($"m_{nameof(Humanoid.LeftLowerLeg)}");
+ m_RightLowerLeg = serializedObject.FindProperty($"m_{nameof(Humanoid.RightLowerLeg)}");
+ m_LeftFoot = serializedObject.FindProperty($"m_{nameof(Humanoid.LeftFoot)}");
+ m_RightFoot = serializedObject.FindProperty($"m_{nameof(Humanoid.RightFoot)}");
+ m_LeftToes = serializedObject.FindProperty($"m_{nameof(Humanoid.LeftToes)}");
+ m_RightToes = serializedObject.FindProperty($"m_{nameof(Humanoid.RightToes)}");
+ #endregion
+
+ #region spine
+ m_Spine = serializedObject.FindProperty($"m_{nameof(Humanoid.Spine)}");
+ m_Chest = serializedObject.FindProperty($"m_{nameof(Humanoid.Chest)}");
+ m_UpperChest = serializedObject.FindProperty($"m_{nameof(Humanoid.UpperChest)}");
+ m_Neck = serializedObject.FindProperty($"m_{nameof(Humanoid.Neck)}");
+ m_Head = serializedObject.FindProperty($"m_{nameof(Humanoid.Head)}");
+ m_LeftEye = serializedObject.FindProperty($"m_{nameof(Humanoid.LeftEye)}");
+ m_RightEye = serializedObject.FindProperty($"m_{nameof(Humanoid.RightEye)}");
+ m_Jaw = serializedObject.FindProperty($"m_{nameof(Humanoid.Jaw)}");
+
+ #endregion
+
+ #region arm
+ m_LeftShoulder = serializedObject.FindProperty($"m_{nameof(Humanoid.LeftShoulder)}");
+ m_RightShoulder = serializedObject.FindProperty($"m_{nameof(Humanoid.RightShoulder)}");
+ m_LeftUpperArm = serializedObject.FindProperty($"m_{nameof(Humanoid.LeftUpperArm)}");
+ m_RightUpperArm = serializedObject.FindProperty($"m_{nameof(Humanoid.RightUpperArm)}");
+ m_LeftLowerArm = serializedObject.FindProperty($"m_{nameof(Humanoid.LeftLowerArm)}");
+ m_RightLowerArm = serializedObject.FindProperty($"m_{nameof(Humanoid.RightLowerArm)}");
+ m_LeftHand = serializedObject.FindProperty($"m_{nameof(Humanoid.LeftHand)}");
+ m_RightHand = serializedObject.FindProperty($"m_{nameof(Humanoid.RightHand)}");
+
+ #endregion
+
+ #region fingers
+ m_LeftThumbProximal = serializedObject.FindProperty($"m_{nameof(Humanoid.LeftThumbProximal)}");
+ m_LeftThumbIntermediate = serializedObject.FindProperty($"m_{nameof(Humanoid.LeftThumbIntermediate)}");
+ m_LeftThumbDistal = serializedObject.FindProperty($"m_{nameof(Humanoid.LeftThumbDistal)}");
+ m_LeftIndexProximal = serializedObject.FindProperty($"m_{nameof(Humanoid.LeftIndexProximal)}");
+ m_LeftIndexIntermediate = serializedObject.FindProperty($"m_{nameof(Humanoid.LeftIndexIntermediate)}");
+ m_LeftIndexDistal = serializedObject.FindProperty($"m_{nameof(Humanoid.LeftIndexDistal)}");
+ m_LeftMiddleProximal = serializedObject.FindProperty($"m_{nameof(Humanoid.LeftMiddleProximal)}");
+ m_LeftMiddleIntermediate = serializedObject.FindProperty($"m_{nameof(Humanoid.LeftMiddleIntermediate)}");
+ m_LeftMiddleDistal = serializedObject.FindProperty($"m_{nameof(Humanoid.LeftMiddleDistal)}");
+ m_LeftRingProximal = serializedObject.FindProperty($"m_{nameof(Humanoid.LeftRingProximal)}");
+ m_LeftRingIntermediate = serializedObject.FindProperty($"m_{nameof(Humanoid.LeftRingIntermediate)}");
+ m_LeftRingDistal = serializedObject.FindProperty($"m_{nameof(Humanoid.LeftRingDistal)}");
+ m_LeftLittleProximal = serializedObject.FindProperty($"m_{nameof(Humanoid.LeftLittleProximal)}");
+ m_LeftLittleIntermediate = serializedObject.FindProperty($"m_{nameof(Humanoid.LeftLittleIntermediate)}");
+ m_LeftLittleDistal = serializedObject.FindProperty($"m_{nameof(Humanoid.LeftLittleDistal)}");
+ m_RightThumbProximal = serializedObject.FindProperty($"m_{nameof(Humanoid.RightThumbProximal)}");
+ m_RightThumbIntermediate = serializedObject.FindProperty($"m_{nameof(Humanoid.RightThumbIntermediate)}");
+ m_RightThumbDistal = serializedObject.FindProperty($"m_{nameof(Humanoid.RightThumbDistal)}");
+ m_RightIndexProximal = serializedObject.FindProperty($"m_{nameof(Humanoid.RightIndexProximal)}");
+ m_RightIndexIntermediate = serializedObject.FindProperty($"m_{nameof(Humanoid.RightIndexIntermediate)}");
+ m_RightIndexDistal = serializedObject.FindProperty($"m_{nameof(Humanoid.RightIndexDistal)}");
+ m_RightMiddleProximal = serializedObject.FindProperty($"m_{nameof(Humanoid.RightMiddleProximal)}");
+ m_RightMiddleIntermediate = serializedObject.FindProperty($"m_{nameof(Humanoid.RightMiddleIntermediate)}");
+ m_RightMiddleDistal = serializedObject.FindProperty($"m_{nameof(Humanoid.RightMiddleDistal)}");
+ m_RightRingProximal = serializedObject.FindProperty($"m_{nameof(Humanoid.RightRingProximal)}");
+ m_RightRingIntermediate = serializedObject.FindProperty($"m_{nameof(Humanoid.RightRingIntermediate)}");
+ m_RightRingDistal = serializedObject.FindProperty($"m_{nameof(Humanoid.RightRingDistal)}");
+ m_RightLittleProximal = serializedObject.FindProperty($"m_{nameof(Humanoid.RightLittleProximal)}");
+ m_RightLittleIntermediate = serializedObject.FindProperty($"m_{nameof(Humanoid.RightLittleIntermediate)}");
+ m_RightLittleDistal = serializedObject.FindProperty($"m_{nameof(Humanoid.RightLittleDistal)}");
+ #endregion
+ }
+
+ struct Horizontal : IDisposable
+ {
+ public static Horizontal Using()
+ {
+ EditorGUILayout.BeginHorizontal();
+ return default;
+ }
+ public void Dispose()
+ {
+ EditorGUILayout.EndHorizontal();
+ }
+ }
+
+ static void HorizontalFields(string label, params SerializedProperty[] props)
+ {
+ try
+ {
+ EditorGUILayout.BeginHorizontal();
+
+ GUILayout.Label(label, GUILayout.Width(LABEL_WIDTH));
+ GUILayout.FlexibleSpace();
+
+ foreach (var prop in props)
+ {
+ EditorGUILayout.PropertyField(prop, GUIContent.none, true, GUILayout.MinWidth(100));
+ }
+ }
+ finally
+ {
+ EditorGUILayout.EndHorizontal();
+ }
+ }
+
+ static bool s_spineFold;
+ static bool s_legFold;
+ static bool s_armFold;
+ static bool s_fingerFold;
+ static string GetDialogDir(UnityEngine.Object obj)
+ {
+ var prefab = PrefabUtility.GetCorrespondingObjectFromSource(obj);
+ if (prefab == null)
+ {
+ return null;
+ }
+ return UnityPath.FromAsset(prefab).FullPath;
+ }
+
+ public override void OnInspectorGUI()
+ {
+ foreach (var validation in m_target.Validate())
+ {
+ EditorGUILayout.HelpBox(validation.Message, validation.IsError ? MessageType.Error : MessageType.Warning);
+ }
+
+ // prefer
+ serializedObject.Update();
+
+ EditorGUILayout.PropertyField(m_Hips);
+
+ s_spineFold = EditorGUILayout.Foldout(s_spineFold, "Body");
+ if (s_spineFold)
+ {
+ EditorGUILayout.PropertyField(m_Spine);
+ EditorGUILayout.PropertyField(m_Chest);
+ EditorGUILayout.PropertyField(m_UpperChest);
+ EditorGUILayout.PropertyField(m_Neck);
+ EditorGUILayout.PropertyField(m_Head);
+ EditorGUILayout.PropertyField(m_Jaw);
+ HorizontalFields("Eye", m_LeftEye, m_RightEye);
+ }
+
+ s_legFold = EditorGUILayout.Foldout(s_legFold, "Leg");
+ if (s_legFold)
+ {
+ HorizontalFields("UpperLeg", m_LeftUpperLeg, m_RightUpperLeg);
+ HorizontalFields("LowerLeg", m_LeftLowerLeg, m_RightLowerLeg);
+ HorizontalFields("Foot", m_LeftFoot, m_RightFoot);
+ HorizontalFields("Toes", m_LeftToes, m_RightToes);
+ }
+
+ s_armFold = EditorGUILayout.Foldout(s_armFold, "Arm");
+ if (s_armFold)
+ {
+ HorizontalFields("Shoulder", m_LeftShoulder, m_RightShoulder);
+ HorizontalFields("UpperArm", m_LeftUpperArm, m_RightUpperArm);
+ HorizontalFields("LowerArm", m_LeftLowerArm, m_RightLowerArm);
+ HorizontalFields("Hand", m_LeftHand, m_RightHand);
+ }
+
+ s_fingerFold = EditorGUILayout.Foldout(s_fingerFold, "Finger");
+ if (s_fingerFold)
+ {
+ HorizontalFields("LeftThumb", m_LeftThumbProximal, m_LeftThumbIntermediate, m_LeftThumbDistal);
+ HorizontalFields("LeftIndex", m_LeftIndexProximal, m_LeftIndexIntermediate, m_LeftIndexDistal);
+ HorizontalFields("LeftMiddle", m_LeftMiddleProximal, m_LeftMiddleIntermediate, m_LeftMiddleDistal);
+ HorizontalFields("LeftRing", m_LeftRingProximal, m_LeftRingIntermediate, m_LeftRingDistal);
+ HorizontalFields("LeftLittle", m_LeftLittleProximal, m_LeftLittleIntermediate, m_LeftLittleDistal);
+ HorizontalFields("RightThumb", m_RightThumbProximal, m_RightThumbIntermediate, m_RightThumbDistal);
+ HorizontalFields("RightIndex", m_RightIndexProximal, m_RightIndexIntermediate, m_RightIndexDistal);
+ HorizontalFields("RightMiddle", m_RightMiddleProximal, m_RightMiddleIntermediate, m_RightMiddleDistal);
+ HorizontalFields("RightRing", m_RightRingProximal, m_RightRingIntermediate, m_RightRingDistal);
+ HorizontalFields("RightLittle", m_RightLittleProximal, m_RightLittleIntermediate, m_RightLittleDistal);
+ }
+
+ serializedObject.ApplyModifiedProperties();
+
+ // create avatar
+ if (GUILayout.Button("Create UnityEngine.Avatar"))
+ {
+ var path = EditorUtility.SaveFilePanel(
+ "Save avatar",
+ GetDialogDir(m_target),
+ string.Format("{0}.avatar.asset", serializedObject.targetObject.name),
+ "asset");
+ if (!string.IsNullOrEmpty(path))
+ {
+ var avatar = m_target.CreateAvatar();
+ if (avatar != null)
+ {
+ var unityPath = UnityPath.FromFullpath(path);
+ avatar.name = "avatar";
+ Debug.LogFormat("Create avatar {0}", unityPath);
+ AssetDatabase.CreateAsset(avatar, unityPath.Value);
+ AssetDatabase.ImportAsset(unityPath.Value);
+
+ // replace
+ var animator = m_target.GetComponent<Animator>();
+ if (animator == null)
+ {
+ animator = m_target.gameObject.AddComponent<Animator>();
+ }
+ animator.avatar = avatar;
+
+ Selection.activeObject = avatar;
+ }
+ }
+ }
+ }
+
+ 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();
+ // }
+ // }
+
+ var forward = m_target.GetForward();
+
+ var begin = m_target.transform.position;
+ var end = begin + forward;
+ Handles.DrawLine(begin, end);
+ }
+ }
+}
diff --git a/Assets/ThirdParty/VRM/MeshUtility/Editor/HumanoidEditor.cs.meta b/Assets/ThirdParty/VRM/MeshUtility/Editor/HumanoidEditor.cs.meta
new file mode 100644
index 00000000..dffaaa18
--- /dev/null
+++ b/Assets/ThirdParty/VRM/MeshUtility/Editor/HumanoidEditor.cs.meta
@@ -0,0 +1,11 @@
+fileFormatVersion: 2
+guid: 57cc7b16eb4146c4ab5631f538e2489f
+MonoImporter:
+ externalObjects: {}
+ serializedVersion: 2
+ defaultReferences: []
+ executionOrder: 0
+ icon: {instanceID: 0}
+ userData:
+ assetBundleName:
+ assetBundleVariant:
diff --git a/Assets/ThirdParty/VRM/MeshUtility/Editor/MeshUtility.Editor.asmdef b/Assets/ThirdParty/VRM/MeshUtility/Editor/MeshUtility.Editor.asmdef
new file mode 100644
index 00000000..9854cd8f
--- /dev/null
+++ b/Assets/ThirdParty/VRM/MeshUtility/Editor/MeshUtility.Editor.asmdef
@@ -0,0 +1,16 @@
+{
+ "name": "MeshUtility.Editor",
+ "references": [
+ "MeshUtility"
+ ],
+ "optionalUnityReferences": [],
+ "includePlatforms": [
+ "Editor"
+ ],
+ "excludePlatforms": [],
+ "allowUnsafeCode": false,
+ "overrideReferences": false,
+ "precompiledReferences": [],
+ "autoReferenced": true,
+ "defineConstraints": []
+} \ No newline at end of file
diff --git a/Assets/ThirdParty/VRM/MeshUtility/Editor/MeshUtility.Editor.asmdef.meta b/Assets/ThirdParty/VRM/MeshUtility/Editor/MeshUtility.Editor.asmdef.meta
new file mode 100644
index 00000000..ad84160c
--- /dev/null
+++ b/Assets/ThirdParty/VRM/MeshUtility/Editor/MeshUtility.Editor.asmdef.meta
@@ -0,0 +1,7 @@
+fileFormatVersion: 2
+guid: eedb868807606df4db953419ab9e0780
+AssemblyDefinitionImporter:
+ externalObjects: {}
+ userData:
+ assetBundleName:
+ assetBundleVariant:
diff --git a/Assets/ThirdParty/VRM/MeshUtility/Editor/MeshUtility.cs b/Assets/ThirdParty/VRM/MeshUtility/Editor/MeshUtility.cs
new file mode 100644
index 00000000..045879c6
--- /dev/null
+++ b/Assets/ThirdParty/VRM/MeshUtility/Editor/MeshUtility.cs
@@ -0,0 +1,286 @@
+using System.Collections.Generic;
+using System.IO;
+using System.Linq;
+using UnityEngine;
+using UnityEditor;
+
+namespace MeshUtility
+{
+ public class MeshUtility
+ {
+ public const string MENU_PARENT = "Mesh Utility/";
+ public const int MENU_PRIORITY = 11;
+
+ private const string ASSET_SUFFIX = ".mesh.asset";
+ private const string MENU_NAME = MENU_PARENT + "MeshSeparator";
+ private static readonly Vector3 ZERO_MOVEMENT = Vector3.zero;
+
+ public static Object GetPrefab(GameObject instance)
+ {
+#if UNITY_2018_2_OR_NEWER
+ return PrefabUtility.GetCorrespondingObjectFromSource(instance);
+#else
+ return PrefabUtility.GetPrefabParent(go);
+#endif
+ }
+
+ private enum BlendShapeLogic
+ {
+ WithBlendShape,
+ WithoutBlendShape,
+ }
+
+ [MenuItem(MENU_NAME, validate = true)]
+ private static bool ShowLogValidation()
+ {
+ if (Selection.activeTransform == null)
+ return false;
+ else
+ return true;
+ }
+
+ [MenuItem(MENU_NAME, priority = 2)]
+ public static void SeparateSkinnedMeshContainedBlendShape()
+ {
+ var go = Selection.activeTransform.gameObject;
+
+ if (go.GetComponentsInChildren<SkinnedMeshRenderer>().Length > 0)
+ {
+ SeparationProcessing(go);
+ go.SetActive(false);
+ }
+ else
+ {
+ EditorUtility.DisplayDialog("Error", "No skinnedMeshRenderer contained", "ok");
+ }
+ }
+
+ [MenuItem("Mesh Utility/MeshSeparator Docs", priority = MeshUtility.MENU_PRIORITY)]
+ public static void LinkToMeshSeparatorDocs()
+ {
+ Application.OpenURL("https://github.com/vrm-c/UniVRM/tree/master/Assets/MeshUtility");
+ }
+
+ private static void SeparationProcessing(GameObject go)
+ {
+ var outputObject = GameObject.Instantiate(go);
+ var skinnedMeshRenderers = outputObject.GetComponentsInChildren<SkinnedMeshRenderer>();
+ foreach (var skinnedMeshRenderer in skinnedMeshRenderers)
+ {
+ if (skinnedMeshRenderer.sharedMesh.blendShapeCount > 0)
+ {
+ SeparatePolyWithBlendShape(skinnedMeshRenderer);
+ }
+ }
+ }
+
+ private static void SeparatePolyWithBlendShape(SkinnedMeshRenderer skinnedMeshRendererInput)
+ {
+ var indicesUsedByBlendShape = new Dictionary<int, int>();
+ var mesh = skinnedMeshRendererInput.sharedMesh;
+
+ // retrieve the original BlendShape data
+ for (int i = 0; i < mesh.blendShapeCount; ++i)
+ {
+ var deltaVertices = new Vector3[mesh.vertexCount];
+ var deltaNormals = new Vector3[mesh.vertexCount];
+ var deltaTangents = new Vector3[mesh.vertexCount];
+ mesh.GetBlendShapeFrameVertices(i, 0, deltaVertices, deltaNormals, deltaTangents);
+
+ for (int j = 0; j < deltaVertices.Length; j++)
+ {
+ if (!deltaVertices[j].Equals(ZERO_MOVEMENT))
+ {
+ if (!indicesUsedByBlendShape.Values.Contains(j))
+ {
+ indicesUsedByBlendShape.Add(indicesUsedByBlendShape.Count, j);
+ }
+ }
+ }
+ }
+
+ var subMeshCount = mesh.subMeshCount;
+ var submeshesWithBlendShape = new Dictionary<int, int[]>();
+ var submeshesWithoutBlendShape = new Dictionary<int, int[]>();
+ var vertexIndexWithBlendShape = new Dictionary<int, int>();
+ var vertexCounterWithBlendShape = 0;
+ var vertexIndexWithoutBlendShape = new Dictionary<int, int>();
+ var vertexCounterWithoutBlendShape = 0;
+
+ // check blendshape's vertex index from submesh
+ for (int i = 0; i < subMeshCount; i++)
+ {
+ var triangle = mesh.GetTriangles(i);
+ var submeshWithBlendShape = new List<int>();
+ var submeshWithoutBlendShape = new List<int>();
+
+ for (int j = 0; j < triangle.Length; j += 3)
+ {
+ if (indicesUsedByBlendShape.Values.Contains(triangle[j]) ||
+ indicesUsedByBlendShape.Values.Contains(triangle[j + 1]) ||
+ indicesUsedByBlendShape.Values.Contains(triangle[j + 2]))
+ {
+ BuildNewTriangleList(vertexIndexWithBlendShape, triangle, j, submeshWithBlendShape, ref vertexCounterWithBlendShape);
+ }
+ else
+ {
+ BuildNewTriangleList(vertexIndexWithoutBlendShape, triangle, j, submeshWithoutBlendShape, ref vertexCounterWithoutBlendShape);
+ }
+ }
+ if (submeshWithBlendShape.Count > 0)
+ submeshesWithBlendShape.Add(i, submeshWithBlendShape.ToArray());
+ if (submeshWithoutBlendShape.Count > 0)
+ submeshesWithoutBlendShape.Add(i, submeshWithoutBlendShape.ToArray()); ;
+ }
+
+ // check if any BlendShape exists
+ if (submeshesWithoutBlendShape.Count > 0)
+ {
+ // put the mesh without BlendShape in a new SkinnedMeshRenderer
+ var srcGameObject = skinnedMeshRendererInput.gameObject;
+ var srcTransform = skinnedMeshRendererInput.transform.parent;
+ var targetObjectForMeshWithoutBS = GameObject.Instantiate(srcGameObject);
+ targetObjectForMeshWithoutBS.name = srcGameObject.name + "_WithoutBlendShape";
+ targetObjectForMeshWithoutBS.transform.SetParent(srcTransform);
+ var skinnedMeshRendererWithoutBS = targetObjectForMeshWithoutBS.GetComponent<SkinnedMeshRenderer>();
+
+ // build meshes with/without BlendShape
+ BuildNewMesh(skinnedMeshRendererInput, vertexIndexWithBlendShape, submeshesWithBlendShape, BlendShapeLogic.WithBlendShape);
+ BuildNewMesh(skinnedMeshRendererWithoutBS, vertexIndexWithoutBlendShape, submeshesWithoutBlendShape, BlendShapeLogic.WithoutBlendShape);
+ }
+ }
+
+ private static void BuildNewTriangleList(Dictionary<int, int> newVerticesListLookUp, int[] triangleList, int index,
+ List<int> newTriangleList, ref int vertexCounter)
+ {
+ // build new vertex list and triangle list
+ // vertex 1
+ if (!newVerticesListLookUp.Keys.Contains(triangleList[index]))
+ {
+ newVerticesListLookUp.Add(triangleList[index], vertexCounter);
+ newTriangleList.Add(vertexCounter);
+ vertexCounter++;
+ }
+ else
+ {
+ var newVertexIndex = newVerticesListLookUp[triangleList[index]];
+ newTriangleList.Add(newVertexIndex);
+ }
+ // vertex 2
+ if (!newVerticesListLookUp.Keys.Contains(triangleList[index + 1]))
+ {
+ newVerticesListLookUp.Add(triangleList[index + 1], vertexCounter);
+ newTriangleList.Add(vertexCounter);
+ vertexCounter++;
+ }
+ else
+ {
+ var newVertexIndex = newVerticesListLookUp[triangleList[index + 1]];
+ newTriangleList.Add(newVertexIndex);
+ }
+ // vertex 3
+ if (!newVerticesListLookUp.Keys.Contains(triangleList[index + 2]))
+ {
+ newVerticesListLookUp.Add(triangleList[index + 2], vertexCounter);
+ newTriangleList.Add(vertexCounter);
+ vertexCounter++;
+ }
+ else
+ {
+ var newVertexIndex = newVerticesListLookUp[triangleList[index + 2]];
+ newTriangleList.Add(newVertexIndex);
+ }
+ }
+
+ private static void BuildNewMesh(SkinnedMeshRenderer skinnedMeshRenderer, Dictionary<int, int> newIndexLookUpDict,
+ Dictionary<int, int[]> subMeshes, BlendShapeLogic blendShapeLabel)
+ {
+ // get original mesh data
+ var materialList = new List<Material>();
+ skinnedMeshRenderer.GetSharedMaterials(materialList);
+ var mesh = skinnedMeshRenderer.sharedMesh;
+ var meshVertices = mesh.vertices;
+ var meshNormals = mesh.normals;
+ var meshTangents = mesh.tangents;
+ var meshColors = mesh.colors;
+ var meshBoneWeights = mesh.boneWeights;
+ var meshUVs = mesh.uv;
+
+ // build new mesh
+ var materialListNew = new List<Material>();
+ var newMesh = new Mesh();
+
+ if (mesh.vertexCount > ushort.MaxValue)
+ {
+#if UNITY_2017_3_OR_NEWER
+ Debug.LogFormat("exceed 65535 vertices: {0}", mesh.vertexCount);
+ newMesh.indexFormat = UnityEngine.Rendering.IndexFormat.UInt32;
+#else
+ throw new NotImplementedException(String.Format("exceed 65535 vertices: {0}", integrator.Positions.Count.ToString()));
+#endif
+ }
+
+ var newDataLength = newIndexLookUpDict.Count;
+ var newIndexLookUp = newIndexLookUpDict.Keys.ToArray();
+
+ newMesh.vertices = newIndexLookUp.Select(x => meshVertices[x]).ToArray();
+ if (meshNormals.Length > 0) newMesh.normals = newIndexLookUp.Select(x => meshNormals[x]).ToArray();
+ if (meshTangents.Length > 0) newMesh.tangents = newIndexLookUp.Select(x => meshTangents[x]).ToArray();
+ if (meshColors.Length > 0) newMesh.colors = newIndexLookUp.Select(x => meshColors[x]).ToArray();
+ if (meshBoneWeights.Length > 0) newMesh.boneWeights = newIndexLookUp.Select(x => meshBoneWeights[x]).ToArray();
+ if (meshUVs.Length > 0) newMesh.uv = newIndexLookUp.Select(x => meshUVs[x]).ToArray();
+ newMesh.bindposes = mesh.bindposes;
+
+ // add BlendShape data
+ if (blendShapeLabel == BlendShapeLogic.WithBlendShape)
+ {
+ for (int i = 0; i < mesh.blendShapeCount; i++)
+ {
+ // get original BlendShape data
+ var srcVertices = new Vector3[mesh.vertexCount];
+ var srcNormals = new Vector3[mesh.vertexCount];
+ var srcTangents = new Vector3[mesh.vertexCount];
+ mesh.GetBlendShapeFrameVertices(i, 0, srcVertices, srcNormals, srcTangents);
+
+ // declare the size for the destination array
+ var dstVertices = new Vector3[newDataLength];
+ var dstNormals = new Vector3[newDataLength];
+ var dstTangents = new Vector3[newDataLength];
+
+ dstVertices = newIndexLookUp.Select(x => srcVertices[x]).ToArray();
+ dstNormals = newIndexLookUp.Select(x => srcNormals[x]).ToArray();
+ dstTangents = newIndexLookUp.Select(x => srcTangents[x]).ToArray();
+ newMesh.AddBlendShapeFrame(mesh.GetBlendShapeName(i), mesh.GetBlendShapeFrameWeight(i, 0),
+ dstVertices, dstNormals, dstTangents);
+ }
+ }
+
+ newMesh.subMeshCount = subMeshes.Count;
+ var cosMaterialIndex = subMeshes.Keys.ToArray();
+
+ // build material list
+ for (int i = 0; i < subMeshes.Count; i++)
+ {
+ newMesh.SetTriangles(subMeshes[cosMaterialIndex[i]], i);
+ materialListNew.Add(materialList[cosMaterialIndex[i]]);
+ }
+ skinnedMeshRenderer.sharedMaterials = materialListNew.ToArray();
+ skinnedMeshRenderer.sharedMesh = newMesh;
+
+ // save mesh as asset
+ var assetPath = string.Format("{0}{1}", Path.GetFileNameWithoutExtension(mesh.name), ASSET_SUFFIX);
+ Debug.Log(assetPath);
+ if (!string.IsNullOrEmpty((AssetDatabase.GetAssetPath(mesh))))
+ {
+ var directory = Path.GetDirectoryName(AssetDatabase.GetAssetPath(mesh)).Replace("\\", "/");
+ assetPath = string.Format("{0}/{1}{2}", directory, Path.GetFileNameWithoutExtension(mesh.name) + "_" + blendShapeLabel.ToString(), ASSET_SUFFIX);
+ }
+ else
+ {
+ assetPath = string.Format("Assets/{0}{1}", Path.GetFileNameWithoutExtension(mesh.name) + "_" + blendShapeLabel.ToString(), ASSET_SUFFIX);
+ }
+ Debug.LogFormat("CreateAsset: {0}", assetPath);
+ AssetDatabase.CreateAsset(newMesh, assetPath);
+ }
+ }
+} \ No newline at end of file
diff --git a/Assets/ThirdParty/VRM/MeshUtility/Editor/MeshUtility.cs.meta b/Assets/ThirdParty/VRM/MeshUtility/Editor/MeshUtility.cs.meta
new file mode 100644
index 00000000..2fb0aadd
--- /dev/null
+++ b/Assets/ThirdParty/VRM/MeshUtility/Editor/MeshUtility.cs.meta
@@ -0,0 +1,11 @@
+fileFormatVersion: 2
+guid: c1bbe850b95e44740bbbb44064e17d25
+MonoImporter:
+ externalObjects: {}
+ serializedVersion: 2
+ defaultReferences: []
+ executionOrder: 0
+ icon: {instanceID: 0}
+ userData:
+ assetBundleName:
+ assetBundleVariant: