205 lines
5.4 KiB
C#
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);
|
|
}
|
|
}
|
|
}
|
|
|
|
}
|
|
} |