275 lines
13 KiB
C#
275 lines
13 KiB
C#
using System;
|
|
using System.Collections.Generic;
|
|
using System.Linq;
|
|
using UnityEngine;
|
|
|
|
|
|
namespace UniHumanoid
|
|
{
|
|
public static class SkeletonMeshUtility
|
|
{
|
|
readonly struct TSRBox
|
|
{
|
|
public readonly Vector3 T;
|
|
public readonly Vector3 S;
|
|
public readonly Quaternion R;
|
|
public readonly Vector3 HeadPosition;
|
|
|
|
public TSRBox(
|
|
Vector3 t,
|
|
Vector3 s,
|
|
Quaternion r,
|
|
Vector3 head)
|
|
{
|
|
T = t;
|
|
S = s;
|
|
R = r;
|
|
HeadPosition = head;
|
|
}
|
|
|
|
public Matrix4x4 ToMatrix()
|
|
{
|
|
return Matrix4x4.Translate(HeadPosition)
|
|
* Matrix4x4.Rotate(R) * Matrix4x4.Scale(S) * Matrix4x4.Translate(T);
|
|
}
|
|
}
|
|
|
|
class MeshBuilder
|
|
{
|
|
List<Vector3> m_positions = new List<Vector3>();
|
|
List<int> m_indices = new List<int>();
|
|
List<BoneWeight> m_boneWeights = new List<BoneWeight>();
|
|
|
|
public void AddBone(Vector3 head, Vector3 tail, int boneIndex, float width, float height, Vector3 xAxis)
|
|
{
|
|
var yAxis = (tail - head).normalized;
|
|
var zAxis = Vector3.Cross(xAxis, yAxis);
|
|
xAxis = Vector3.Cross(yAxis, zAxis);
|
|
|
|
AddBox(boneIndex, new TSRBox
|
|
(
|
|
new Vector3(0, 0.5f, 0),
|
|
new Vector3(width, (tail - head).magnitude, height),
|
|
new Matrix4x4(
|
|
xAxis, yAxis, zAxis, new Vector4(0, 0, 0, 1)
|
|
).rotation,
|
|
head
|
|
));
|
|
}
|
|
|
|
// rotation * scale * beforeTranslation
|
|
void AddBox(int boneIndex, TSRBox box)
|
|
{
|
|
var m = box.ToMatrix();
|
|
|
|
// v6+---+v7
|
|
// v2/| v3|
|
|
// +---+ |
|
|
// | +v5-+v4
|
|
// |/ |/
|
|
// +---+
|
|
// v1 v0
|
|
var s = 0.5f;
|
|
var cube = new Vector3[]
|
|
{
|
|
m.MultiplyPoint(new Vector3(+s, -s, -s)),
|
|
m.MultiplyPoint(new Vector3(-s, -s, -s)),
|
|
m.MultiplyPoint(new Vector3(-s, +s, -s)),
|
|
m.MultiplyPoint(new Vector3(+s, +s, -s)),
|
|
m.MultiplyPoint(new Vector3(+s, -s, +s)),
|
|
m.MultiplyPoint(new Vector3(-s, -s, +s)),
|
|
m.MultiplyPoint(new Vector3(-s, +s, +s)),
|
|
m.MultiplyPoint(new Vector3(+s, +s, +s)),
|
|
};
|
|
|
|
AddQuad(boneIndex, cube[0], cube[1], cube[2], cube[3]);
|
|
AddQuad(boneIndex, cube[1], cube[5], cube[6], cube[2]);
|
|
AddQuad(boneIndex, cube[5], cube[4], cube[7], cube[6]);
|
|
AddQuad(boneIndex, cube[4], cube[0], cube[3], cube[7]);
|
|
AddQuad(boneIndex, cube[3], cube[2], cube[6], cube[7]);
|
|
AddQuad(boneIndex, cube[4], cube[5], cube[1], cube[0]);
|
|
}
|
|
|
|
void AddQuad(int boneIndex, Vector3 v0, Vector3 v1, Vector3 v2, Vector3 v3)
|
|
{
|
|
var i = m_positions.Count;
|
|
m_positions.Add(v0);
|
|
m_positions.Add(v1);
|
|
m_positions.Add(v2);
|
|
m_positions.Add(v3);
|
|
|
|
var bw = new BoneWeight
|
|
{
|
|
boneIndex0 = boneIndex,
|
|
weight0 = 1.0f,
|
|
};
|
|
m_boneWeights.Add(bw);
|
|
m_boneWeights.Add(bw);
|
|
m_boneWeights.Add(bw);
|
|
m_boneWeights.Add(bw);
|
|
|
|
{
|
|
m_indices.Add(i);
|
|
m_indices.Add(i + 1);
|
|
m_indices.Add(i + 2);
|
|
|
|
m_indices.Add(i + 2);
|
|
m_indices.Add(i + 3);
|
|
m_indices.Add(i);
|
|
}
|
|
}
|
|
|
|
public Mesh CreateMesh()
|
|
{
|
|
var mesh = new Mesh();
|
|
mesh.SetVertices(m_positions);
|
|
mesh.boneWeights = m_boneWeights.ToArray();
|
|
mesh.triangles = m_indices.ToArray();
|
|
mesh.RecalculateNormals();
|
|
mesh.RecalculateBounds();
|
|
return mesh;
|
|
}
|
|
}
|
|
|
|
struct BoneHeadTail
|
|
{
|
|
public HumanBodyBones Head;
|
|
public HumanBodyBones Tail;
|
|
public Vector3 TailOffset;
|
|
public float Width;
|
|
public float Height;
|
|
public Vector3 XAxis;
|
|
|
|
public BoneHeadTail(HumanBodyBones head, HumanBodyBones tail, Vector3 xAxis, float width = 0.05f, float height = 0.05f)
|
|
{
|
|
Head = head;
|
|
Tail = tail;
|
|
TailOffset = Vector3.zero;
|
|
XAxis = xAxis;
|
|
Width = width;
|
|
Height = height;
|
|
}
|
|
|
|
public BoneHeadTail(HumanBodyBones head, Vector3 tailOffset, Vector3 xAxis, float width = 0.05f, float height = 0.05f)
|
|
{
|
|
Head = head;
|
|
Tail = HumanBodyBones.LastBone;
|
|
TailOffset = tailOffset;
|
|
XAxis = xAxis;
|
|
Width = width;
|
|
Height = height;
|
|
}
|
|
}
|
|
|
|
static BoneHeadTail[] Bones = new BoneHeadTail[]
|
|
{
|
|
new BoneHeadTail(HumanBodyBones.Hips, HumanBodyBones.Spine, Vector3.right, 0.2f, 0.12f),
|
|
new BoneHeadTail(HumanBodyBones.Spine, HumanBodyBones.Chest, Vector3.right),
|
|
new BoneHeadTail(HumanBodyBones.Chest, HumanBodyBones.Neck, Vector3.right, 0.2f, 0.12f),
|
|
new BoneHeadTail(HumanBodyBones.Neck, HumanBodyBones.Head, Vector3.right, 0.06f, 0.06f),
|
|
new BoneHeadTail(HumanBodyBones.Head, new Vector3(0, 0.2f, 0), Vector3.right, 0.2f, 0.2f),
|
|
// new BoneHeadTail(HumanBodyBones.Head, new Vector3(0, 0, 0.1f), Vector3.right, 0.2f, 0.2f),
|
|
|
|
new BoneHeadTail(HumanBodyBones.LeftShoulder, HumanBodyBones.LeftUpperArm, Vector3.forward),
|
|
new BoneHeadTail(HumanBodyBones.LeftUpperArm, HumanBodyBones.LeftLowerArm, Vector3.forward),
|
|
new BoneHeadTail(HumanBodyBones.LeftLowerArm, HumanBodyBones.LeftHand, Vector3.forward),
|
|
|
|
new BoneHeadTail(HumanBodyBones.LeftHand, HumanBodyBones.LeftMiddleProximal, Vector3.forward, 0.05f, 0.02f),
|
|
new BoneHeadTail(HumanBodyBones.LeftThumbProximal, HumanBodyBones.LeftThumbIntermediate, Vector3.forward, 0.01f, 0.01f),
|
|
new BoneHeadTail(HumanBodyBones.LeftThumbIntermediate, HumanBodyBones.LeftThumbDistal, Vector3.forward, 0.01f, 0.01f),
|
|
new BoneHeadTail(HumanBodyBones.LeftThumbDistal, new Vector3(-0.03f, 0, 0), Vector3.forward, 0.01f, 0.01f),
|
|
new BoneHeadTail(HumanBodyBones.LeftIndexProximal, HumanBodyBones.LeftIndexIntermediate, Vector3.forward, 0.01f, 0.01f),
|
|
new BoneHeadTail(HumanBodyBones.LeftIndexIntermediate, HumanBodyBones.LeftIndexDistal, Vector3.forward, 0.01f, 0.01f),
|
|
new BoneHeadTail(HumanBodyBones.LeftIndexDistal, new Vector3(-0.03f, 0, 0), Vector3.forward, 0.01f, 0.01f),
|
|
new BoneHeadTail(HumanBodyBones.LeftMiddleProximal, HumanBodyBones.LeftMiddleIntermediate, Vector3.forward, 0.01f, 0.01f),
|
|
new BoneHeadTail(HumanBodyBones.LeftMiddleIntermediate, HumanBodyBones.LeftMiddleDistal, Vector3.forward, 0.01f, 0.01f),
|
|
new BoneHeadTail(HumanBodyBones.LeftMiddleDistal, new Vector3(-0.032f, 0, 0), Vector3.forward, 0.01f, 0.01f),
|
|
new BoneHeadTail(HumanBodyBones.LeftRingProximal, HumanBodyBones.LeftRingIntermediate, Vector3.forward, 0.01f, 0.01f),
|
|
new BoneHeadTail(HumanBodyBones.LeftRingIntermediate, HumanBodyBones.LeftRingDistal, Vector3.forward, 0.01f, 0.01f),
|
|
new BoneHeadTail(HumanBodyBones.LeftRingDistal, new Vector3(-0.028f, 0, 0), Vector3.forward, 0.01f, 0.01f),
|
|
new BoneHeadTail(HumanBodyBones.LeftLittleProximal, HumanBodyBones.LeftLittleIntermediate, Vector3.forward, 0.01f, 0.01f),
|
|
new BoneHeadTail(HumanBodyBones.LeftLittleIntermediate, HumanBodyBones.LeftLittleDistal, Vector3.forward, 0.01f, 0.01f),
|
|
new BoneHeadTail(HumanBodyBones.LeftLittleDistal, new Vector3(-0.025f, 0, 0), Vector3.forward, 0.01f, 0.01f),
|
|
|
|
new BoneHeadTail(HumanBodyBones.LeftUpperLeg, HumanBodyBones.LeftLowerLeg, Vector3.left),
|
|
new BoneHeadTail(HumanBodyBones.LeftLowerLeg, HumanBodyBones.LeftFoot, Vector3.left),
|
|
new BoneHeadTail(HumanBodyBones.LeftFoot, HumanBodyBones.LeftToes, Vector3.left),
|
|
new BoneHeadTail(HumanBodyBones.LeftToes, new Vector3(0, 0, 0.03f), Vector3.left),
|
|
|
|
new BoneHeadTail(HumanBodyBones.RightShoulder, HumanBodyBones.RightUpperArm, Vector3.back),
|
|
new BoneHeadTail(HumanBodyBones.RightUpperArm, HumanBodyBones.RightLowerArm, Vector3.back),
|
|
new BoneHeadTail(HumanBodyBones.RightLowerArm, HumanBodyBones.RightHand, Vector3.back),
|
|
|
|
new BoneHeadTail(HumanBodyBones.RightHand, new Vector3(0.1f, 0, 0), Vector3.back, 0.05f, 0.02f),
|
|
new BoneHeadTail(HumanBodyBones.RightThumbProximal, HumanBodyBones.RightThumbIntermediate, Vector3.forward, 0.01f, 0.01f),
|
|
new BoneHeadTail(HumanBodyBones.RightThumbIntermediate, HumanBodyBones.RightThumbDistal, Vector3.forward, 0.01f, 0.01f),
|
|
new BoneHeadTail(HumanBodyBones.RightThumbDistal, new Vector3(0.03f, 0, 0), Vector3.forward, 0.01f, 0.01f),
|
|
new BoneHeadTail(HumanBodyBones.RightIndexProximal, HumanBodyBones.RightIndexIntermediate, Vector3.forward, 0.01f, 0.01f),
|
|
new BoneHeadTail(HumanBodyBones.RightIndexIntermediate, HumanBodyBones.RightIndexDistal, Vector3.forward, 0.01f, 0.01f),
|
|
new BoneHeadTail(HumanBodyBones.RightIndexDistal, new Vector3(0.03f, 0, 0), Vector3.forward, 0.01f, 0.01f),
|
|
new BoneHeadTail(HumanBodyBones.RightMiddleProximal, HumanBodyBones.RightMiddleIntermediate, Vector3.forward, 0.01f, 0.01f),
|
|
new BoneHeadTail(HumanBodyBones.RightMiddleIntermediate, HumanBodyBones.RightMiddleDistal, Vector3.forward, 0.01f, 0.01f),
|
|
new BoneHeadTail(HumanBodyBones.RightMiddleDistal, new Vector3(0.032f, 0, 0), Vector3.forward, 0.01f, 0.01f),
|
|
new BoneHeadTail(HumanBodyBones.RightRingProximal, HumanBodyBones.RightRingIntermediate, Vector3.forward, 0.01f, 0.01f),
|
|
new BoneHeadTail(HumanBodyBones.RightRingIntermediate, HumanBodyBones.RightRingDistal, Vector3.forward, 0.01f, 0.01f),
|
|
new BoneHeadTail(HumanBodyBones.RightRingDistal, new Vector3(0.028f, 0, 0), Vector3.forward, 0.01f, 0.01f),
|
|
new BoneHeadTail(HumanBodyBones.RightLittleProximal, HumanBodyBones.RightLittleIntermediate, Vector3.forward, 0.01f, 0.01f),
|
|
new BoneHeadTail(HumanBodyBones.RightLittleIntermediate, HumanBodyBones.RightLittleDistal, Vector3.forward, 0.01f, 0.01f),
|
|
new BoneHeadTail(HumanBodyBones.RightLittleDistal, new Vector3(0.025f, 0, 0), Vector3.forward, 0.01f, 0.01f),
|
|
|
|
new BoneHeadTail(HumanBodyBones.RightUpperLeg, HumanBodyBones.RightLowerLeg, Vector3.left),
|
|
new BoneHeadTail(HumanBodyBones.RightLowerLeg, HumanBodyBones.RightFoot, Vector3.left),
|
|
new BoneHeadTail(HumanBodyBones.RightFoot, HumanBodyBones.RightToes, Vector3.left),
|
|
new BoneHeadTail(HumanBodyBones.RightToes, new Vector3(0, 0, 0.03f), Vector3.left),
|
|
|
|
|
|
};
|
|
|
|
public static SkinnedMeshRenderer CreateRenderer(Animator animator)
|
|
{
|
|
var bones = animator.transform.Traverse().ToList();
|
|
|
|
var builder = new MeshBuilder();
|
|
foreach (var headTail in Bones)
|
|
{
|
|
var head = animator.GetBoneTransform(headTail.Head);
|
|
if (head != null)
|
|
{
|
|
Transform tail = null;
|
|
if (headTail.Tail != HumanBodyBones.LastBone)
|
|
{
|
|
tail = animator.GetBoneTransform(headTail.Tail);
|
|
}
|
|
|
|
if (tail != null)
|
|
{
|
|
builder.AddBone(head.position, tail.position, bones.IndexOf(head), headTail.Width, headTail.Height, headTail.XAxis);
|
|
}
|
|
else
|
|
{
|
|
builder.AddBone(head.position, head.position + headTail.TailOffset, bones.IndexOf(head), headTail.Width, headTail.Height, headTail.XAxis);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
if (VRMShaders.Symbols.VRM_DEVELOP)
|
|
{
|
|
Debug.LogWarningFormat("{0} not found", headTail.Head);
|
|
}
|
|
}
|
|
}
|
|
|
|
var mesh = builder.CreateMesh();
|
|
mesh.name = "box-man";
|
|
mesh.bindposes = bones.Select(x => x.worldToLocalMatrix * animator.transform.localToWorldMatrix).ToArray();
|
|
|
|
var renderer = animator.gameObject.AddComponent<SkinnedMeshRenderer>();
|
|
renderer.bones = bones.ToArray();
|
|
renderer.rootBone = animator.GetBoneTransform(HumanBodyBones.Hips);
|
|
renderer.sharedMesh = mesh;
|
|
//var bounds = new Bounds(Vector3.zero, mesh.bounds.size);
|
|
//renderer.localBounds = bounds;
|
|
return renderer;
|
|
}
|
|
}
|
|
} |