using System; using System.Collections.Generic; using UnityEngine; using UnityEditor; namespace DreadScripts.ResetHumanoid { public class ResetHumanoid : EditorWindow { private static Animator ani; private static bool full; private static bool pos = true, rot = true, scale = true; [MenuItem("DreadTools/Utility/Reset Humanoid")] private static void showWindow() { GetWindow(false, "Reset Humanoid", true); if (ani == null) ani = FindObjectOfType(); } private void OnGUI() { EditorGUIUtility.labelWidth = 60; ani = (Animator) EditorGUILayout.ObjectField("Avatar", ani, typeof(Animator), true); EditorGUILayout.BeginHorizontal(); pos = EditorGUILayout.Toggle("Position", pos); rot = EditorGUILayout.Toggle("Rotation", rot); scale = EditorGUILayout.Toggle("Scale", scale); EditorGUIUtility.labelWidth = 0; EditorGUILayout.EndHorizontal(); full = EditorGUILayout.Toggle(new GUIContent("Full Reset", "Reset includes the objects that the Model was imported with"), full); if (GUILayout.Button("Reset")) ResetPose(ani, full, pos, rot, scale); } public static void ResetPose(Animator ani, bool fullReset = false, bool position = true, bool rotation = true, bool scale = true) { if (!ani.avatar) { Debug.LogWarning("Avatar is required to reset pose!"); return; } // Humans IDs if not full reset, otherwise All Ids // ID > Path // ID > Element > Transform Data Undo.RegisterFullObjectHierarchyUndo(ani.gameObject, "HierarchyReset"); SerializedObject sAvi = new SerializedObject(ani.avatar); SerializedProperty humanIds = sAvi.FindProperty("m_Avatar.m_Human.data.m_Skeleton.data.m_ID"); SerializedProperty allIds = sAvi.FindProperty("m_Avatar.m_AvatarSkeleton.data.m_ID"); SerializedProperty defaultPose = sAvi.FindProperty("m_Avatar.m_DefaultPose.data.m_X"); SerializedProperty tos = sAvi.FindProperty("m_TOS"); Dictionary idToElem = new Dictionary(); Dictionary elemToTransform = new Dictionary(); Dictionary IdToPath = new Dictionary(); for (int i = 0; i < allIds.arraySize; i++) idToElem.Add(allIds.GetArrayElementAtIndex(i).longValue, i); for (int i = 0; i < defaultPose.arraySize; i++) elemToTransform.Add(i, new TransformData(defaultPose.GetArrayElementAtIndex(i))); for (int i = 0; i < tos.arraySize; i++) { SerializedProperty currProp = tos.GetArrayElementAtIndex(i); IdToPath.Add(currProp.FindPropertyRelative("first").longValue, currProp.FindPropertyRelative("second").stringValue); } Action applyTransform = (transform, data) => { if (transform) { if (position) transform.localPosition = data.pos; if (rotation) transform.localRotation = data.rot; if (scale) transform.localScale = data.scale; } }; if (!fullReset) { for (int i = 0; i < humanIds.arraySize; i++) { Transform myBone = ani.transform.Find(IdToPath[humanIds.GetArrayElementAtIndex(i).longValue]); TransformData data = elemToTransform[idToElem[humanIds.GetArrayElementAtIndex(i).longValue]]; applyTransform(myBone, data); } } else { for (int i = 0; i < allIds.arraySize; i++) { Transform myBone = ani.transform.Find(IdToPath[allIds.GetArrayElementAtIndex(i).longValue]); TransformData data = elemToTransform[idToElem[allIds.GetArrayElementAtIndex(i).longValue]]; applyTransform(myBone, data); } } } struct TransformData { public Vector3 pos; public Quaternion rot; public Vector3 scale; public TransformData(SerializedProperty t) { SerializedProperty tProp = t.FindPropertyRelative("t"); SerializedProperty qProp = t.FindPropertyRelative("q"); SerializedProperty sProp = t.FindPropertyRelative("s"); pos = new Vector3(tProp.FindPropertyRelative("x").floatValue, tProp.FindPropertyRelative("y").floatValue, tProp.FindPropertyRelative("z").floatValue); rot = new Quaternion(qProp.FindPropertyRelative("x").floatValue, qProp.FindPropertyRelative("y").floatValue, qProp.FindPropertyRelative("z").floatValue, qProp.FindPropertyRelative("w").floatValue); scale = new Vector3(sProp.FindPropertyRelative("x").floatValue, sProp.FindPropertyRelative("y").floatValue, sProp.FindPropertyRelative("z").floatValue); } } } }