Files
SimUL/Assets/UMA/Core/Scripts/SkeletonTools.cs
T
2025-01-07 18:54:46 +02:00

205 lines
5.4 KiB
C#

using UnityEngine;
namespace UMA
{
public static class SkeletonTools
{
#if UNITY_EDITOR
[UnityEditor.MenuItem("UMA/Verify Slot Mesh")]
static void Start()
{
var transforms = UnityEditor.Selection.GetTransforms(UnityEditor.SelectionMode.Editable);
if (transforms.Length != 2)
{
if(Debug.isDebugBuild)
{
Debug.LogError("To Compare Skeletons you need to select two characters in your hierarchy.");
}
return;
}
var root1 = LocateRoot(transforms[0]);
var root2 = LocateRoot(transforms[1]);
int failure = 0;
CompareSkeletonRecursive(root1, root2, ref failure);
}
#endif
private static void CompareRootBone(Transform raceRoot, Transform slotRoot, ref int failure)
{
var rootIterator = slotRoot;
while (rootIterator.parent != null)
{
rootIterator = rootIterator.parent;
}
if (RecursiveFindBone(rootIterator, raceRoot) == null)
{
if (Debug.isDebugBuild)
{
Debug.LogError("Race root: " + raceRoot.name + " not found in the slot hierarchy");
}
failure++;
}
}
private static Transform RecursiveFindBone(Transform bone, Transform raceRoot)
{
if (bone.name == raceRoot.name)
{
return bone;
}
for (int i = 0; i < bone.childCount; i++)
{
var result = RecursiveFindBone(bone.GetChild(i), raceRoot);
if (result != null)
{
return result;
}
}
return null;
}
public static Transform RecursiveFindBone(Transform bone, string Name)
{
if (bone.name == Name)
{
return bone;
}
for (int i = 0; i < bone.childCount; i++)
{
var result = RecursiveFindBone(bone.GetChild(i), Name);
if (result != null)
{
return result;
}
}
return null;
}
private static void CompareSkeletonRecursive(Transform race, Transform slot, ref int failure)
{
if ((race.localScale - slot.localScale).sqrMagnitude > 0.0001f)
{
failure++;
if (Debug.isDebugBuild)
{
Debug.LogError("Scale on " + race.name + " differs by " + (race.localScale - slot.localScale), slot);
}
}
if ((race.localPosition - slot.localPosition).sqrMagnitude > 0.0001f)
{
failure++;
if (Debug.isDebugBuild)
{
Debug.LogError("Position on " + race.name + " differs by " + (race.localPosition - slot.localPosition), slot);
}
}
if (race.localRotation != slot.localRotation)
{
failure++;
if (Debug.isDebugBuild)
{
Debug.LogError("Rotation on " + race.name + " differs by " + Quaternion.Angle(race.localRotation, slot.localRotation) + " degrees", slot);
}
}
for (int i = 0; i < race.childCount; i++)
{
var raceChild = race.GetChild(i);
var slotChild = slot.Find(raceChild.name);
if (slotChild != null)
{
CompareSkeletonRecursive(raceChild, slotChild, ref failure);
}
else
{
failure++;
if (Debug.isDebugBuild)
{
Debug.LogError("Bone is missing: " + raceChild.name + " on bone: " + slot.name, slot);
}
}
if (failure >= 50)
{
return;
}
}
}
public static Transform LocateRoot(Transform parent)
{
for (int i = 0; i < parent.childCount; i++)
{
var child = parent.GetChild(i);
if (child.childCount == 0)
{
continue;
}
return child;
}
return null;
}
public enum ValidateResult
{
Ok,
InvalidScale,
SkeletonProblem,
}
public static ValidateResult ValidateSlot(SkinnedMeshRenderer RaceSMR, SkinnedMeshRenderer SlotSMR, out string description)
{
var slotMesh = new Mesh();
#if UMA_32BITBUFFERS
slotMesh.indexFormat = UnityEngine.Rendering.IndexFormat.UInt32;
#endif
SlotSMR.BakeMesh(slotMesh);
var bounds = slotMesh.bounds;
if (bounds.max.y < 0.05f)
{
description = "Scale Factor on the Model Import Settings seems to be wrong!";
return ValidateResult.InvalidScale;
}
int failure = 0;
CompareSkeletonRecursive(LocateRoot(RaceSMR.transform.parent), LocateRoot(SlotSMR.transform.parent), ref failure);
CompareRootBone(RaceSMR.rootBone, SlotSMR.rootBone, ref failure);
if (failure > 0)
{
description = "The Skeleton Hierarchy seems off, check the log for more info.";
return ValidateResult.SkeletonProblem;
}
description = "Everything seems fine.";
return ValidateResult.Ok;
}
public static void ForceSkeleton(SkinnedMeshRenderer SourceSMR, SkinnedMeshRenderer DestSMR)
{
ForceSkeletonRecursive(LocateRoot(SourceSMR.transform.parent), LocateRoot(DestSMR.transform.parent));
}
private static void ForceSkeletonRecursive(Transform source, Transform dest)
{
dest.localScale = source.localScale;
dest.localPosition = source.localPosition;
dest.localRotation = source.localRotation;
for (int i = 0; i < source.childCount; i++)
{
var raceChild = source.GetChild(i);
var slotChild = dest.Find(raceChild.name);
if (slotChild != null)
{
ForceSkeletonRecursive(raceChild, slotChild);
}
}
}
}
}