159 lines
4.5 KiB
C#
159 lines
4.5 KiB
C#
using System.Collections.Generic;
|
|
using System.Linq;
|
|
using UnityEngine;
|
|
// using UniGLTF;
|
|
#if UNITY_EDITOR
|
|
using UnityEditor;
|
|
#endif
|
|
|
|
|
|
namespace UniGLTF.MeshUtility
|
|
{
|
|
[DisallowMultipleComponent]
|
|
public class BindposeGizmo : MonoBehaviour
|
|
{
|
|
[SerializeField]
|
|
Mesh m_target;
|
|
|
|
[SerializeField]
|
|
float[] m_boneWeights;
|
|
|
|
[SerializeField, Range(0.1f, 1.0f)]
|
|
float m_gizmoSize = 0.02f;
|
|
|
|
[SerializeField]
|
|
Color m_meshGizmoColor = Color.yellow;
|
|
|
|
[SerializeField]
|
|
Color m_bindGizmoColor = Color.red;
|
|
|
|
private void Reset()
|
|
{
|
|
var renderer = GetComponent<SkinnedMeshRenderer>();
|
|
if (renderer == null) return;
|
|
m_target = renderer.sharedMesh;
|
|
}
|
|
|
|
#if UNITY_EDITOR
|
|
#region ToBindpose
|
|
[ContextMenu("ToBindpose")]
|
|
void ToBindpose()
|
|
{
|
|
var renderer = GetComponent<SkinnedMeshRenderer>();
|
|
|
|
var root =
|
|
renderer.bones
|
|
.Select(x => Ancestors(x).Reverse().ToArray())
|
|
.Aggregate((a, b) =>
|
|
{
|
|
int i = 0;
|
|
for (; i < a.Length && i < b.Length; ++i)
|
|
{
|
|
if (a[i] != b[i])
|
|
{
|
|
break;
|
|
}
|
|
}
|
|
return a.Take(i).ToArray();
|
|
})
|
|
.Last()
|
|
;
|
|
|
|
var map = new Dictionary<Transform, Matrix4x4>();
|
|
for (int i = 0; i < renderer.bones.Length; ++i)
|
|
{
|
|
map[renderer.bones[i]] = m_target.bindposes[i];
|
|
}
|
|
|
|
{
|
|
var bones = Traverse(root);
|
|
Undo.RecordObjects(bones.ToArray(), "toBindpose");
|
|
|
|
foreach (var x in bones)
|
|
{
|
|
var bind = default(Matrix4x4);
|
|
if (map.TryGetValue(x, out bind))
|
|
{
|
|
var toWorld = renderer.transform.localToWorldMatrix * bind.inverse;
|
|
x.position = toWorld.GetColumn(3);
|
|
x.rotation = toWorld.ExtractRotation();
|
|
}
|
|
}
|
|
|
|
//EditorUtility.SetDirty(transform);
|
|
}
|
|
}
|
|
|
|
IEnumerable<Transform> Traverse(Transform self)
|
|
{
|
|
yield return self;
|
|
|
|
foreach (Transform child in self)
|
|
{
|
|
foreach (var x in Traverse(child))
|
|
{
|
|
yield return x;
|
|
}
|
|
}
|
|
}
|
|
|
|
IEnumerable<Transform> Ancestors(Transform self)
|
|
{
|
|
yield return self;
|
|
|
|
if (self.parent != null)
|
|
{
|
|
foreach (var x in Ancestors(self.parent))
|
|
{
|
|
yield return x;
|
|
}
|
|
}
|
|
}
|
|
#endregion
|
|
#endif
|
|
|
|
private void OnDrawGizmos()
|
|
{
|
|
if (m_target == null)
|
|
{
|
|
return;
|
|
}
|
|
|
|
Gizmos.matrix = transform.localToWorldMatrix;
|
|
|
|
if (m_target.bindposes != null && m_target.bindposes.Length > 0)
|
|
{
|
|
if (m_boneWeights == null || m_boneWeights.Length != m_target.bindposes.Length)
|
|
{
|
|
m_boneWeights = new float[m_target.bindposes.Length];
|
|
foreach (var bw in m_target.boneWeights)
|
|
{
|
|
if (bw.weight0 > 0) m_boneWeights[bw.boneIndex0] += bw.weight0;
|
|
if (bw.weight1 > 0) m_boneWeights[bw.boneIndex1] += bw.weight1;
|
|
if (bw.weight2 > 0) m_boneWeights[bw.boneIndex2] += bw.weight2;
|
|
if (bw.weight3 > 0) m_boneWeights[bw.boneIndex3] += bw.weight3;
|
|
}
|
|
}
|
|
|
|
Gizmos.color = m_meshGizmoColor;
|
|
Gizmos.DrawWireMesh(m_target);
|
|
|
|
for (var i = 0; i < m_target.bindposes.Length; ++i)
|
|
{
|
|
var color = m_bindGizmoColor * m_boneWeights[i];
|
|
color.a = 1.0f;
|
|
Gizmos.color = color;
|
|
|
|
Gizmos.matrix = transform.localToWorldMatrix * m_target.bindposes[i].inverse;
|
|
Gizmos.DrawWireCube(Vector3.zero, Vector3.one * m_gizmoSize);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
Gizmos.color = Color.gray;
|
|
Gizmos.DrawWireMesh(m_target);
|
|
}
|
|
}
|
|
}
|
|
}
|