using System.Collections.Generic; using UnityEditor; using UnityEngine; namespace FluffyGroomingTool { public class BindPoseHelper { private Dictionary bindPoseMap; public bool isInBindPose; public void updateBindPoseState(FurCreator furCreator) { if (furCreator.FurRenderer.CurrentRenderer is SkinnedMeshRenderer renderer) { if (bindPoseMap == null) bindPoseMap = createBindPoseMap(getSkinnedMeshRenderers(renderer)); isInBindPose = checkBindPose(renderer); } else { isInBindPose = true; } } private bool checkBindPose(SkinnedMeshRenderer skinnedMeshRenderer) { foreach (var kvp in bindPoseMap) { Transform boneTrans = kvp.Key; if (boneTrans == null) { bindPoseMap = null; break; } if (boneTrans != skinnedMeshRenderer.rootBone) { Matrix4x4 bindPose = kvp.Value; var parent = boneTrans.parent; Matrix4x4 localMatrix = bindPoseMap.ContainsKey(parent) ? (bindPose * bindPoseMap[parent].inverse).inverse : bindPose.inverse; var bindPoseScale = new Vector3( localMatrix.GetColumn(0).magnitude, localMatrix.GetColumn(1).magnitude, localMatrix.GetColumn(2).magnitude ); if (boneTrans.localPosition != localMatrix.MultiplyPoint(Vector3.zero) || boneTrans.localRotation != Quaternion.LookRotation(localMatrix.GetColumn(2), localMatrix.GetColumn(1)) || boneTrans.localScale != bindPoseScale) { return false; } } } return true; } private const int CancelOption = 1; public void restoreBindPose(FurCreator furCreator) { var dialogSelection = EditorUtility.DisplayDialogComplex("Restore Bind Pose", "This will restore the rotation and scale bind poses. " + "Restoring the position bind pose may in some cases give buggy results. " + "Would you like to exclude the position property?", "Yes", "Cancel", "No"); if (dialogSelection != CancelOption) { if (furCreator.FurRenderer.CurrentRenderer is SkinnedMeshRenderer renderer) { foreach (var kvp in bindPoseMap) { Transform boneTrans = kvp.Key; if (boneTrans != renderer.rootBone) { Matrix4x4 bindPose = kvp.Value; var parent = boneTrans.parent; Undo.RecordObject(parent, "undo"); Matrix4x4 localMatrix = bindPoseMap.ContainsKey(parent) ? (bindPose * bindPoseMap[parent].inverse).inverse : bindPose.inverse; Undo.RegisterCompleteObjectUndo(boneTrans, "Undo: " + boneTrans.name); if (dialogSelection == 0) { boneTrans.localPosition = localMatrix.MultiplyPoint(Vector3.zero); } boneTrans.localRotation = Quaternion.LookRotation(localMatrix.GetColumn(2), localMatrix.GetColumn(1)); boneTrans.localScale = new Vector3( localMatrix.GetColumn(0).magnitude, localMatrix.GetColumn(1).magnitude, localMatrix.GetColumn(2).magnitude ); } } } } } private static Dictionary createBindPoseMap(SkinnedMeshRenderer[] renderers) { Dictionary bindPoseMap = new Dictionary(); foreach (var smr in renderers) { for (int i = 0; i < smr.bones.Length; i++) { var smrBone = smr.bones[i]; if (smrBone != null && !bindPoseMap.ContainsKey(smrBone)) { bindPoseMap.Add(smrBone, smr.sharedMesh.bindposes[i]); } } } return bindPoseMap; } private SkinnedMeshRenderer[] getSkinnedMeshRenderers(SkinnedMeshRenderer skinnedMeshRenderer) { var parent = skinnedMeshRenderer.transform.parent; return parent != null ? parent.GetComponentsInChildren() : skinnedMeshRenderer.transform.GetComponentsInChildren(); } public void reset() { bindPoseMap.Clear(); bindPoseMap = null; } } }