您最多选择25个主题
主题必须以中文或者字母或数字开头,可以包含连字符 (-),并且长度不得超过35个字符
154 行
4.0 KiB
154 行
4.0 KiB
using System;
|
|
using System.Collections.Generic;
|
|
using UnityEngine;
|
|
using UnityEngine.Serialization;
|
|
|
|
[ExecuteAlways]
|
|
public class Skeleton : MonoBehaviour, ISkeletonTypeComponent//
|
|
{
|
|
public static event Action<Skeleton> SkeletonEnabled;
|
|
public static event Action<Skeleton> SkeletonDisabled;
|
|
|
|
public bool drawSkeleton;
|
|
public Color skeletonColor = Color.green;
|
|
[Range(0.01f, 5.0f)]
|
|
public float boneSize = 1.0f;
|
|
public bool drawTripods;
|
|
|
|
|
|
// TODO: Make bone arrays show up in editor as read only @sunek
|
|
[FormerlySerializedAs("m_Bones")]
|
|
public Transform[] bones;
|
|
[FormerlySerializedAs("m_BoneNames")]
|
|
public int[] nameHashes;
|
|
[FormerlySerializedAs("m_ParentIndex")]
|
|
public int[] parentIndex;
|
|
[FormerlySerializedAs("m_Bindpose")]
|
|
public Bonepose[] importPose;
|
|
|
|
[Serializable]
|
|
public struct Bonepose
|
|
{
|
|
public Vector3 localPosition;
|
|
public Quaternion localRotation;
|
|
public Vector3 localScale;
|
|
}
|
|
|
|
#if UNITY_EDITOR
|
|
void Start()
|
|
{
|
|
skeletonColor = UnityEngine.Random.ColorHSV(0f, 1f, 1f, 1f, 1f, 1f, 1f, 1f);
|
|
}
|
|
|
|
void OnEnable()
|
|
{
|
|
if (SkeletonEnabled != null)
|
|
{
|
|
SkeletonEnabled(this);
|
|
}
|
|
}
|
|
|
|
void OnDisable()
|
|
{
|
|
if (SkeletonDisabled != null)
|
|
{
|
|
SkeletonDisabled(this);
|
|
}
|
|
}
|
|
#endif
|
|
|
|
public bool StoreBoneData(Transform skeletonRoot)
|
|
{
|
|
if (!skeletonRoot)
|
|
{
|
|
bones = new Transform[0];
|
|
nameHashes = new int[0];
|
|
parentIndex = new int[0];
|
|
importPose = new Bonepose[0];
|
|
return false;
|
|
}
|
|
|
|
var boneList = new List<Transform>();
|
|
GetBones(skeletonRoot, skeletonRoot, ref boneList);
|
|
|
|
var numBones = boneList.Count;
|
|
bones = boneList.ToArray();
|
|
|
|
nameHashes = new int[numBones];
|
|
importPose = new Bonepose[numBones];
|
|
|
|
for (var i = 0; i < numBones; i++)
|
|
{
|
|
string boneName = bones[i].gameObject.name;
|
|
int hashCode = boneName.GetHashCode();
|
|
nameHashes[i] = hashCode;
|
|
var bindpose = new Bonepose
|
|
{
|
|
localPosition = bones[i].localPosition,
|
|
localRotation = bones[i].localRotation,
|
|
localScale = bones[i].localScale
|
|
};
|
|
|
|
importPose[i] = bindpose;
|
|
}
|
|
|
|
parentIndex = new int[numBones];
|
|
for (var i = 0; i < numBones; i++)
|
|
{
|
|
parentIndex[i] = GetBoneIndex(bones[i].parent.gameObject.name.GetHashCode());
|
|
}
|
|
return true;
|
|
}
|
|
|
|
public int GetBoneIndex(int stringHash)
|
|
{
|
|
// TODO: (sunek) Consider lazily building a persisted hashmap or do binary search on a sorted hash sequence
|
|
var numBones = bones.Length;
|
|
for (var i = 0; i < numBones; i++)
|
|
{
|
|
if (nameHashes[i] == stringHash)
|
|
return i;
|
|
}
|
|
|
|
return -1;
|
|
}
|
|
|
|
static void GetBones(Transform t, Transform skeletonRoot, ref List<Transform> boneList)
|
|
{
|
|
var bonesToProcess = new Queue<Transform>();
|
|
bonesToProcess.Enqueue(t);
|
|
|
|
while (bonesToProcess.Count > 0)
|
|
{
|
|
var currentBone = bonesToProcess.Dequeue();
|
|
boneList.Add(currentBone);
|
|
|
|
var numChildren = currentBone.childCount;
|
|
for (var i = 0; i < numChildren; i++)
|
|
{
|
|
bonesToProcess.Enqueue(currentBone.GetChild(i));
|
|
}
|
|
}
|
|
}
|
|
|
|
public bool GotoBindpose()
|
|
{
|
|
var numBones = bones.Length;
|
|
if (numBones == 0 || numBones != importPose.Length)
|
|
{
|
|
return false;
|
|
}
|
|
|
|
for (var i = 0; i < numBones; i++)
|
|
{
|
|
if (bones[i] != null)
|
|
{
|
|
bones[i].localPosition = importPose[i].localPosition;
|
|
bones[i].localRotation = importPose[i].localRotation;
|
|
bones[i].localScale = importPose[i].localScale;
|
|
}
|
|
}
|
|
|
|
return true;
|
|
}
|
|
}
|