Move UniHumanoid to Assets/*
@@ -1,175 +1,175 @@
|
||||
using System;
|
||||
using UnityEngine;
|
||||
|
||||
|
||||
namespace UniHumanoid
|
||||
{
|
||||
public class HandPoseModifier : IPoseModifier
|
||||
{
|
||||
public class HandPose
|
||||
{
|
||||
public float ThumbStrech;
|
||||
public float ThumbSpread;
|
||||
|
||||
public float IndexStrech;
|
||||
public float IndexSpread;
|
||||
|
||||
public float MiddleStrech;
|
||||
public float MiddleSpread;
|
||||
|
||||
public float RingStrech;
|
||||
public float RingSpread;
|
||||
|
||||
public float LittleStrech;
|
||||
public float LittleSpread;
|
||||
}
|
||||
public HandPose LeftHandPose
|
||||
{
|
||||
get;
|
||||
set;
|
||||
}
|
||||
public HandPose RightHandPose
|
||||
{
|
||||
get;
|
||||
set;
|
||||
}
|
||||
|
||||
int LeftThumb1Stretched;
|
||||
int LeftThumb2Stretched;
|
||||
int LeftThumb3Stretched;
|
||||
int LeftIndex1Stretched;
|
||||
int LeftIndex2Stretched;
|
||||
int LeftIndex3Stretched;
|
||||
int LeftMiddle1Stretched;
|
||||
int LeftMiddle2Stretched;
|
||||
int LeftMiddle3Stretched;
|
||||
int LeftRing1Stretched;
|
||||
int LeftRing2Stretched;
|
||||
int LeftRing3Stretched;
|
||||
int LeftLittle1Stretched;
|
||||
int LeftLittle2Stretched;
|
||||
int LeftLittle3Stretched;
|
||||
int LeftThumbSpread;
|
||||
int LeftIndexSpread;
|
||||
int LeftMiddleSpread;
|
||||
int LeftRingSpread;
|
||||
int LeftLittleSpread;
|
||||
|
||||
int RightThumb1Stretched;
|
||||
int RightThumb2Stretched;
|
||||
int RightThumb3Stretched;
|
||||
int RightIndex1Stretched;
|
||||
int RightIndex2Stretched;
|
||||
int RightIndex3Stretched;
|
||||
int RightMiddle1Stretched;
|
||||
int RightMiddle2Stretched;
|
||||
int RightMiddle3Stretched;
|
||||
int RightRing1Stretched;
|
||||
int RightRing2Stretched;
|
||||
int RightRing3Stretched;
|
||||
int RightLittle1Stretched;
|
||||
int RightLittle2Stretched;
|
||||
int RightLittle3Stretched;
|
||||
int RightThumbSpread;
|
||||
int RightIndexSpread;
|
||||
int RightMiddleSpread;
|
||||
int RightRingSpread;
|
||||
int RightLittleSpread;
|
||||
|
||||
public HandPoseModifier()
|
||||
{
|
||||
LeftThumb1Stretched = Array.IndexOf(HumanTrait.MuscleName, "Left Thumb 1 Stretched");
|
||||
LeftThumb2Stretched = Array.IndexOf(HumanTrait.MuscleName, "Left Thumb 2 Stretched");
|
||||
LeftThumb3Stretched = Array.IndexOf(HumanTrait.MuscleName, "Left Thumb 3 Stretched");
|
||||
LeftIndex1Stretched = Array.IndexOf(HumanTrait.MuscleName, "Left Index 1 Stretched");
|
||||
LeftIndex2Stretched = Array.IndexOf(HumanTrait.MuscleName, "Left Index 2 Stretched");
|
||||
LeftIndex3Stretched = Array.IndexOf(HumanTrait.MuscleName, "Left Index 3 Stretched");
|
||||
LeftMiddle1Stretched = Array.IndexOf(HumanTrait.MuscleName, "Left Middle 1 Stretched");
|
||||
LeftMiddle2Stretched = Array.IndexOf(HumanTrait.MuscleName, "Left Middle 2 Stretched");
|
||||
LeftMiddle3Stretched = Array.IndexOf(HumanTrait.MuscleName, "Left Middle 3 Stretched");
|
||||
LeftRing1Stretched = Array.IndexOf(HumanTrait.MuscleName, "Left Ring 1 Stretched");
|
||||
LeftRing2Stretched = Array.IndexOf(HumanTrait.MuscleName, "Left Ring 2 Stretched");
|
||||
LeftRing3Stretched = Array.IndexOf(HumanTrait.MuscleName, "Left Ring 3 Stretched");
|
||||
LeftLittle1Stretched = Array.IndexOf(HumanTrait.MuscleName, "Left Little 1 Stretched");
|
||||
LeftLittle2Stretched = Array.IndexOf(HumanTrait.MuscleName, "Left Little 2 Stretched");
|
||||
LeftLittle3Stretched = Array.IndexOf(HumanTrait.MuscleName, "Left Little 3 Stretched");
|
||||
LeftThumbSpread = Array.IndexOf(HumanTrait.MuscleName, "Left Thumb Spread");
|
||||
LeftIndexSpread = Array.IndexOf(HumanTrait.MuscleName, "Left Index Spread");
|
||||
LeftMiddleSpread = Array.IndexOf(HumanTrait.MuscleName, "Left Middle Spread");
|
||||
LeftRingSpread = Array.IndexOf(HumanTrait.MuscleName, "Left Ring Spread");
|
||||
LeftLittleSpread = Array.IndexOf(HumanTrait.MuscleName, "Left Little Spread");
|
||||
|
||||
RightThumb1Stretched = Array.IndexOf(HumanTrait.MuscleName, "Right Thumb 1 Stretched");
|
||||
RightThumb2Stretched = Array.IndexOf(HumanTrait.MuscleName, "Right Thumb 2 Stretched");
|
||||
RightThumb3Stretched = Array.IndexOf(HumanTrait.MuscleName, "Right Thumb 3 Stretched");
|
||||
RightIndex1Stretched = Array.IndexOf(HumanTrait.MuscleName, "Right Index 1 Stretched");
|
||||
RightIndex2Stretched = Array.IndexOf(HumanTrait.MuscleName, "Right Index 2 Stretched");
|
||||
RightIndex3Stretched = Array.IndexOf(HumanTrait.MuscleName, "Right Index 3 Stretched");
|
||||
RightMiddle1Stretched = Array.IndexOf(HumanTrait.MuscleName, "Right Middle 1 Stretched");
|
||||
RightMiddle2Stretched = Array.IndexOf(HumanTrait.MuscleName, "Right Middle 2 Stretched");
|
||||
RightMiddle3Stretched = Array.IndexOf(HumanTrait.MuscleName, "Right Middle 3 Stretched");
|
||||
RightRing1Stretched = Array.IndexOf(HumanTrait.MuscleName, "Right Ring 1 Stretched");
|
||||
RightRing2Stretched = Array.IndexOf(HumanTrait.MuscleName, "Right Ring 2 Stretched");
|
||||
RightRing3Stretched = Array.IndexOf(HumanTrait.MuscleName, "Right Ring 3 Stretched");
|
||||
RightLittle1Stretched = Array.IndexOf(HumanTrait.MuscleName, "Right Little 1 Stretched");
|
||||
RightLittle2Stretched = Array.IndexOf(HumanTrait.MuscleName, "Right Little 2 Stretched");
|
||||
RightLittle3Stretched = Array.IndexOf(HumanTrait.MuscleName, "Right Little 3 Stretched");
|
||||
RightThumbSpread = Array.IndexOf(HumanTrait.MuscleName, "Right Thumb Spread");
|
||||
RightIndexSpread = Array.IndexOf(HumanTrait.MuscleName, "Right Index Spread");
|
||||
RightMiddleSpread = Array.IndexOf(HumanTrait.MuscleName, "Right Middle Spread");
|
||||
RightRingSpread = Array.IndexOf(HumanTrait.MuscleName, "Right Ring Spread");
|
||||
RightLittleSpread = Array.IndexOf(HumanTrait.MuscleName, "Right Little Spread");
|
||||
}
|
||||
|
||||
public void Modify(ref HumanPose pose)
|
||||
{
|
||||
if (LeftHandPose != null)
|
||||
{
|
||||
pose.muscles[this.LeftThumb1Stretched] = LeftHandPose.ThumbStrech;
|
||||
pose.muscles[this.LeftThumb2Stretched] = LeftHandPose.ThumbStrech;
|
||||
pose.muscles[this.LeftThumb3Stretched] = LeftHandPose.ThumbStrech;
|
||||
pose.muscles[this.LeftIndex1Stretched] = LeftHandPose.IndexStrech;
|
||||
pose.muscles[this.LeftIndex2Stretched] = LeftHandPose.IndexStrech;
|
||||
pose.muscles[this.LeftIndex3Stretched] = LeftHandPose.IndexStrech;
|
||||
pose.muscles[this.LeftMiddle1Stretched] = LeftHandPose.MiddleStrech;
|
||||
pose.muscles[this.LeftMiddle2Stretched] = LeftHandPose.MiddleStrech;
|
||||
pose.muscles[this.LeftMiddle3Stretched] = LeftHandPose.MiddleStrech;
|
||||
pose.muscles[this.LeftRing1Stretched] = LeftHandPose.RingStrech;
|
||||
pose.muscles[this.LeftRing2Stretched] = LeftHandPose.RingStrech;
|
||||
pose.muscles[this.LeftRing3Stretched] = LeftHandPose.RingStrech;
|
||||
pose.muscles[this.LeftLittle1Stretched] = LeftHandPose.LittleStrech;
|
||||
pose.muscles[this.LeftLittle2Stretched] = LeftHandPose.LittleStrech;
|
||||
pose.muscles[this.LeftLittle3Stretched] = LeftHandPose.LittleStrech;
|
||||
pose.muscles[this.LeftThumbSpread] = LeftHandPose.ThumbSpread;
|
||||
pose.muscles[this.LeftIndexSpread] = LeftHandPose.IndexSpread;
|
||||
pose.muscles[this.LeftMiddleSpread] = LeftHandPose.MiddleSpread;
|
||||
pose.muscles[this.LeftRingSpread] = LeftHandPose.RingSpread;
|
||||
pose.muscles[this.LeftLittleSpread] = LeftHandPose.LittleSpread;
|
||||
}
|
||||
|
||||
if (RightHandPose != null)
|
||||
{
|
||||
pose.muscles[this.RightThumb1Stretched] = RightHandPose.ThumbStrech;
|
||||
pose.muscles[this.RightThumb2Stretched] = RightHandPose.ThumbStrech;
|
||||
pose.muscles[this.RightThumb3Stretched] = RightHandPose.ThumbStrech;
|
||||
pose.muscles[this.RightIndex1Stretched] = RightHandPose.IndexStrech;
|
||||
pose.muscles[this.RightIndex2Stretched] = RightHandPose.IndexStrech;
|
||||
pose.muscles[this.RightIndex3Stretched] = RightHandPose.IndexStrech;
|
||||
pose.muscles[this.RightMiddle1Stretched] = RightHandPose.MiddleStrech;
|
||||
pose.muscles[this.RightMiddle2Stretched] = RightHandPose.MiddleStrech;
|
||||
pose.muscles[this.RightMiddle3Stretched] = RightHandPose.MiddleStrech;
|
||||
pose.muscles[this.RightRing1Stretched] = RightHandPose.RingStrech;
|
||||
pose.muscles[this.RightRing2Stretched] = RightHandPose.RingStrech;
|
||||
pose.muscles[this.RightRing3Stretched] = RightHandPose.RingStrech;
|
||||
pose.muscles[this.RightLittle1Stretched] = RightHandPose.LittleStrech;
|
||||
pose.muscles[this.RightLittle2Stretched] = RightHandPose.LittleStrech;
|
||||
pose.muscles[this.RightLittle3Stretched] = RightHandPose.LittleStrech;
|
||||
pose.muscles[this.RightThumbSpread] = RightHandPose.ThumbSpread;
|
||||
pose.muscles[this.RightIndexSpread] = RightHandPose.IndexSpread;
|
||||
pose.muscles[this.RightMiddleSpread] = RightHandPose.MiddleSpread;
|
||||
pose.muscles[this.RightRingSpread] = RightHandPose.RingSpread;
|
||||
pose.muscles[this.RightLittleSpread] = RightHandPose.LittleSpread;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
using System;
|
||||
using UnityEngine;
|
||||
|
||||
|
||||
namespace UniHumanoid
|
||||
{
|
||||
public class HandPoseModifier : IPoseModifier
|
||||
{
|
||||
public class HandPose
|
||||
{
|
||||
public float ThumbStrech;
|
||||
public float ThumbSpread;
|
||||
|
||||
public float IndexStrech;
|
||||
public float IndexSpread;
|
||||
|
||||
public float MiddleStrech;
|
||||
public float MiddleSpread;
|
||||
|
||||
public float RingStrech;
|
||||
public float RingSpread;
|
||||
|
||||
public float LittleStrech;
|
||||
public float LittleSpread;
|
||||
}
|
||||
public HandPose LeftHandPose
|
||||
{
|
||||
get;
|
||||
set;
|
||||
}
|
||||
public HandPose RightHandPose
|
||||
{
|
||||
get;
|
||||
set;
|
||||
}
|
||||
|
||||
int LeftThumb1Stretched;
|
||||
int LeftThumb2Stretched;
|
||||
int LeftThumb3Stretched;
|
||||
int LeftIndex1Stretched;
|
||||
int LeftIndex2Stretched;
|
||||
int LeftIndex3Stretched;
|
||||
int LeftMiddle1Stretched;
|
||||
int LeftMiddle2Stretched;
|
||||
int LeftMiddle3Stretched;
|
||||
int LeftRing1Stretched;
|
||||
int LeftRing2Stretched;
|
||||
int LeftRing3Stretched;
|
||||
int LeftLittle1Stretched;
|
||||
int LeftLittle2Stretched;
|
||||
int LeftLittle3Stretched;
|
||||
int LeftThumbSpread;
|
||||
int LeftIndexSpread;
|
||||
int LeftMiddleSpread;
|
||||
int LeftRingSpread;
|
||||
int LeftLittleSpread;
|
||||
|
||||
int RightThumb1Stretched;
|
||||
int RightThumb2Stretched;
|
||||
int RightThumb3Stretched;
|
||||
int RightIndex1Stretched;
|
||||
int RightIndex2Stretched;
|
||||
int RightIndex3Stretched;
|
||||
int RightMiddle1Stretched;
|
||||
int RightMiddle2Stretched;
|
||||
int RightMiddle3Stretched;
|
||||
int RightRing1Stretched;
|
||||
int RightRing2Stretched;
|
||||
int RightRing3Stretched;
|
||||
int RightLittle1Stretched;
|
||||
int RightLittle2Stretched;
|
||||
int RightLittle3Stretched;
|
||||
int RightThumbSpread;
|
||||
int RightIndexSpread;
|
||||
int RightMiddleSpread;
|
||||
int RightRingSpread;
|
||||
int RightLittleSpread;
|
||||
|
||||
public HandPoseModifier()
|
||||
{
|
||||
LeftThumb1Stretched = Array.IndexOf(HumanTrait.MuscleName, "Left Thumb 1 Stretched");
|
||||
LeftThumb2Stretched = Array.IndexOf(HumanTrait.MuscleName, "Left Thumb 2 Stretched");
|
||||
LeftThumb3Stretched = Array.IndexOf(HumanTrait.MuscleName, "Left Thumb 3 Stretched");
|
||||
LeftIndex1Stretched = Array.IndexOf(HumanTrait.MuscleName, "Left Index 1 Stretched");
|
||||
LeftIndex2Stretched = Array.IndexOf(HumanTrait.MuscleName, "Left Index 2 Stretched");
|
||||
LeftIndex3Stretched = Array.IndexOf(HumanTrait.MuscleName, "Left Index 3 Stretched");
|
||||
LeftMiddle1Stretched = Array.IndexOf(HumanTrait.MuscleName, "Left Middle 1 Stretched");
|
||||
LeftMiddle2Stretched = Array.IndexOf(HumanTrait.MuscleName, "Left Middle 2 Stretched");
|
||||
LeftMiddle3Stretched = Array.IndexOf(HumanTrait.MuscleName, "Left Middle 3 Stretched");
|
||||
LeftRing1Stretched = Array.IndexOf(HumanTrait.MuscleName, "Left Ring 1 Stretched");
|
||||
LeftRing2Stretched = Array.IndexOf(HumanTrait.MuscleName, "Left Ring 2 Stretched");
|
||||
LeftRing3Stretched = Array.IndexOf(HumanTrait.MuscleName, "Left Ring 3 Stretched");
|
||||
LeftLittle1Stretched = Array.IndexOf(HumanTrait.MuscleName, "Left Little 1 Stretched");
|
||||
LeftLittle2Stretched = Array.IndexOf(HumanTrait.MuscleName, "Left Little 2 Stretched");
|
||||
LeftLittle3Stretched = Array.IndexOf(HumanTrait.MuscleName, "Left Little 3 Stretched");
|
||||
LeftThumbSpread = Array.IndexOf(HumanTrait.MuscleName, "Left Thumb Spread");
|
||||
LeftIndexSpread = Array.IndexOf(HumanTrait.MuscleName, "Left Index Spread");
|
||||
LeftMiddleSpread = Array.IndexOf(HumanTrait.MuscleName, "Left Middle Spread");
|
||||
LeftRingSpread = Array.IndexOf(HumanTrait.MuscleName, "Left Ring Spread");
|
||||
LeftLittleSpread = Array.IndexOf(HumanTrait.MuscleName, "Left Little Spread");
|
||||
|
||||
RightThumb1Stretched = Array.IndexOf(HumanTrait.MuscleName, "Right Thumb 1 Stretched");
|
||||
RightThumb2Stretched = Array.IndexOf(HumanTrait.MuscleName, "Right Thumb 2 Stretched");
|
||||
RightThumb3Stretched = Array.IndexOf(HumanTrait.MuscleName, "Right Thumb 3 Stretched");
|
||||
RightIndex1Stretched = Array.IndexOf(HumanTrait.MuscleName, "Right Index 1 Stretched");
|
||||
RightIndex2Stretched = Array.IndexOf(HumanTrait.MuscleName, "Right Index 2 Stretched");
|
||||
RightIndex3Stretched = Array.IndexOf(HumanTrait.MuscleName, "Right Index 3 Stretched");
|
||||
RightMiddle1Stretched = Array.IndexOf(HumanTrait.MuscleName, "Right Middle 1 Stretched");
|
||||
RightMiddle2Stretched = Array.IndexOf(HumanTrait.MuscleName, "Right Middle 2 Stretched");
|
||||
RightMiddle3Stretched = Array.IndexOf(HumanTrait.MuscleName, "Right Middle 3 Stretched");
|
||||
RightRing1Stretched = Array.IndexOf(HumanTrait.MuscleName, "Right Ring 1 Stretched");
|
||||
RightRing2Stretched = Array.IndexOf(HumanTrait.MuscleName, "Right Ring 2 Stretched");
|
||||
RightRing3Stretched = Array.IndexOf(HumanTrait.MuscleName, "Right Ring 3 Stretched");
|
||||
RightLittle1Stretched = Array.IndexOf(HumanTrait.MuscleName, "Right Little 1 Stretched");
|
||||
RightLittle2Stretched = Array.IndexOf(HumanTrait.MuscleName, "Right Little 2 Stretched");
|
||||
RightLittle3Stretched = Array.IndexOf(HumanTrait.MuscleName, "Right Little 3 Stretched");
|
||||
RightThumbSpread = Array.IndexOf(HumanTrait.MuscleName, "Right Thumb Spread");
|
||||
RightIndexSpread = Array.IndexOf(HumanTrait.MuscleName, "Right Index Spread");
|
||||
RightMiddleSpread = Array.IndexOf(HumanTrait.MuscleName, "Right Middle Spread");
|
||||
RightRingSpread = Array.IndexOf(HumanTrait.MuscleName, "Right Ring Spread");
|
||||
RightLittleSpread = Array.IndexOf(HumanTrait.MuscleName, "Right Little Spread");
|
||||
}
|
||||
|
||||
public void Modify(ref HumanPose pose)
|
||||
{
|
||||
if (LeftHandPose != null)
|
||||
{
|
||||
pose.muscles[this.LeftThumb1Stretched] = LeftHandPose.ThumbStrech;
|
||||
pose.muscles[this.LeftThumb2Stretched] = LeftHandPose.ThumbStrech;
|
||||
pose.muscles[this.LeftThumb3Stretched] = LeftHandPose.ThumbStrech;
|
||||
pose.muscles[this.LeftIndex1Stretched] = LeftHandPose.IndexStrech;
|
||||
pose.muscles[this.LeftIndex2Stretched] = LeftHandPose.IndexStrech;
|
||||
pose.muscles[this.LeftIndex3Stretched] = LeftHandPose.IndexStrech;
|
||||
pose.muscles[this.LeftMiddle1Stretched] = LeftHandPose.MiddleStrech;
|
||||
pose.muscles[this.LeftMiddle2Stretched] = LeftHandPose.MiddleStrech;
|
||||
pose.muscles[this.LeftMiddle3Stretched] = LeftHandPose.MiddleStrech;
|
||||
pose.muscles[this.LeftRing1Stretched] = LeftHandPose.RingStrech;
|
||||
pose.muscles[this.LeftRing2Stretched] = LeftHandPose.RingStrech;
|
||||
pose.muscles[this.LeftRing3Stretched] = LeftHandPose.RingStrech;
|
||||
pose.muscles[this.LeftLittle1Stretched] = LeftHandPose.LittleStrech;
|
||||
pose.muscles[this.LeftLittle2Stretched] = LeftHandPose.LittleStrech;
|
||||
pose.muscles[this.LeftLittle3Stretched] = LeftHandPose.LittleStrech;
|
||||
pose.muscles[this.LeftThumbSpread] = LeftHandPose.ThumbSpread;
|
||||
pose.muscles[this.LeftIndexSpread] = LeftHandPose.IndexSpread;
|
||||
pose.muscles[this.LeftMiddleSpread] = LeftHandPose.MiddleSpread;
|
||||
pose.muscles[this.LeftRingSpread] = LeftHandPose.RingSpread;
|
||||
pose.muscles[this.LeftLittleSpread] = LeftHandPose.LittleSpread;
|
||||
}
|
||||
|
||||
if (RightHandPose != null)
|
||||
{
|
||||
pose.muscles[this.RightThumb1Stretched] = RightHandPose.ThumbStrech;
|
||||
pose.muscles[this.RightThumb2Stretched] = RightHandPose.ThumbStrech;
|
||||
pose.muscles[this.RightThumb3Stretched] = RightHandPose.ThumbStrech;
|
||||
pose.muscles[this.RightIndex1Stretched] = RightHandPose.IndexStrech;
|
||||
pose.muscles[this.RightIndex2Stretched] = RightHandPose.IndexStrech;
|
||||
pose.muscles[this.RightIndex3Stretched] = RightHandPose.IndexStrech;
|
||||
pose.muscles[this.RightMiddle1Stretched] = RightHandPose.MiddleStrech;
|
||||
pose.muscles[this.RightMiddle2Stretched] = RightHandPose.MiddleStrech;
|
||||
pose.muscles[this.RightMiddle3Stretched] = RightHandPose.MiddleStrech;
|
||||
pose.muscles[this.RightRing1Stretched] = RightHandPose.RingStrech;
|
||||
pose.muscles[this.RightRing2Stretched] = RightHandPose.RingStrech;
|
||||
pose.muscles[this.RightRing3Stretched] = RightHandPose.RingStrech;
|
||||
pose.muscles[this.RightLittle1Stretched] = RightHandPose.LittleStrech;
|
||||
pose.muscles[this.RightLittle2Stretched] = RightHandPose.LittleStrech;
|
||||
pose.muscles[this.RightLittle3Stretched] = RightHandPose.LittleStrech;
|
||||
pose.muscles[this.RightThumbSpread] = RightHandPose.ThumbSpread;
|
||||
pose.muscles[this.RightIndexSpread] = RightHandPose.IndexSpread;
|
||||
pose.muscles[this.RightMiddleSpread] = RightHandPose.MiddleSpread;
|
||||
pose.muscles[this.RightRingSpread] = RightHandPose.RingSpread;
|
||||
pose.muscles[this.RightLittleSpread] = RightHandPose.LittleSpread;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,100 +1,100 @@
|
||||
using UnityEngine;
|
||||
|
||||
|
||||
namespace UniHumanoid
|
||||
{
|
||||
public class HandRig : MonoBehaviour
|
||||
{
|
||||
[SerializeField]
|
||||
Animator m_animator;
|
||||
public Animator Animator
|
||||
{
|
||||
get { return m_animator; }
|
||||
}
|
||||
|
||||
[SerializeField, Range(-1, 1)]
|
||||
public float LeftStrech;
|
||||
|
||||
[SerializeField, Range(-1, 1)]
|
||||
public float LeftSpread;
|
||||
|
||||
[SerializeField, Range(-1, 1)]
|
||||
public float RightStrech;
|
||||
|
||||
[SerializeField, Range(-1, 1)]
|
||||
public float RightSpread;
|
||||
|
||||
private void Reset()
|
||||
{
|
||||
m_animator = GetComponent<Animator>();
|
||||
}
|
||||
|
||||
HumanPoseHandler m_handler;
|
||||
public static HumanPoseHandler GetHandler(Animator animator)
|
||||
{
|
||||
if (animator == null)
|
||||
{
|
||||
return null;
|
||||
}
|
||||
if (animator.avatar == null)
|
||||
{
|
||||
return null;
|
||||
}
|
||||
if (!animator.avatar.isValid
|
||||
|| !animator.avatar.isHuman)
|
||||
{
|
||||
return null;
|
||||
}
|
||||
return new HumanPoseHandler(animator.avatar, animator.transform);
|
||||
}
|
||||
|
||||
HandPoseModifier m_updater;
|
||||
|
||||
private void Awake()
|
||||
{
|
||||
m_handler = GetHandler(m_animator);
|
||||
if (m_handler == null)
|
||||
{
|
||||
enabled = false;
|
||||
return;
|
||||
}
|
||||
m_updater = new HandPoseModifier();
|
||||
}
|
||||
|
||||
HandPoseModifier.HandPose m_leftHand = new HandPoseModifier.HandPose();
|
||||
HandPoseModifier.HandPose m_rightHand = new HandPoseModifier.HandPose();
|
||||
HumanPose m_pose;
|
||||
|
||||
private void Update()
|
||||
{
|
||||
m_leftHand.ThumbStrech = LeftStrech;
|
||||
m_leftHand.ThumbSpread = LeftSpread;
|
||||
m_leftHand.IndexStrech = LeftStrech;
|
||||
m_leftHand.IndexSpread = LeftSpread;
|
||||
m_leftHand.MiddleStrech = LeftStrech;
|
||||
m_leftHand.MiddleSpread = LeftSpread;
|
||||
m_leftHand.RingStrech = LeftStrech;
|
||||
m_leftHand.RingSpread = LeftSpread;
|
||||
m_leftHand.LittleStrech = LeftStrech;
|
||||
m_leftHand.LittleSpread = LeftSpread;
|
||||
|
||||
m_rightHand.ThumbStrech = RightStrech;
|
||||
m_rightHand.ThumbSpread = RightSpread;
|
||||
m_rightHand.IndexStrech = RightStrech;
|
||||
m_rightHand.IndexSpread = RightSpread;
|
||||
m_rightHand.MiddleStrech = RightStrech;
|
||||
m_rightHand.MiddleSpread = RightSpread;
|
||||
m_rightHand.RingStrech = RightStrech;
|
||||
m_rightHand.RingSpread = RightSpread;
|
||||
m_rightHand.LittleStrech = RightStrech;
|
||||
m_rightHand.LittleSpread = RightSpread;
|
||||
|
||||
m_updater.LeftHandPose = m_leftHand;
|
||||
m_updater.RightHandPose = m_rightHand;
|
||||
|
||||
m_handler.GetHumanPose(ref m_pose);
|
||||
m_updater.Modify(ref m_pose);
|
||||
m_handler.SetHumanPose(ref m_pose);
|
||||
}
|
||||
}
|
||||
}
|
||||
using UnityEngine;
|
||||
|
||||
|
||||
namespace UniHumanoid
|
||||
{
|
||||
public class HandRig : MonoBehaviour
|
||||
{
|
||||
[SerializeField]
|
||||
Animator m_animator;
|
||||
public Animator Animator
|
||||
{
|
||||
get { return m_animator; }
|
||||
}
|
||||
|
||||
[SerializeField, Range(-1, 1)]
|
||||
public float LeftStrech;
|
||||
|
||||
[SerializeField, Range(-1, 1)]
|
||||
public float LeftSpread;
|
||||
|
||||
[SerializeField, Range(-1, 1)]
|
||||
public float RightStrech;
|
||||
|
||||
[SerializeField, Range(-1, 1)]
|
||||
public float RightSpread;
|
||||
|
||||
private void Reset()
|
||||
{
|
||||
m_animator = GetComponent<Animator>();
|
||||
}
|
||||
|
||||
HumanPoseHandler m_handler;
|
||||
public static HumanPoseHandler GetHandler(Animator animator)
|
||||
{
|
||||
if (animator == null)
|
||||
{
|
||||
return null;
|
||||
}
|
||||
if (animator.avatar == null)
|
||||
{
|
||||
return null;
|
||||
}
|
||||
if (!animator.avatar.isValid
|
||||
|| !animator.avatar.isHuman)
|
||||
{
|
||||
return null;
|
||||
}
|
||||
return new HumanPoseHandler(animator.avatar, animator.transform);
|
||||
}
|
||||
|
||||
HandPoseModifier m_updater;
|
||||
|
||||
private void Awake()
|
||||
{
|
||||
m_handler = GetHandler(m_animator);
|
||||
if (m_handler == null)
|
||||
{
|
||||
enabled = false;
|
||||
return;
|
||||
}
|
||||
m_updater = new HandPoseModifier();
|
||||
}
|
||||
|
||||
HandPoseModifier.HandPose m_leftHand = new HandPoseModifier.HandPose();
|
||||
HandPoseModifier.HandPose m_rightHand = new HandPoseModifier.HandPose();
|
||||
HumanPose m_pose;
|
||||
|
||||
private void Update()
|
||||
{
|
||||
m_leftHand.ThumbStrech = LeftStrech;
|
||||
m_leftHand.ThumbSpread = LeftSpread;
|
||||
m_leftHand.IndexStrech = LeftStrech;
|
||||
m_leftHand.IndexSpread = LeftSpread;
|
||||
m_leftHand.MiddleStrech = LeftStrech;
|
||||
m_leftHand.MiddleSpread = LeftSpread;
|
||||
m_leftHand.RingStrech = LeftStrech;
|
||||
m_leftHand.RingSpread = LeftSpread;
|
||||
m_leftHand.LittleStrech = LeftStrech;
|
||||
m_leftHand.LittleSpread = LeftSpread;
|
||||
|
||||
m_rightHand.ThumbStrech = RightStrech;
|
||||
m_rightHand.ThumbSpread = RightSpread;
|
||||
m_rightHand.IndexStrech = RightStrech;
|
||||
m_rightHand.IndexSpread = RightSpread;
|
||||
m_rightHand.MiddleStrech = RightStrech;
|
||||
m_rightHand.MiddleSpread = RightSpread;
|
||||
m_rightHand.RingStrech = RightStrech;
|
||||
m_rightHand.RingSpread = RightSpread;
|
||||
m_rightHand.LittleStrech = RightStrech;
|
||||
m_rightHand.LittleSpread = RightSpread;
|
||||
|
||||
m_updater.LeftHandPose = m_leftHand;
|
||||
m_updater.RightHandPose = m_rightHand;
|
||||
|
||||
m_handler.GetHumanPose(ref m_pose);
|
||||
m_updater.Modify(ref m_pose);
|
||||
m_handler.SetHumanPose(ref m_pose);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,10 +1,10 @@
|
||||
using UnityEngine;
|
||||
|
||||
|
||||
namespace UniHumanoid
|
||||
{
|
||||
public interface IPoseModifier
|
||||
{
|
||||
void Modify(ref HumanPose pose);
|
||||
}
|
||||
}
|
||||
using UnityEngine;
|
||||
|
||||
|
||||
namespace UniHumanoid
|
||||
{
|
||||
public interface IPoseModifier
|
||||
{
|
||||
void Modify(ref HumanPose pose);
|
||||
}
|
||||
}
|
||||
@@ -1,77 +1,77 @@
|
||||
# UniHumanoid
|
||||
|
||||
Unity humanoid utility with bvh importer.
|
||||
|
||||
# License
|
||||
|
||||
* [MIT](./LICENSE.md)
|
||||
|
||||
# BVH runtime loader
|
||||
|
||||
```cs
|
||||
var context = new BvhImporterContext();
|
||||
context.Parse(path);
|
||||
context.Load(); // create Skeleton hierarchy and mesh for visualize
|
||||
GameObject root = context.Root;
|
||||
```
|
||||
|
||||
## RuntimeLoader
|
||||
* Scenes/RuntimeBvhLoader.unity
|
||||
|
||||
## RuntimeLoader and PoseTransfer
|
||||
Load BVH and transfer pose to any model with humanoid avatar.
|
||||
|
||||
* Scenes/PoseTransfer.unity
|
||||
|
||||

|
||||
|
||||

|
||||
|
||||
# Load bvh and create prefab with AnimationClip
|
||||
|
||||
Drop bvh file to Assets folder.
|
||||
Then, AssetPostprocessor import bvh file.
|
||||
|
||||
* create a hierarchy prefab
|
||||
* create a humanoid Avatar
|
||||
* create a legacy mode AnimationClip
|
||||
* create a skinned mesh for preview
|
||||
|
||||

|
||||
|
||||
Instanciate prefab to scene.
|
||||
|
||||

|
||||
|
||||
That object can play.
|
||||
|
||||
# BoneMapping
|
||||
|
||||
This script help create human avatar from exist GameObject hierarchy.
|
||||
First, attach this script to root GameObject that has Animator.
|
||||
|
||||
Next, setup below.
|
||||
|
||||
* model position is origin
|
||||
* model look at +z orientation
|
||||
* model root node rotation is Quatenion.identity
|
||||
* Set hips bone.
|
||||
|
||||
press Guess bone mapping.
|
||||
If fail to guess bone mapping, you can set bones manually.
|
||||
|
||||
Optional, press Ensure T-Pose.
|
||||
Create avatar.
|
||||
|
||||

|
||||
|
||||
These humanoids imported by [UniGLTF](https://github.com/ousttrue/UniGLTF) and created human avatar by BoneMapping.
|
||||
|
||||

|
||||
|
||||
# Download BVH files
|
||||
|
||||
* https://sites.google.com/a/cgspeed.com/cgspeed/motion-capture
|
||||
* http://mocapdata.com/
|
||||
* http://www.thetrailerspark.com/download/Mocap/Packed/EYES-JAPAN/BVH/
|
||||
|
||||
# UniHumanoid
|
||||
|
||||
Unity humanoid utility with bvh importer.
|
||||
|
||||
# License
|
||||
|
||||
* [MIT](./LICENSE.md)
|
||||
|
||||
# BVH runtime loader
|
||||
|
||||
```cs
|
||||
var context = new BvhImporterContext();
|
||||
context.Parse(path);
|
||||
context.Load(); // create Skeleton hierarchy and mesh for visualize
|
||||
GameObject root = context.Root;
|
||||
```
|
||||
|
||||
## RuntimeLoader
|
||||
* Scenes/RuntimeBvhLoader.unity
|
||||
|
||||
## RuntimeLoader and PoseTransfer
|
||||
Load BVH and transfer pose to any model with humanoid avatar.
|
||||
|
||||
* Scenes/PoseTransfer.unity
|
||||
|
||||

|
||||
|
||||

|
||||
|
||||
# Load bvh and create prefab with AnimationClip
|
||||
|
||||
Drop bvh file to Assets folder.
|
||||
Then, AssetPostprocessor import bvh file.
|
||||
|
||||
* create a hierarchy prefab
|
||||
* create a humanoid Avatar
|
||||
* create a legacy mode AnimationClip
|
||||
* create a skinned mesh for preview
|
||||
|
||||

|
||||
|
||||
Instanciate prefab to scene.
|
||||
|
||||

|
||||
|
||||
That object can play.
|
||||
|
||||
# BoneMapping
|
||||
|
||||
This script help create human avatar from exist GameObject hierarchy.
|
||||
First, attach this script to root GameObject that has Animator.
|
||||
|
||||
Next, setup below.
|
||||
|
||||
* model position is origin
|
||||
* model look at +z orientation
|
||||
* model root node rotation is Quatenion.identity
|
||||
* Set hips bone.
|
||||
|
||||
press Guess bone mapping.
|
||||
If fail to guess bone mapping, you can set bones manually.
|
||||
|
||||
Optional, press Ensure T-Pose.
|
||||
Create avatar.
|
||||
|
||||

|
||||
|
||||
These humanoids imported by [UniGLTF](https://github.com/ousttrue/UniGLTF) and created human avatar by BoneMapping.
|
||||
|
||||

|
||||
|
||||
# Download BVH files
|
||||
|
||||
* https://sites.google.com/a/cgspeed.com/cgspeed/motion-capture
|
||||
* http://mocapdata.com/
|
||||
* http://www.thetrailerspark.com/download/Mocap/Packed/EYES-JAPAN/BVH/
|
||||
|
||||
@@ -1,149 +1,149 @@
|
||||
using System.Collections;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using UnityEngine;
|
||||
|
||||
|
||||
namespace UniHumanoid
|
||||
{
|
||||
[RequireComponent(typeof(Animator))]
|
||||
public class HumanBuilderTest : MonoBehaviour
|
||||
{
|
||||
[SerializeField]
|
||||
Material m_material;
|
||||
|
||||
class SkeletonBuilder
|
||||
{
|
||||
Dictionary<HumanBodyBones, Transform> m_skeleton = new Dictionary<HumanBodyBones, Transform>();
|
||||
public IDictionary<HumanBodyBones, Transform> Skeleton
|
||||
{
|
||||
get { return m_skeleton; }
|
||||
}
|
||||
|
||||
Dictionary<HumanBodyBones, Vector3> m_boneTail = new Dictionary<HumanBodyBones, Vector3>();
|
||||
Transform m_root;
|
||||
|
||||
public SkeletonBuilder(Transform root)
|
||||
{
|
||||
m_root = root;
|
||||
}
|
||||
|
||||
void Add(HumanBodyBones key, Transform parent, Vector3 headPosition, Vector3 tailPosition)
|
||||
{
|
||||
var bone = new GameObject(key.ToString()).transform;
|
||||
bone.SetParent(parent, false);
|
||||
bone.localPosition = headPosition;
|
||||
m_skeleton[key] = bone;
|
||||
m_boneTail[key] = tailPosition;
|
||||
}
|
||||
|
||||
void Add(HumanBodyBones key, HumanBodyBones parentKey, Vector3 tailPosition)
|
||||
{
|
||||
Add(key, m_skeleton[parentKey], m_boneTail[parentKey], tailPosition);
|
||||
}
|
||||
|
||||
#region Spine
|
||||
public void AddHips(float height, float len)
|
||||
{
|
||||
Add(HumanBodyBones.Hips, m_root, new Vector3(0, height, 0), new Vector3(0, len, 0));
|
||||
}
|
||||
|
||||
public void AddSpine(float len)
|
||||
{
|
||||
Add(HumanBodyBones.Spine, HumanBodyBones.Hips, new Vector3(0, len, 0));
|
||||
}
|
||||
|
||||
public void AddChest(float len)
|
||||
{
|
||||
Add(HumanBodyBones.Chest, HumanBodyBones.Spine, new Vector3(0, len, 0));
|
||||
}
|
||||
|
||||
public void AddNeck(float len)
|
||||
{
|
||||
Add(HumanBodyBones.Neck, HumanBodyBones.Chest, new Vector3(0, len, 0));
|
||||
}
|
||||
|
||||
public void AddHead(float len)
|
||||
{
|
||||
Add(HumanBodyBones.Head, HumanBodyBones.Neck, new Vector3(0, len, 0));
|
||||
}
|
||||
#endregion
|
||||
|
||||
public void AddArm(float shoulder, float upper, float lower, float hand)
|
||||
{
|
||||
Add(HumanBodyBones.LeftShoulder, HumanBodyBones.Chest, new Vector3(-shoulder, 0, 0));
|
||||
Add(HumanBodyBones.LeftUpperArm, HumanBodyBones.LeftShoulder, new Vector3(-upper, 0, 0));
|
||||
Add(HumanBodyBones.LeftLowerArm, HumanBodyBones.LeftUpperArm, new Vector3(-lower, 0, 0));
|
||||
Add(HumanBodyBones.LeftHand, HumanBodyBones.LeftLowerArm, new Vector3(-hand, 0, 0));
|
||||
|
||||
Add(HumanBodyBones.RightShoulder, HumanBodyBones.Chest, new Vector3(shoulder, 0, 0));
|
||||
Add(HumanBodyBones.RightUpperArm, HumanBodyBones.RightShoulder, new Vector3(upper, 0, 0));
|
||||
Add(HumanBodyBones.RightLowerArm, HumanBodyBones.RightUpperArm, new Vector3(lower, 0, 0));
|
||||
Add(HumanBodyBones.RightHand, HumanBodyBones.RightLowerArm, new Vector3(hand, 0, 0));
|
||||
}
|
||||
|
||||
public void AddLeg(float distance, float upper, float lower, float foot, float toe)
|
||||
{
|
||||
Add(HumanBodyBones.LeftUpperLeg, m_skeleton[HumanBodyBones.Hips], new Vector3(-distance, 0, 0), new Vector3(0, -upper, 0));
|
||||
Add(HumanBodyBones.LeftLowerLeg, HumanBodyBones.LeftUpperLeg, new Vector3(0, -lower, 0));
|
||||
Add(HumanBodyBones.LeftFoot, HumanBodyBones.LeftLowerLeg, new Vector3(0, -foot, foot));
|
||||
Add(HumanBodyBones.LeftToes, HumanBodyBones.LeftFoot, new Vector3(0, 0, toe));
|
||||
|
||||
Add(HumanBodyBones.RightUpperLeg, m_skeleton[HumanBodyBones.Hips], new Vector3(distance, 0, 0), new Vector3(0, -upper, 0));
|
||||
Add(HumanBodyBones.RightLowerLeg, HumanBodyBones.RightUpperLeg, new Vector3(0, -lower, 0));
|
||||
Add(HumanBodyBones.RightFoot, HumanBodyBones.RightLowerLeg, new Vector3(0, -foot, foot));
|
||||
Add(HumanBodyBones.RightToes, HumanBodyBones.RightFoot, new Vector3(0, 0, toe));
|
||||
}
|
||||
}
|
||||
|
||||
void OnEnable()
|
||||
{
|
||||
BuildSkeleton(transform);
|
||||
}
|
||||
|
||||
private void BuildSkeleton(Transform root)
|
||||
{
|
||||
var position = root.position;
|
||||
root.position = Vector3.zero;
|
||||
|
||||
try
|
||||
{
|
||||
// hips -> spine -> chest
|
||||
var builder = new SkeletonBuilder(root);
|
||||
builder.AddHips(0.8f, 0.2f);
|
||||
builder.AddSpine(0.1f);
|
||||
builder.AddChest(0.2f);
|
||||
builder.AddNeck(0.1f);
|
||||
builder.AddHead(0.2f);
|
||||
builder.AddArm(0.1f, 0.3f, 0.3f, 0.1f);
|
||||
builder.AddLeg(0.1f, 0.3f, 0.4f, 0.1f, 0.1f);
|
||||
|
||||
var description = AvatarDescription.Create(builder.Skeleton);
|
||||
var animator = GetComponent<Animator>();
|
||||
animator.avatar = description.CreateAvatar(root);
|
||||
|
||||
// create SkinnedMesh for bone visualize
|
||||
var renderer = SkeletonMeshUtility.CreateRenderer(animator);
|
||||
|
||||
if (m_material == null)
|
||||
{
|
||||
m_material = new Material(Shader.Find("Standard"));
|
||||
}
|
||||
renderer.sharedMaterial = m_material;
|
||||
//root.gameObject.AddComponent<BoneMapping>();
|
||||
|
||||
var transfer = GetComponent<HumanPoseTransfer>();
|
||||
if (transfer != null)
|
||||
{
|
||||
transfer.Avatar = animator.avatar;
|
||||
transfer.Setup();
|
||||
}
|
||||
}
|
||||
finally
|
||||
{
|
||||
// restore position
|
||||
root.position = position;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
using System.Collections;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using UnityEngine;
|
||||
|
||||
|
||||
namespace UniHumanoid
|
||||
{
|
||||
[RequireComponent(typeof(Animator))]
|
||||
public class HumanBuilderTest : MonoBehaviour
|
||||
{
|
||||
[SerializeField]
|
||||
Material m_material;
|
||||
|
||||
class SkeletonBuilder
|
||||
{
|
||||
Dictionary<HumanBodyBones, Transform> m_skeleton = new Dictionary<HumanBodyBones, Transform>();
|
||||
public IDictionary<HumanBodyBones, Transform> Skeleton
|
||||
{
|
||||
get { return m_skeleton; }
|
||||
}
|
||||
|
||||
Dictionary<HumanBodyBones, Vector3> m_boneTail = new Dictionary<HumanBodyBones, Vector3>();
|
||||
Transform m_root;
|
||||
|
||||
public SkeletonBuilder(Transform root)
|
||||
{
|
||||
m_root = root;
|
||||
}
|
||||
|
||||
void Add(HumanBodyBones key, Transform parent, Vector3 headPosition, Vector3 tailPosition)
|
||||
{
|
||||
var bone = new GameObject(key.ToString()).transform;
|
||||
bone.SetParent(parent, false);
|
||||
bone.localPosition = headPosition;
|
||||
m_skeleton[key] = bone;
|
||||
m_boneTail[key] = tailPosition;
|
||||
}
|
||||
|
||||
void Add(HumanBodyBones key, HumanBodyBones parentKey, Vector3 tailPosition)
|
||||
{
|
||||
Add(key, m_skeleton[parentKey], m_boneTail[parentKey], tailPosition);
|
||||
}
|
||||
|
||||
#region Spine
|
||||
public void AddHips(float height, float len)
|
||||
{
|
||||
Add(HumanBodyBones.Hips, m_root, new Vector3(0, height, 0), new Vector3(0, len, 0));
|
||||
}
|
||||
|
||||
public void AddSpine(float len)
|
||||
{
|
||||
Add(HumanBodyBones.Spine, HumanBodyBones.Hips, new Vector3(0, len, 0));
|
||||
}
|
||||
|
||||
public void AddChest(float len)
|
||||
{
|
||||
Add(HumanBodyBones.Chest, HumanBodyBones.Spine, new Vector3(0, len, 0));
|
||||
}
|
||||
|
||||
public void AddNeck(float len)
|
||||
{
|
||||
Add(HumanBodyBones.Neck, HumanBodyBones.Chest, new Vector3(0, len, 0));
|
||||
}
|
||||
|
||||
public void AddHead(float len)
|
||||
{
|
||||
Add(HumanBodyBones.Head, HumanBodyBones.Neck, new Vector3(0, len, 0));
|
||||
}
|
||||
#endregion
|
||||
|
||||
public void AddArm(float shoulder, float upper, float lower, float hand)
|
||||
{
|
||||
Add(HumanBodyBones.LeftShoulder, HumanBodyBones.Chest, new Vector3(-shoulder, 0, 0));
|
||||
Add(HumanBodyBones.LeftUpperArm, HumanBodyBones.LeftShoulder, new Vector3(-upper, 0, 0));
|
||||
Add(HumanBodyBones.LeftLowerArm, HumanBodyBones.LeftUpperArm, new Vector3(-lower, 0, 0));
|
||||
Add(HumanBodyBones.LeftHand, HumanBodyBones.LeftLowerArm, new Vector3(-hand, 0, 0));
|
||||
|
||||
Add(HumanBodyBones.RightShoulder, HumanBodyBones.Chest, new Vector3(shoulder, 0, 0));
|
||||
Add(HumanBodyBones.RightUpperArm, HumanBodyBones.RightShoulder, new Vector3(upper, 0, 0));
|
||||
Add(HumanBodyBones.RightLowerArm, HumanBodyBones.RightUpperArm, new Vector3(lower, 0, 0));
|
||||
Add(HumanBodyBones.RightHand, HumanBodyBones.RightLowerArm, new Vector3(hand, 0, 0));
|
||||
}
|
||||
|
||||
public void AddLeg(float distance, float upper, float lower, float foot, float toe)
|
||||
{
|
||||
Add(HumanBodyBones.LeftUpperLeg, m_skeleton[HumanBodyBones.Hips], new Vector3(-distance, 0, 0), new Vector3(0, -upper, 0));
|
||||
Add(HumanBodyBones.LeftLowerLeg, HumanBodyBones.LeftUpperLeg, new Vector3(0, -lower, 0));
|
||||
Add(HumanBodyBones.LeftFoot, HumanBodyBones.LeftLowerLeg, new Vector3(0, -foot, foot));
|
||||
Add(HumanBodyBones.LeftToes, HumanBodyBones.LeftFoot, new Vector3(0, 0, toe));
|
||||
|
||||
Add(HumanBodyBones.RightUpperLeg, m_skeleton[HumanBodyBones.Hips], new Vector3(distance, 0, 0), new Vector3(0, -upper, 0));
|
||||
Add(HumanBodyBones.RightLowerLeg, HumanBodyBones.RightUpperLeg, new Vector3(0, -lower, 0));
|
||||
Add(HumanBodyBones.RightFoot, HumanBodyBones.RightLowerLeg, new Vector3(0, -foot, foot));
|
||||
Add(HumanBodyBones.RightToes, HumanBodyBones.RightFoot, new Vector3(0, 0, toe));
|
||||
}
|
||||
}
|
||||
|
||||
void OnEnable()
|
||||
{
|
||||
BuildSkeleton(transform);
|
||||
}
|
||||
|
||||
private void BuildSkeleton(Transform root)
|
||||
{
|
||||
var position = root.position;
|
||||
root.position = Vector3.zero;
|
||||
|
||||
try
|
||||
{
|
||||
// hips -> spine -> chest
|
||||
var builder = new SkeletonBuilder(root);
|
||||
builder.AddHips(0.8f, 0.2f);
|
||||
builder.AddSpine(0.1f);
|
||||
builder.AddChest(0.2f);
|
||||
builder.AddNeck(0.1f);
|
||||
builder.AddHead(0.2f);
|
||||
builder.AddArm(0.1f, 0.3f, 0.3f, 0.1f);
|
||||
builder.AddLeg(0.1f, 0.3f, 0.4f, 0.1f, 0.1f);
|
||||
|
||||
var description = AvatarDescription.Create(builder.Skeleton);
|
||||
var animator = GetComponent<Animator>();
|
||||
animator.avatar = description.CreateAvatar(root);
|
||||
|
||||
// create SkinnedMesh for bone visualize
|
||||
var renderer = SkeletonMeshUtility.CreateRenderer(animator);
|
||||
|
||||
if (m_material == null)
|
||||
{
|
||||
m_material = new Material(Shader.Find("Standard"));
|
||||
}
|
||||
renderer.sharedMaterial = m_material;
|
||||
//root.gameObject.AddComponent<BoneMapping>();
|
||||
|
||||
var transfer = GetComponent<HumanPoseTransfer>();
|
||||
if (transfer != null)
|
||||
{
|
||||
transfer.Avatar = animator.avatar;
|
||||
transfer.Setup();
|
||||
}
|
||||
}
|
||||
finally
|
||||
{
|
||||
// restore position
|
||||
root.position = position;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,84 +1,84 @@
|
||||
using UnityEngine;
|
||||
using UnityEngine.Events;
|
||||
using UnityEngine.UI;
|
||||
using UniHumanoid;
|
||||
using System.IO;
|
||||
using System;
|
||||
#if UNITY_EDITOR
|
||||
using UnityEditor;
|
||||
#endif
|
||||
|
||||
|
||||
namespace UniHumanoid
|
||||
{
|
||||
public class RuntimeBvhLoader : MonoBehaviour
|
||||
{
|
||||
[SerializeField]
|
||||
Button m_openButton;
|
||||
|
||||
[SerializeField]
|
||||
HumanPoseTransfer m_dst;
|
||||
|
||||
UnityAction m_onClick;
|
||||
|
||||
private void Awake()
|
||||
{
|
||||
m_onClick = new UnityEngine.Events.UnityAction(OnClick);
|
||||
}
|
||||
|
||||
private void OnEnable()
|
||||
{
|
||||
m_openButton.onClick.AddListener(m_onClick);
|
||||
}
|
||||
|
||||
private void OnDisable()
|
||||
{
|
||||
m_openButton.onClick.RemoveListener(m_onClick);
|
||||
}
|
||||
|
||||
static string m_lastDir;
|
||||
|
||||
public void OnClick()
|
||||
{
|
||||
#if UNITY_EDITOR
|
||||
var path = EditorUtility.OpenFilePanel("open bvh", m_lastDir, "bvh");
|
||||
if (String.IsNullOrEmpty(path))
|
||||
{
|
||||
return;
|
||||
}
|
||||
m_lastDir = Path.GetDirectoryName(path);
|
||||
#else
|
||||
string path=null;
|
||||
throw new NotImplementedException();
|
||||
#endif
|
||||
|
||||
#pragma warning disable 4014
|
||||
Open(path);
|
||||
#pragma warning restore 4014
|
||||
}
|
||||
|
||||
BvhImporterContext m_context;
|
||||
|
||||
void Open(string path)
|
||||
{
|
||||
Debug.LogFormat("Open: {0}", path);
|
||||
if (m_context != null)
|
||||
{
|
||||
m_context.Destroy(true);
|
||||
m_context = null;
|
||||
}
|
||||
|
||||
m_context = new BvhImporterContext();
|
||||
m_context.Parse(path);
|
||||
m_context.Load();
|
||||
|
||||
var src = m_context.Root.AddComponent<HumanPoseTransfer>();
|
||||
|
||||
if (m_dst != null)
|
||||
{
|
||||
m_dst.SourceType = HumanPoseTransfer.HumanPoseTransferSourceType.HumanPoseTransfer;
|
||||
m_dst.Source = src;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
using UnityEngine;
|
||||
using UnityEngine.Events;
|
||||
using UnityEngine.UI;
|
||||
using UniHumanoid;
|
||||
using System.IO;
|
||||
using System;
|
||||
#if UNITY_EDITOR
|
||||
using UnityEditor;
|
||||
#endif
|
||||
|
||||
|
||||
namespace UniHumanoid
|
||||
{
|
||||
public class RuntimeBvhLoader : MonoBehaviour
|
||||
{
|
||||
[SerializeField]
|
||||
Button m_openButton;
|
||||
|
||||
[SerializeField]
|
||||
HumanPoseTransfer m_dst;
|
||||
|
||||
UnityAction m_onClick;
|
||||
|
||||
private void Awake()
|
||||
{
|
||||
m_onClick = new UnityEngine.Events.UnityAction(OnClick);
|
||||
}
|
||||
|
||||
private void OnEnable()
|
||||
{
|
||||
m_openButton.onClick.AddListener(m_onClick);
|
||||
}
|
||||
|
||||
private void OnDisable()
|
||||
{
|
||||
m_openButton.onClick.RemoveListener(m_onClick);
|
||||
}
|
||||
|
||||
static string m_lastDir;
|
||||
|
||||
public void OnClick()
|
||||
{
|
||||
#if UNITY_EDITOR
|
||||
var path = EditorUtility.OpenFilePanel("open bvh", m_lastDir, "bvh");
|
||||
if (String.IsNullOrEmpty(path))
|
||||
{
|
||||
return;
|
||||
}
|
||||
m_lastDir = Path.GetDirectoryName(path);
|
||||
#else
|
||||
string path=null;
|
||||
throw new NotImplementedException();
|
||||
#endif
|
||||
|
||||
#pragma warning disable 4014
|
||||
Open(path);
|
||||
#pragma warning restore 4014
|
||||
}
|
||||
|
||||
BvhImporterContext m_context;
|
||||
|
||||
void Open(string path)
|
||||
{
|
||||
Debug.LogFormat("Open: {0}", path);
|
||||
if (m_context != null)
|
||||
{
|
||||
m_context.Destroy(true);
|
||||
m_context = null;
|
||||
}
|
||||
|
||||
m_context = new BvhImporterContext();
|
||||
m_context.Parse(path);
|
||||
m_context.Load();
|
||||
|
||||
var src = m_context.Root.AddComponent<HumanPoseTransfer>();
|
||||
|
||||
if (m_dst != null)
|
||||
{
|
||||
m_dst.SourceType = HumanPoseTransfer.HumanPoseTransferSourceType.HumanPoseTransfer;
|
||||
m_dst.Source = src;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,134 +1,134 @@
|
||||
using System.Collections.Generic;
|
||||
using UnityEngine;
|
||||
|
||||
|
||||
namespace UniHumanoid
|
||||
{
|
||||
public static class AnimationClipUtility
|
||||
{
|
||||
static Dictionary<string, string> TraitPropMap = new Dictionary<string, string>
|
||||
{
|
||||
{"Left Thumb 1 Stretched", "LeftHand.Thumb.1 Stretched"},
|
||||
{"Left Thumb Spread", "LeftHand.Thumb Spread"},
|
||||
{"Left Thumb 2 Stretched", "LeftHand.Thumb.2 Stretched"},
|
||||
{"Left Thumb 3 Stretched", "LeftHand.Thumb.3 Stretched"},
|
||||
{"Left Index 1 Stretched", "LeftHand.Index.1 Stretched"},
|
||||
{"Left Index Spread", "LeftHand.Index Spread"},
|
||||
{"Left Index 2 Stretched", "LeftHand.Index.2 Stretched"},
|
||||
{"Left Index 3 Stretched", "LeftHand.Index.3 Stretched"},
|
||||
{"Left Middle 1 Stretched", "LeftHand.Middle.1 Stretched"},
|
||||
{"Left Middle Spread", "LeftHand.Middle Spread"},
|
||||
{"Left Middle 2 Stretched", "LeftHand.Middle.2 Stretched"},
|
||||
{"Left Middle 3 Stretched", "LeftHand.Middle.3 Stretched"},
|
||||
{"Left Ring 1 Stretched", "LeftHand.Ring.1 Stretched"},
|
||||
{"Left Ring Spread", "LeftHand.Ring Spread"},
|
||||
{"Left Ring 2 Stretched", "LeftHand.Ring.2 Stretched"},
|
||||
{"Left Ring 3 Stretched", "LeftHand.Ring.3 Stretched"},
|
||||
{"Left Little 1 Stretched", "LeftHand.Little.1 Stretched"},
|
||||
{"Left Little Spread", "LeftHand.Little Spread"},
|
||||
{"Left Little 2 Stretched", "LeftHand.Little.2 Stretched"},
|
||||
{"Left Little 3 Stretched", "LeftHand.Little.3 Stretched"},
|
||||
{"Right Thumb 1 Stretched", "RightHand.Thumb.1 Stretched"},
|
||||
{"Right Thumb Spread", "RightHand.Thumb Spread"},
|
||||
{"Right Thumb 2 Stretched", "RightHand.Thumb.2 Stretched"},
|
||||
{"Right Thumb 3 Stretched", "RightHand.Thumb.3 Stretched"},
|
||||
{"Right Index 1 Stretched", "RightHand.Index.1 Stretched"},
|
||||
{"Right Index Spread", "RightHand.Index Spread"},
|
||||
{"Right Index 2 Stretched", "RightHand.Index.2 Stretched"},
|
||||
{"Right Index 3 Stretched", "RightHand.Index.3 Stretched"},
|
||||
{"Right Middle 1 Stretched", "RightHand.Middle.1 Stretched"},
|
||||
{"Right Middle Spread", "RightHand.Middle Spread"},
|
||||
{"Right Middle 2 Stretched", "RightHand.Middle.2 Stretched"},
|
||||
{"Right Middle 3 Stretched", "RightHand.Middle.3 Stretched"},
|
||||
{"Right Ring 1 Stretched", "RightHand.Ring.1 Stretched"},
|
||||
{"Right Ring Spread", "RightHand.Ring Spread"},
|
||||
{"Right Ring 2 Stretched", "RightHand.Ring.2 Stretched"},
|
||||
{"Right Ring 3 Stretched", "RightHand.Ring.3 Stretched"},
|
||||
{"Right Little 1 Stretched", "RightHand.Little.1 Stretched"},
|
||||
{"Right Little Spread", "RightHand.Little Spread"},
|
||||
{"Right Little 2 Stretched", "RightHand.Little.2 Stretched"},
|
||||
{"Right Little 3 Stretched", "RightHand.Little.3 Stretched"},
|
||||
};
|
||||
|
||||
public static AnimationClip CreateAnimationClipFromHumanPose(HumanPose pose)
|
||||
{
|
||||
var clip = new AnimationClip();
|
||||
|
||||
// pos
|
||||
{
|
||||
var curve = new AnimationCurve(new Keyframe[]
|
||||
{
|
||||
new Keyframe(0, pose.bodyPosition.x),
|
||||
});
|
||||
var muscle = "RootT.x";
|
||||
clip.SetCurve(null, typeof(Animator), muscle, curve);
|
||||
}
|
||||
{
|
||||
var curve = new AnimationCurve(new Keyframe[]
|
||||
{
|
||||
new Keyframe(0, pose.bodyPosition.y),
|
||||
});
|
||||
var muscle = "RootT.y";
|
||||
clip.SetCurve(null, typeof(Animator), muscle, curve);
|
||||
}
|
||||
{
|
||||
var curve = new AnimationCurve(new Keyframe[]
|
||||
{
|
||||
new Keyframe(0, pose.bodyPosition.z),
|
||||
});
|
||||
var muscle = "RootT.z";
|
||||
clip.SetCurve(null, typeof(Animator), muscle, curve);
|
||||
}
|
||||
|
||||
// rot
|
||||
{
|
||||
var curve = new AnimationCurve(new Keyframe[]
|
||||
{
|
||||
new Keyframe(0, pose.bodyRotation.x),
|
||||
});
|
||||
var muscle = "RootQ.x";
|
||||
clip.SetCurve(null, typeof(Animator), muscle, curve);
|
||||
}
|
||||
{
|
||||
var curve = new AnimationCurve(new Keyframe[]
|
||||
{
|
||||
new Keyframe(0, pose.bodyRotation.y),
|
||||
});
|
||||
var muscle = "RootQ.y";
|
||||
clip.SetCurve(null, typeof(Animator), muscle, curve);
|
||||
}
|
||||
{
|
||||
var curve = new AnimationCurve(new Keyframe[]
|
||||
{
|
||||
new Keyframe(0, pose.bodyRotation.z),
|
||||
});
|
||||
var muscle = "RootQ.z";
|
||||
clip.SetCurve(null, typeof(Animator), muscle, curve);
|
||||
}
|
||||
{
|
||||
var curve = new AnimationCurve(new Keyframe[]
|
||||
{
|
||||
new Keyframe(0, pose.bodyRotation.w),
|
||||
});
|
||||
var muscle = "RootQ.w";
|
||||
clip.SetCurve(null, typeof(Animator), muscle, curve);
|
||||
}
|
||||
|
||||
// muscles
|
||||
for (int i = 0; i < HumanTrait.MuscleCount; ++i)
|
||||
{
|
||||
var curve = new AnimationCurve(new Keyframe[]
|
||||
{
|
||||
new Keyframe(0, pose.muscles[i]),
|
||||
});
|
||||
var muscle = HumanTrait.MuscleName[i];
|
||||
if (TraitPropMap.ContainsKey(muscle))
|
||||
{
|
||||
muscle = TraitPropMap[muscle];
|
||||
}
|
||||
clip.SetCurve(null, typeof(Animator), muscle, curve);
|
||||
}
|
||||
return clip;
|
||||
}
|
||||
}
|
||||
}
|
||||
using System.Collections.Generic;
|
||||
using UnityEngine;
|
||||
|
||||
|
||||
namespace UniHumanoid
|
||||
{
|
||||
public static class AnimationClipUtility
|
||||
{
|
||||
static Dictionary<string, string> TraitPropMap = new Dictionary<string, string>
|
||||
{
|
||||
{"Left Thumb 1 Stretched", "LeftHand.Thumb.1 Stretched"},
|
||||
{"Left Thumb Spread", "LeftHand.Thumb Spread"},
|
||||
{"Left Thumb 2 Stretched", "LeftHand.Thumb.2 Stretched"},
|
||||
{"Left Thumb 3 Stretched", "LeftHand.Thumb.3 Stretched"},
|
||||
{"Left Index 1 Stretched", "LeftHand.Index.1 Stretched"},
|
||||
{"Left Index Spread", "LeftHand.Index Spread"},
|
||||
{"Left Index 2 Stretched", "LeftHand.Index.2 Stretched"},
|
||||
{"Left Index 3 Stretched", "LeftHand.Index.3 Stretched"},
|
||||
{"Left Middle 1 Stretched", "LeftHand.Middle.1 Stretched"},
|
||||
{"Left Middle Spread", "LeftHand.Middle Spread"},
|
||||
{"Left Middle 2 Stretched", "LeftHand.Middle.2 Stretched"},
|
||||
{"Left Middle 3 Stretched", "LeftHand.Middle.3 Stretched"},
|
||||
{"Left Ring 1 Stretched", "LeftHand.Ring.1 Stretched"},
|
||||
{"Left Ring Spread", "LeftHand.Ring Spread"},
|
||||
{"Left Ring 2 Stretched", "LeftHand.Ring.2 Stretched"},
|
||||
{"Left Ring 3 Stretched", "LeftHand.Ring.3 Stretched"},
|
||||
{"Left Little 1 Stretched", "LeftHand.Little.1 Stretched"},
|
||||
{"Left Little Spread", "LeftHand.Little Spread"},
|
||||
{"Left Little 2 Stretched", "LeftHand.Little.2 Stretched"},
|
||||
{"Left Little 3 Stretched", "LeftHand.Little.3 Stretched"},
|
||||
{"Right Thumb 1 Stretched", "RightHand.Thumb.1 Stretched"},
|
||||
{"Right Thumb Spread", "RightHand.Thumb Spread"},
|
||||
{"Right Thumb 2 Stretched", "RightHand.Thumb.2 Stretched"},
|
||||
{"Right Thumb 3 Stretched", "RightHand.Thumb.3 Stretched"},
|
||||
{"Right Index 1 Stretched", "RightHand.Index.1 Stretched"},
|
||||
{"Right Index Spread", "RightHand.Index Spread"},
|
||||
{"Right Index 2 Stretched", "RightHand.Index.2 Stretched"},
|
||||
{"Right Index 3 Stretched", "RightHand.Index.3 Stretched"},
|
||||
{"Right Middle 1 Stretched", "RightHand.Middle.1 Stretched"},
|
||||
{"Right Middle Spread", "RightHand.Middle Spread"},
|
||||
{"Right Middle 2 Stretched", "RightHand.Middle.2 Stretched"},
|
||||
{"Right Middle 3 Stretched", "RightHand.Middle.3 Stretched"},
|
||||
{"Right Ring 1 Stretched", "RightHand.Ring.1 Stretched"},
|
||||
{"Right Ring Spread", "RightHand.Ring Spread"},
|
||||
{"Right Ring 2 Stretched", "RightHand.Ring.2 Stretched"},
|
||||
{"Right Ring 3 Stretched", "RightHand.Ring.3 Stretched"},
|
||||
{"Right Little 1 Stretched", "RightHand.Little.1 Stretched"},
|
||||
{"Right Little Spread", "RightHand.Little Spread"},
|
||||
{"Right Little 2 Stretched", "RightHand.Little.2 Stretched"},
|
||||
{"Right Little 3 Stretched", "RightHand.Little.3 Stretched"},
|
||||
};
|
||||
|
||||
public static AnimationClip CreateAnimationClipFromHumanPose(HumanPose pose)
|
||||
{
|
||||
var clip = new AnimationClip();
|
||||
|
||||
// pos
|
||||
{
|
||||
var curve = new AnimationCurve(new Keyframe[]
|
||||
{
|
||||
new Keyframe(0, pose.bodyPosition.x),
|
||||
});
|
||||
var muscle = "RootT.x";
|
||||
clip.SetCurve(null, typeof(Animator), muscle, curve);
|
||||
}
|
||||
{
|
||||
var curve = new AnimationCurve(new Keyframe[]
|
||||
{
|
||||
new Keyframe(0, pose.bodyPosition.y),
|
||||
});
|
||||
var muscle = "RootT.y";
|
||||
clip.SetCurve(null, typeof(Animator), muscle, curve);
|
||||
}
|
||||
{
|
||||
var curve = new AnimationCurve(new Keyframe[]
|
||||
{
|
||||
new Keyframe(0, pose.bodyPosition.z),
|
||||
});
|
||||
var muscle = "RootT.z";
|
||||
clip.SetCurve(null, typeof(Animator), muscle, curve);
|
||||
}
|
||||
|
||||
// rot
|
||||
{
|
||||
var curve = new AnimationCurve(new Keyframe[]
|
||||
{
|
||||
new Keyframe(0, pose.bodyRotation.x),
|
||||
});
|
||||
var muscle = "RootQ.x";
|
||||
clip.SetCurve(null, typeof(Animator), muscle, curve);
|
||||
}
|
||||
{
|
||||
var curve = new AnimationCurve(new Keyframe[]
|
||||
{
|
||||
new Keyframe(0, pose.bodyRotation.y),
|
||||
});
|
||||
var muscle = "RootQ.y";
|
||||
clip.SetCurve(null, typeof(Animator), muscle, curve);
|
||||
}
|
||||
{
|
||||
var curve = new AnimationCurve(new Keyframe[]
|
||||
{
|
||||
new Keyframe(0, pose.bodyRotation.z),
|
||||
});
|
||||
var muscle = "RootQ.z";
|
||||
clip.SetCurve(null, typeof(Animator), muscle, curve);
|
||||
}
|
||||
{
|
||||
var curve = new AnimationCurve(new Keyframe[]
|
||||
{
|
||||
new Keyframe(0, pose.bodyRotation.w),
|
||||
});
|
||||
var muscle = "RootQ.w";
|
||||
clip.SetCurve(null, typeof(Animator), muscle, curve);
|
||||
}
|
||||
|
||||
// muscles
|
||||
for (int i = 0; i < HumanTrait.MuscleCount; ++i)
|
||||
{
|
||||
var curve = new AnimationCurve(new Keyframe[]
|
||||
{
|
||||
new Keyframe(0, pose.muscles[i]),
|
||||
});
|
||||
var muscle = HumanTrait.MuscleName[i];
|
||||
if (TraitPropMap.ContainsKey(muscle))
|
||||
{
|
||||
muscle = TraitPropMap[muscle];
|
||||
}
|
||||
clip.SetCurve(null, typeof(Animator), muscle, curve);
|
||||
}
|
||||
return clip;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,242 +1,242 @@
|
||||
#if UNITY_EDITOR
|
||||
using UnityEditor;
|
||||
#endif
|
||||
using UnityEngine;
|
||||
using System;
|
||||
using System.Linq;
|
||||
using System.Collections.Generic;
|
||||
|
||||
|
||||
namespace UniHumanoid
|
||||
{
|
||||
[Serializable]
|
||||
public struct BoneLimit
|
||||
{
|
||||
public HumanBodyBones humanBone;
|
||||
public string boneName;
|
||||
public bool useDefaultValues;
|
||||
public Vector3 min;
|
||||
public Vector3 max;
|
||||
public Vector3 center;
|
||||
public float axisLength;
|
||||
|
||||
public static BoneLimit From(HumanBone bone)
|
||||
{
|
||||
return new BoneLimit
|
||||
{
|
||||
humanBone = (HumanBodyBones)Enum.Parse(typeof(HumanBodyBones), bone.humanName.Replace(" ", ""), true),
|
||||
boneName = bone.boneName,
|
||||
useDefaultValues = bone.limit.useDefaultValues,
|
||||
min = bone.limit.min,
|
||||
max = bone.limit.max,
|
||||
center = bone.limit.center,
|
||||
axisLength = bone.limit.axisLength,
|
||||
};
|
||||
}
|
||||
|
||||
public static String ToHumanBoneName(HumanBodyBones b)
|
||||
{
|
||||
foreach (var x in HumanTrait.BoneName)
|
||||
{
|
||||
if (x.Replace(" ", "") == b.ToString())
|
||||
{
|
||||
return x;
|
||||
}
|
||||
}
|
||||
|
||||
throw new KeyNotFoundException();
|
||||
}
|
||||
|
||||
public HumanBone ToHumanBone()
|
||||
{
|
||||
return new HumanBone
|
||||
{
|
||||
boneName = boneName,
|
||||
humanName = ToHumanBoneName(humanBone),
|
||||
limit = new HumanLimit
|
||||
{
|
||||
useDefaultValues = useDefaultValues,
|
||||
axisLength = axisLength,
|
||||
center = center,
|
||||
max = max,
|
||||
min = min
|
||||
},
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
[Serializable]
|
||||
public class AvatarDescription : ScriptableObject
|
||||
{
|
||||
public float armStretch = 0.05f;
|
||||
public float legStretch = 0.05f;
|
||||
public float upperArmTwist = 0.5f;
|
||||
public float lowerArmTwist = 0.5f;
|
||||
public float upperLegTwist = 0.5f;
|
||||
public float lowerLegTwist = 0.5f;
|
||||
public float feetSpacing = 0;
|
||||
public bool hasTranslationDoF;
|
||||
public BoneLimit[] human;
|
||||
|
||||
public HumanDescription ToHumanDescription(Transform root)
|
||||
{
|
||||
return new HumanDescription
|
||||
{
|
||||
skeleton = root.Traverse().Select(x => x.ToSkeletonBone()).ToArray(),
|
||||
human = human.Select(x => x.ToHumanBone()).ToArray(),
|
||||
armStretch = armStretch,
|
||||
legStretch = legStretch,
|
||||
upperArmTwist = upperArmTwist,
|
||||
lowerArmTwist = lowerArmTwist,
|
||||
upperLegTwist = upperLegTwist,
|
||||
lowerLegTwist = lowerLegTwist,
|
||||
feetSpacing = feetSpacing,
|
||||
hasTranslationDoF = hasTranslationDoF,
|
||||
};
|
||||
}
|
||||
|
||||
public Avatar CreateAvatar(Transform root)
|
||||
{
|
||||
return AvatarBuilder.BuildHumanAvatar(root.gameObject, ToHumanDescription(root));
|
||||
}
|
||||
|
||||
public Avatar CreateAvatarAndSetup(Transform root)
|
||||
{
|
||||
var avatar = CreateAvatar(root);
|
||||
avatar.name = name;
|
||||
|
||||
var animator = root.GetComponent<Animator>();
|
||||
if (animator != null)
|
||||
{
|
||||
var positionMap = root.Traverse().ToDictionary(x => x, x => x.position);
|
||||
animator.avatar = avatar;
|
||||
foreach (var x in root.Traverse())
|
||||
{
|
||||
x.position = positionMap[x];
|
||||
}
|
||||
}
|
||||
|
||||
var transfer = root.GetComponent<HumanPoseTransfer>();
|
||||
if (transfer != null)
|
||||
{
|
||||
transfer.Avatar = avatar;
|
||||
}
|
||||
|
||||
return avatar;
|
||||
}
|
||||
|
||||
#if UNITY_EDITOR
|
||||
public static AvatarDescription CreateFrom(Avatar avatar)
|
||||
{
|
||||
var description = default(HumanDescription);
|
||||
if (!GetHumanDescription(avatar, ref description))
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
return CreateFrom(description);
|
||||
}
|
||||
#endif
|
||||
|
||||
public static AvatarDescription CreateFrom(HumanDescription description)
|
||||
{
|
||||
var avatarDescription = ScriptableObject.CreateInstance<AvatarDescription>();
|
||||
avatarDescription.name = "AvatarDescription";
|
||||
avatarDescription.armStretch = description.armStretch;
|
||||
avatarDescription.legStretch = description.legStretch;
|
||||
avatarDescription.feetSpacing = description.feetSpacing;
|
||||
avatarDescription.hasTranslationDoF = description.hasTranslationDoF;
|
||||
avatarDescription.lowerArmTwist = description.lowerArmTwist;
|
||||
avatarDescription.lowerLegTwist = description.lowerLegTwist;
|
||||
avatarDescription.upperArmTwist = description.upperArmTwist;
|
||||
avatarDescription.upperLegTwist = description.upperLegTwist;
|
||||
avatarDescription.human = description.human.Select(BoneLimit.From).ToArray();
|
||||
return avatarDescription;
|
||||
}
|
||||
|
||||
public static AvatarDescription Create(AvatarDescription src=null)
|
||||
{
|
||||
var avatarDescription = ScriptableObject.CreateInstance<AvatarDescription>();
|
||||
avatarDescription.name = "AvatarDescription";
|
||||
if (src != null)
|
||||
{
|
||||
avatarDescription.armStretch = src.armStretch;
|
||||
avatarDescription.legStretch = src.legStretch;
|
||||
avatarDescription.feetSpacing = src.feetSpacing;
|
||||
avatarDescription.upperArmTwist = src.upperArmTwist;
|
||||
avatarDescription.lowerArmTwist = src.lowerArmTwist;
|
||||
avatarDescription.upperLegTwist = src.upperLegTwist;
|
||||
avatarDescription.lowerLegTwist = src.lowerLegTwist;
|
||||
}
|
||||
else
|
||||
{
|
||||
avatarDescription.armStretch = 0.05f;
|
||||
avatarDescription.legStretch = 0.05f;
|
||||
avatarDescription.feetSpacing = 0.0f;
|
||||
avatarDescription.lowerArmTwist = 0.5f;
|
||||
avatarDescription.upperArmTwist = 0.5f;
|
||||
avatarDescription.upperLegTwist = 0.5f;
|
||||
avatarDescription.lowerLegTwist = 0.5f;
|
||||
}
|
||||
return avatarDescription;
|
||||
}
|
||||
|
||||
public static AvatarDescription Create(Transform[] boneTransforms, Skeleton skeleton)
|
||||
{
|
||||
return Create(skeleton.Bones.Select(
|
||||
x => new KeyValuePair<HumanBodyBones, Transform>(x.Key, boneTransforms[x.Value])));
|
||||
}
|
||||
|
||||
public static AvatarDescription Create(IEnumerable<KeyValuePair<HumanBodyBones, Transform>> skeleton)
|
||||
{
|
||||
var description = Create();
|
||||
description.SetHumanBones(skeleton);
|
||||
return description;
|
||||
}
|
||||
|
||||
public void SetHumanBones(IEnumerable<KeyValuePair<HumanBodyBones, Transform>> skeleton)
|
||||
{
|
||||
human = skeleton.Select(x =>
|
||||
{
|
||||
return new BoneLimit
|
||||
{
|
||||
humanBone = x.Key,
|
||||
boneName = x.Value.name,
|
||||
useDefaultValues = true,
|
||||
};
|
||||
}).ToArray();
|
||||
}
|
||||
|
||||
#if UNITY_EDITOR
|
||||
/// <summary>
|
||||
/// * https://answers.unity.com/questions/612177/how-can-i-access-human-avatar-bone-and-muscle-valu.html
|
||||
/// </summary>
|
||||
/// <param name="target"></param>
|
||||
/// <param name="des"></param>
|
||||
/// <returns></returns>
|
||||
public static bool GetHumanDescription(UnityEngine.Object target, ref HumanDescription des)
|
||||
{
|
||||
if (target != null)
|
||||
{
|
||||
var importer = AssetImporter.GetAtPath(AssetDatabase.GetAssetPath(target));
|
||||
if (importer != null)
|
||||
{
|
||||
Debug.Log("AssetImporter Type: " + importer.GetType());
|
||||
ModelImporter modelImporter = importer as ModelImporter;
|
||||
if (modelImporter != null)
|
||||
{
|
||||
des = modelImporter.humanDescription;
|
||||
Debug.Log("## Cool stuff data by ModelImporter ##");
|
||||
return true;
|
||||
}
|
||||
else
|
||||
{
|
||||
Debug.LogWarning("## Please Select Imported Model in Project View not prefab or other things ##");
|
||||
}
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
#endif
|
||||
}
|
||||
}
|
||||
#if UNITY_EDITOR
|
||||
using UnityEditor;
|
||||
#endif
|
||||
using UnityEngine;
|
||||
using System;
|
||||
using System.Linq;
|
||||
using System.Collections.Generic;
|
||||
|
||||
|
||||
namespace UniHumanoid
|
||||
{
|
||||
[Serializable]
|
||||
public struct BoneLimit
|
||||
{
|
||||
public HumanBodyBones humanBone;
|
||||
public string boneName;
|
||||
public bool useDefaultValues;
|
||||
public Vector3 min;
|
||||
public Vector3 max;
|
||||
public Vector3 center;
|
||||
public float axisLength;
|
||||
|
||||
public static BoneLimit From(HumanBone bone)
|
||||
{
|
||||
return new BoneLimit
|
||||
{
|
||||
humanBone = (HumanBodyBones)Enum.Parse(typeof(HumanBodyBones), bone.humanName.Replace(" ", ""), true),
|
||||
boneName = bone.boneName,
|
||||
useDefaultValues = bone.limit.useDefaultValues,
|
||||
min = bone.limit.min,
|
||||
max = bone.limit.max,
|
||||
center = bone.limit.center,
|
||||
axisLength = bone.limit.axisLength,
|
||||
};
|
||||
}
|
||||
|
||||
public static String ToHumanBoneName(HumanBodyBones b)
|
||||
{
|
||||
foreach (var x in HumanTrait.BoneName)
|
||||
{
|
||||
if (x.Replace(" ", "") == b.ToString())
|
||||
{
|
||||
return x;
|
||||
}
|
||||
}
|
||||
|
||||
throw new KeyNotFoundException();
|
||||
}
|
||||
|
||||
public HumanBone ToHumanBone()
|
||||
{
|
||||
return new HumanBone
|
||||
{
|
||||
boneName = boneName,
|
||||
humanName = ToHumanBoneName(humanBone),
|
||||
limit = new HumanLimit
|
||||
{
|
||||
useDefaultValues = useDefaultValues,
|
||||
axisLength = axisLength,
|
||||
center = center,
|
||||
max = max,
|
||||
min = min
|
||||
},
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
[Serializable]
|
||||
public class AvatarDescription : ScriptableObject
|
||||
{
|
||||
public float armStretch = 0.05f;
|
||||
public float legStretch = 0.05f;
|
||||
public float upperArmTwist = 0.5f;
|
||||
public float lowerArmTwist = 0.5f;
|
||||
public float upperLegTwist = 0.5f;
|
||||
public float lowerLegTwist = 0.5f;
|
||||
public float feetSpacing = 0;
|
||||
public bool hasTranslationDoF;
|
||||
public BoneLimit[] human;
|
||||
|
||||
public HumanDescription ToHumanDescription(Transform root)
|
||||
{
|
||||
return new HumanDescription
|
||||
{
|
||||
skeleton = root.Traverse().Select(x => x.ToSkeletonBone()).ToArray(),
|
||||
human = human.Select(x => x.ToHumanBone()).ToArray(),
|
||||
armStretch = armStretch,
|
||||
legStretch = legStretch,
|
||||
upperArmTwist = upperArmTwist,
|
||||
lowerArmTwist = lowerArmTwist,
|
||||
upperLegTwist = upperLegTwist,
|
||||
lowerLegTwist = lowerLegTwist,
|
||||
feetSpacing = feetSpacing,
|
||||
hasTranslationDoF = hasTranslationDoF,
|
||||
};
|
||||
}
|
||||
|
||||
public Avatar CreateAvatar(Transform root)
|
||||
{
|
||||
return AvatarBuilder.BuildHumanAvatar(root.gameObject, ToHumanDescription(root));
|
||||
}
|
||||
|
||||
public Avatar CreateAvatarAndSetup(Transform root)
|
||||
{
|
||||
var avatar = CreateAvatar(root);
|
||||
avatar.name = name;
|
||||
|
||||
var animator = root.GetComponent<Animator>();
|
||||
if (animator != null)
|
||||
{
|
||||
var positionMap = root.Traverse().ToDictionary(x => x, x => x.position);
|
||||
animator.avatar = avatar;
|
||||
foreach (var x in root.Traverse())
|
||||
{
|
||||
x.position = positionMap[x];
|
||||
}
|
||||
}
|
||||
|
||||
var transfer = root.GetComponent<HumanPoseTransfer>();
|
||||
if (transfer != null)
|
||||
{
|
||||
transfer.Avatar = avatar;
|
||||
}
|
||||
|
||||
return avatar;
|
||||
}
|
||||
|
||||
#if UNITY_EDITOR
|
||||
public static AvatarDescription CreateFrom(Avatar avatar)
|
||||
{
|
||||
var description = default(HumanDescription);
|
||||
if (!GetHumanDescription(avatar, ref description))
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
return CreateFrom(description);
|
||||
}
|
||||
#endif
|
||||
|
||||
public static AvatarDescription CreateFrom(HumanDescription description)
|
||||
{
|
||||
var avatarDescription = ScriptableObject.CreateInstance<AvatarDescription>();
|
||||
avatarDescription.name = "AvatarDescription";
|
||||
avatarDescription.armStretch = description.armStretch;
|
||||
avatarDescription.legStretch = description.legStretch;
|
||||
avatarDescription.feetSpacing = description.feetSpacing;
|
||||
avatarDescription.hasTranslationDoF = description.hasTranslationDoF;
|
||||
avatarDescription.lowerArmTwist = description.lowerArmTwist;
|
||||
avatarDescription.lowerLegTwist = description.lowerLegTwist;
|
||||
avatarDescription.upperArmTwist = description.upperArmTwist;
|
||||
avatarDescription.upperLegTwist = description.upperLegTwist;
|
||||
avatarDescription.human = description.human.Select(BoneLimit.From).ToArray();
|
||||
return avatarDescription;
|
||||
}
|
||||
|
||||
public static AvatarDescription Create(AvatarDescription src=null)
|
||||
{
|
||||
var avatarDescription = ScriptableObject.CreateInstance<AvatarDescription>();
|
||||
avatarDescription.name = "AvatarDescription";
|
||||
if (src != null)
|
||||
{
|
||||
avatarDescription.armStretch = src.armStretch;
|
||||
avatarDescription.legStretch = src.legStretch;
|
||||
avatarDescription.feetSpacing = src.feetSpacing;
|
||||
avatarDescription.upperArmTwist = src.upperArmTwist;
|
||||
avatarDescription.lowerArmTwist = src.lowerArmTwist;
|
||||
avatarDescription.upperLegTwist = src.upperLegTwist;
|
||||
avatarDescription.lowerLegTwist = src.lowerLegTwist;
|
||||
}
|
||||
else
|
||||
{
|
||||
avatarDescription.armStretch = 0.05f;
|
||||
avatarDescription.legStretch = 0.05f;
|
||||
avatarDescription.feetSpacing = 0.0f;
|
||||
avatarDescription.lowerArmTwist = 0.5f;
|
||||
avatarDescription.upperArmTwist = 0.5f;
|
||||
avatarDescription.upperLegTwist = 0.5f;
|
||||
avatarDescription.lowerLegTwist = 0.5f;
|
||||
}
|
||||
return avatarDescription;
|
||||
}
|
||||
|
||||
public static AvatarDescription Create(Transform[] boneTransforms, Skeleton skeleton)
|
||||
{
|
||||
return Create(skeleton.Bones.Select(
|
||||
x => new KeyValuePair<HumanBodyBones, Transform>(x.Key, boneTransforms[x.Value])));
|
||||
}
|
||||
|
||||
public static AvatarDescription Create(IEnumerable<KeyValuePair<HumanBodyBones, Transform>> skeleton)
|
||||
{
|
||||
var description = Create();
|
||||
description.SetHumanBones(skeleton);
|
||||
return description;
|
||||
}
|
||||
|
||||
public void SetHumanBones(IEnumerable<KeyValuePair<HumanBodyBones, Transform>> skeleton)
|
||||
{
|
||||
human = skeleton.Select(x =>
|
||||
{
|
||||
return new BoneLimit
|
||||
{
|
||||
humanBone = x.Key,
|
||||
boneName = x.Value.name,
|
||||
useDefaultValues = true,
|
||||
};
|
||||
}).ToArray();
|
||||
}
|
||||
|
||||
#if UNITY_EDITOR
|
||||
/// <summary>
|
||||
/// * https://answers.unity.com/questions/612177/how-can-i-access-human-avatar-bone-and-muscle-valu.html
|
||||
/// </summary>
|
||||
/// <param name="target"></param>
|
||||
/// <param name="des"></param>
|
||||
/// <returns></returns>
|
||||
public static bool GetHumanDescription(UnityEngine.Object target, ref HumanDescription des)
|
||||
{
|
||||
if (target != null)
|
||||
{
|
||||
var importer = AssetImporter.GetAtPath(AssetDatabase.GetAssetPath(target));
|
||||
if (importer != null)
|
||||
{
|
||||
Debug.Log("AssetImporter Type: " + importer.GetType());
|
||||
ModelImporter modelImporter = importer as ModelImporter;
|
||||
if (modelImporter != null)
|
||||
{
|
||||
des = modelImporter.humanDescription;
|
||||
Debug.Log("## Cool stuff data by ModelImporter ##");
|
||||
return true;
|
||||
}
|
||||
else
|
||||
{
|
||||
Debug.LogWarning("## Please Select Imported Model in Project View not prefab or other things ##");
|
||||
}
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
#endif
|
||||
}
|
||||
}
|
||||
@@ -1,28 +1,28 @@
|
||||
using UnityEngine;
|
||||
|
||||
|
||||
namespace UniHumanoid
|
||||
{
|
||||
public class BoneGizmoDrawer : MonoBehaviour
|
||||
{
|
||||
const float size = 0.03f;
|
||||
readonly Vector3 SIZE = new Vector3(size, size, size);
|
||||
|
||||
[SerializeField]
|
||||
public bool Draw = true;
|
||||
|
||||
void OnDrawGizmos()
|
||||
{
|
||||
#if UNITY_EDITOR
|
||||
if (Draw && transform.parent != null)
|
||||
{
|
||||
Gizmos.color = Color.yellow;
|
||||
Gizmos.DrawCube(transform.position, SIZE);
|
||||
Gizmos.DrawLine(transform.parent.position, transform.position);
|
||||
|
||||
UnityEditor.Handles.Label(transform.position, name);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
}
|
||||
}
|
||||
using UnityEngine;
|
||||
|
||||
|
||||
namespace UniHumanoid
|
||||
{
|
||||
public class BoneGizmoDrawer : MonoBehaviour
|
||||
{
|
||||
const float size = 0.03f;
|
||||
readonly Vector3 SIZE = new Vector3(size, size, size);
|
||||
|
||||
[SerializeField]
|
||||
public bool Draw = true;
|
||||
|
||||
void OnDrawGizmos()
|
||||
{
|
||||
#if UNITY_EDITOR
|
||||
if (Draw && transform.parent != null)
|
||||
{
|
||||
Gizmos.color = Color.yellow;
|
||||
Gizmos.DrawCube(transform.position, SIZE);
|
||||
Gizmos.DrawLine(transform.parent.position, transform.position);
|
||||
|
||||
UnityEditor.Handles.Label(transform.position, name);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,103 +1,103 @@
|
||||
using UnityEngine;
|
||||
using System.Linq;
|
||||
using System;
|
||||
|
||||
namespace UniHumanoid
|
||||
{
|
||||
public class BoneMapping : MonoBehaviour
|
||||
{
|
||||
[SerializeField]
|
||||
public GameObject[] Bones = new GameObject[(int)HumanBodyBones.LastBone];
|
||||
|
||||
[SerializeField]
|
||||
public AvatarDescription Description;
|
||||
|
||||
private void Reset()
|
||||
{
|
||||
GetBones();
|
||||
}
|
||||
|
||||
private void GetBones()
|
||||
{
|
||||
Bones = new GameObject[(int)HumanBodyBones.LastBone];
|
||||
|
||||
var animator = GetComponent<Animator>();
|
||||
if (animator != null)
|
||||
{
|
||||
if (animator.avatar != null)
|
||||
{
|
||||
foreach (HumanBodyBones key in Enum.GetValues(typeof(HumanBodyBones)))
|
||||
{
|
||||
if (key == HumanBodyBones.LastBone)
|
||||
{
|
||||
break;
|
||||
}
|
||||
var transform = animator.GetBoneTransform(key);
|
||||
if (transform != null)
|
||||
{
|
||||
Bones[(int)key] = transform.gameObject;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void GuessBoneMapping()
|
||||
{
|
||||
var hips = Bones[(int)HumanBodyBones.Hips];
|
||||
if (hips == null)
|
||||
{
|
||||
Debug.LogWarning("require hips");
|
||||
return;
|
||||
}
|
||||
|
||||
var estimater = new BvhSkeletonEstimator();
|
||||
var skeleton = estimater.Detect(hips.transform);
|
||||
var bones = hips.transform.Traverse().ToArray();
|
||||
for (int i = 0; i < (int)HumanBodyBones.LastBone; ++i)
|
||||
{
|
||||
var index = skeleton.GetBoneIndex((HumanBodyBones)i);
|
||||
if (index >= 0)
|
||||
{
|
||||
Bones[i] = bones[index].gameObject;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void EnsureTPose()
|
||||
{
|
||||
var map = Bones
|
||||
.Select((x, i) => new { i, x })
|
||||
.Where(x => x.x != null)
|
||||
.ToDictionary(x => (HumanBodyBones)x.i, x => x.x.transform)
|
||||
;
|
||||
{
|
||||
var left = (map[HumanBodyBones.LeftLowerArm].position - map[HumanBodyBones.LeftUpperArm].position).normalized;
|
||||
map[HumanBodyBones.LeftUpperArm].rotation = Quaternion.FromToRotation(left, Vector3.left) * map[HumanBodyBones.LeftUpperArm].rotation;
|
||||
}
|
||||
{
|
||||
var right = (map[HumanBodyBones.RightLowerArm].position - map[HumanBodyBones.RightUpperArm].position).normalized;
|
||||
map[HumanBodyBones.RightUpperArm].rotation = Quaternion.FromToRotation(right, Vector3.right) * map[HumanBodyBones.RightUpperArm].rotation;
|
||||
}
|
||||
}
|
||||
|
||||
public static void SetBonesToDescription(BoneMapping mapping, AvatarDescription description)
|
||||
{
|
||||
var map = mapping.Bones
|
||||
.Select((x, i) => new { i, x })
|
||||
.Where(x => x.x != null)
|
||||
.ToDictionary(x => (HumanBodyBones)x.i, x => x.x.transform)
|
||||
;
|
||||
description.SetHumanBones(map);
|
||||
}
|
||||
|
||||
private void Awake()
|
||||
{
|
||||
if (Bones == null
|
||||
|| Bones.All(x => x==null))
|
||||
{
|
||||
GetBones();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
using UnityEngine;
|
||||
using System.Linq;
|
||||
using System;
|
||||
|
||||
namespace UniHumanoid
|
||||
{
|
||||
public class BoneMapping : MonoBehaviour
|
||||
{
|
||||
[SerializeField]
|
||||
public GameObject[] Bones = new GameObject[(int)HumanBodyBones.LastBone];
|
||||
|
||||
[SerializeField]
|
||||
public AvatarDescription Description;
|
||||
|
||||
private void Reset()
|
||||
{
|
||||
GetBones();
|
||||
}
|
||||
|
||||
private void GetBones()
|
||||
{
|
||||
Bones = new GameObject[(int)HumanBodyBones.LastBone];
|
||||
|
||||
var animator = GetComponent<Animator>();
|
||||
if (animator != null)
|
||||
{
|
||||
if (animator.avatar != null)
|
||||
{
|
||||
foreach (HumanBodyBones key in Enum.GetValues(typeof(HumanBodyBones)))
|
||||
{
|
||||
if (key == HumanBodyBones.LastBone)
|
||||
{
|
||||
break;
|
||||
}
|
||||
var transform = animator.GetBoneTransform(key);
|
||||
if (transform != null)
|
||||
{
|
||||
Bones[(int)key] = transform.gameObject;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void GuessBoneMapping()
|
||||
{
|
||||
var hips = Bones[(int)HumanBodyBones.Hips];
|
||||
if (hips == null)
|
||||
{
|
||||
Debug.LogWarning("require hips");
|
||||
return;
|
||||
}
|
||||
|
||||
var estimater = new BvhSkeletonEstimator();
|
||||
var skeleton = estimater.Detect(hips.transform);
|
||||
var bones = hips.transform.Traverse().ToArray();
|
||||
for (int i = 0; i < (int)HumanBodyBones.LastBone; ++i)
|
||||
{
|
||||
var index = skeleton.GetBoneIndex((HumanBodyBones)i);
|
||||
if (index >= 0)
|
||||
{
|
||||
Bones[i] = bones[index].gameObject;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void EnsureTPose()
|
||||
{
|
||||
var map = Bones
|
||||
.Select((x, i) => new { i, x })
|
||||
.Where(x => x.x != null)
|
||||
.ToDictionary(x => (HumanBodyBones)x.i, x => x.x.transform)
|
||||
;
|
||||
{
|
||||
var left = (map[HumanBodyBones.LeftLowerArm].position - map[HumanBodyBones.LeftUpperArm].position).normalized;
|
||||
map[HumanBodyBones.LeftUpperArm].rotation = Quaternion.FromToRotation(left, Vector3.left) * map[HumanBodyBones.LeftUpperArm].rotation;
|
||||
}
|
||||
{
|
||||
var right = (map[HumanBodyBones.RightLowerArm].position - map[HumanBodyBones.RightUpperArm].position).normalized;
|
||||
map[HumanBodyBones.RightUpperArm].rotation = Quaternion.FromToRotation(right, Vector3.right) * map[HumanBodyBones.RightUpperArm].rotation;
|
||||
}
|
||||
}
|
||||
|
||||
public static void SetBonesToDescription(BoneMapping mapping, AvatarDescription description)
|
||||
{
|
||||
var map = mapping.Bones
|
||||
.Select((x, i) => new { i, x })
|
||||
.Where(x => x.x != null)
|
||||
.ToDictionary(x => (HumanBodyBones)x.i, x => x.x.transform)
|
||||
;
|
||||
description.SetHumanBones(map);
|
||||
}
|
||||
|
||||
private void Awake()
|
||||
{
|
||||
if (Bones == null
|
||||
|| Bones.All(x => x==null))
|
||||
{
|
||||
GetBones();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,80 +1,80 @@
|
||||
using System.Collections.Generic;
|
||||
using UnityEngine;
|
||||
|
||||
|
||||
namespace UniHumanoid
|
||||
{
|
||||
public class BvhBone : IBone
|
||||
{
|
||||
public string Name
|
||||
{
|
||||
private set;
|
||||
get;
|
||||
}
|
||||
|
||||
public Vector3 SkeletonLocalPosition
|
||||
{
|
||||
private set;
|
||||
get;
|
||||
}
|
||||
|
||||
public BvhBone(string name, Vector3 position)
|
||||
{
|
||||
Name = name;
|
||||
SkeletonLocalPosition = position;
|
||||
}
|
||||
|
||||
public override string ToString()
|
||||
{
|
||||
return string.Format("<BvhBone: {0}>", Name);
|
||||
}
|
||||
|
||||
public IBone Parent
|
||||
{
|
||||
private set;
|
||||
get;
|
||||
}
|
||||
|
||||
List<IBone> _children = new List<IBone>();
|
||||
public IList<IBone> Children
|
||||
{
|
||||
get { return _children; }
|
||||
}
|
||||
|
||||
public void Build(Transform t)
|
||||
{
|
||||
foreach (Transform child in t)
|
||||
{
|
||||
var childBone = new BvhBone(child.name, SkeletonLocalPosition + child.localPosition);
|
||||
childBone.Parent = this;
|
||||
_children.Add(childBone);
|
||||
|
||||
childBone.Build(child);
|
||||
}
|
||||
}
|
||||
|
||||
public void Build(BvhNode node)
|
||||
{
|
||||
foreach (var child in node.Children)
|
||||
{
|
||||
var childBone = new BvhBone(child.Name, SkeletonLocalPosition + child.Offset.ToXReversedVector3());
|
||||
childBone.Parent = this;
|
||||
_children.Add(childBone);
|
||||
|
||||
childBone.Build(child);
|
||||
}
|
||||
}
|
||||
|
||||
public IEnumerable<BvhBone> Traverse()
|
||||
{
|
||||
yield return this;
|
||||
foreach (var child in Children)
|
||||
{
|
||||
foreach (var x in child.Traverse())
|
||||
{
|
||||
yield return (BvhBone)x;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
using System.Collections.Generic;
|
||||
using UnityEngine;
|
||||
|
||||
|
||||
namespace UniHumanoid
|
||||
{
|
||||
public class BvhBone : IBone
|
||||
{
|
||||
public string Name
|
||||
{
|
||||
private set;
|
||||
get;
|
||||
}
|
||||
|
||||
public Vector3 SkeletonLocalPosition
|
||||
{
|
||||
private set;
|
||||
get;
|
||||
}
|
||||
|
||||
public BvhBone(string name, Vector3 position)
|
||||
{
|
||||
Name = name;
|
||||
SkeletonLocalPosition = position;
|
||||
}
|
||||
|
||||
public override string ToString()
|
||||
{
|
||||
return string.Format("<BvhBone: {0}>", Name);
|
||||
}
|
||||
|
||||
public IBone Parent
|
||||
{
|
||||
private set;
|
||||
get;
|
||||
}
|
||||
|
||||
List<IBone> _children = new List<IBone>();
|
||||
public IList<IBone> Children
|
||||
{
|
||||
get { return _children; }
|
||||
}
|
||||
|
||||
public void Build(Transform t)
|
||||
{
|
||||
foreach (Transform child in t)
|
||||
{
|
||||
var childBone = new BvhBone(child.name, SkeletonLocalPosition + child.localPosition);
|
||||
childBone.Parent = this;
|
||||
_children.Add(childBone);
|
||||
|
||||
childBone.Build(child);
|
||||
}
|
||||
}
|
||||
|
||||
public void Build(BvhNode node)
|
||||
{
|
||||
foreach (var child in node.Children)
|
||||
{
|
||||
var childBone = new BvhBone(child.Name, SkeletonLocalPosition + child.Offset.ToXReversedVector3());
|
||||
childBone.Parent = this;
|
||||
_children.Add(childBone);
|
||||
|
||||
childBone.Build(child);
|
||||
}
|
||||
}
|
||||
|
||||
public IEnumerable<BvhBone> Traverse()
|
||||
{
|
||||
yield return this;
|
||||
foreach (var child in Children)
|
||||
{
|
||||
foreach (var x in child.Traverse())
|
||||
{
|
||||
yield return (BvhBone)x;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,419 +1,419 @@
|
||||
using System.Collections;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.IO;
|
||||
using UnityEditor;
|
||||
using UnityEngine;
|
||||
|
||||
|
||||
namespace UniHumanoid
|
||||
{
|
||||
[CustomEditor(typeof(BoneMapping))]
|
||||
public class BoneMappingEditor : Editor
|
||||
{
|
||||
BoneMapping m_target;
|
||||
|
||||
void OnEnable()
|
||||
{
|
||||
m_target = (BoneMapping)target;
|
||||
|
||||
var animator = m_target.GetComponent<Animator>();
|
||||
if (animator != null)
|
||||
{
|
||||
m_bones = EachBoneDefs.Select(x => new Bone(
|
||||
animator.GetBoneTransform(x.Head), animator.GetBoneTransform(x.Tail)))
|
||||
.Where(x => x.Head != null && x.Tail != null)
|
||||
.ToArray();
|
||||
}
|
||||
}
|
||||
|
||||
static GameObject ObjectField(GameObject obj)
|
||||
{
|
||||
return (GameObject)EditorGUILayout.ObjectField(obj, typeof(GameObject), true);
|
||||
}
|
||||
|
||||
static GameObject ObjectField(string label, GameObject obj)
|
||||
{
|
||||
return (GameObject)EditorGUILayout.ObjectField(label, obj, typeof(GameObject), true);
|
||||
}
|
||||
|
||||
const int LABEL_WIDTH = 100;
|
||||
|
||||
static void BoneField(HumanBodyBones bone, GameObject[] bones)
|
||||
{
|
||||
EditorGUILayout.BeginHorizontal();
|
||||
EditorGUILayout.LabelField(bone.ToString(), GUILayout.Width(LABEL_WIDTH));
|
||||
bones[(int)bone] = ObjectField(bones[(int)bone]);
|
||||
EditorGUILayout.EndHorizontal();
|
||||
}
|
||||
|
||||
static void BoneField(HumanBodyBones left, HumanBodyBones right, GameObject[] bones)
|
||||
{
|
||||
EditorGUILayout.BeginHorizontal();
|
||||
EditorGUILayout.LabelField(left.ToString().Substring(4), GUILayout.Width(LABEL_WIDTH)); // skip left
|
||||
bones[(int)left] = ObjectField(bones[(int)left]);
|
||||
bones[(int)right] = ObjectField(bones[(int)right]);
|
||||
EditorGUILayout.EndHorizontal();
|
||||
}
|
||||
|
||||
bool m_handFoldout;
|
||||
bool m_settingsFoldout;
|
||||
|
||||
public override void OnInspectorGUI()
|
||||
{
|
||||
var bones = m_target.Bones;
|
||||
if (bones == null)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
BoneField(HumanBodyBones.Hips, bones);
|
||||
|
||||
if (bones[(int)HumanBodyBones.Hips] == null)
|
||||
{
|
||||
EditorGUILayout.HelpBox(@"First, you set hips", MessageType.Warning);
|
||||
}
|
||||
else
|
||||
{
|
||||
if (GUILayout.Button("Guess bone mapping"))
|
||||
{
|
||||
m_target.GuessBoneMapping();
|
||||
}
|
||||
EditorGUILayout.HelpBox(@"Guess bones from hips", MessageType.Info);
|
||||
|
||||
if (GUILayout.Button("Ensure T-Pose"))
|
||||
{
|
||||
m_target.EnsureTPose();
|
||||
}
|
||||
EditorGUILayout.HelpBox(@"Arms to Horizontal", MessageType.Info);
|
||||
|
||||
if (GUILayout.Button("Create avatar"))
|
||||
{
|
||||
var description = AvatarDescription.Create(m_target.Description);
|
||||
BoneMapping.SetBonesToDescription(m_target, description);
|
||||
var avatar = description.CreateAvatarAndSetup(m_target.transform);
|
||||
if (avatar != null)
|
||||
{
|
||||
avatar.name = "avatar";
|
||||
#if UNITY_2018_2_OR_NEWER
|
||||
var prefabRoot = PrefabUtility.GetCorrespondingObjectFromSource(m_target.gameObject);
|
||||
#else
|
||||
var prefabRoot = PrefabUtility.GetPrefabParent(m_target.gameObject);
|
||||
#endif
|
||||
var prefabPath = AssetDatabase.GetAssetPath(prefabRoot);
|
||||
|
||||
var path = (string.IsNullOrEmpty(prefabPath))
|
||||
? string.Format("Assets/{0}.asset", avatar.name)
|
||||
: string.Format("{0}/{1}.asset", Path.GetDirectoryName(prefabPath), Path.GetFileNameWithoutExtension(prefabPath))
|
||||
;
|
||||
path = EditorUtility.SaveFilePanel(
|
||||
"Save avatar",
|
||||
Path.GetDirectoryName(path),
|
||||
string.Format("{0}.avatar.asset", serializedObject.targetObject.name),
|
||||
"asset");
|
||||
var assetPath = HumanPoseTransferEditor.ToAssetPath(path);
|
||||
if (!string.IsNullOrEmpty(assetPath))
|
||||
{
|
||||
AssetDatabase.CreateAsset(description, assetPath); // overwrite
|
||||
AssetDatabase.AddObjectToAsset(avatar, assetPath);
|
||||
|
||||
Debug.LogFormat("Create avatar {0}", path);
|
||||
AssetDatabase.ImportAsset(assetPath);
|
||||
Selection.activeObject = avatar;
|
||||
}
|
||||
else
|
||||
{
|
||||
Debug.LogWarning("fail to CreateAvatar");
|
||||
}
|
||||
}
|
||||
}
|
||||
EditorGUILayout.HelpBox(@"before create,
|
||||
|
||||
1. Model root transform should reset(origin without rotation)
|
||||
2. Model forward to Z+(rotate child of model root)
|
||||
3. Required bones filled
|
||||
", MessageType.Info);
|
||||
}
|
||||
|
||||
/*
|
||||
m_settingsFoldout = EditorGUILayout.Foldout(m_settingsFoldout, "AvatarSettings");
|
||||
if (m_settingsFoldout)
|
||||
{
|
||||
EditorGUILayout.FloatField("armStretch", m_target.armStretch);
|
||||
EditorGUILayout.FloatField("legStretch", m_target.legStretch);
|
||||
EditorGUILayout.FloatField("upperArmTwist", m_target.upperArmTwist);
|
||||
EditorGUILayout.FloatField("lowerArmTwist", m_target.lowerArmTwist);
|
||||
EditorGUILayout.FloatField("upperLegTwist", m_target.upperLegTwist);
|
||||
EditorGUILayout.FloatField("lowerLegTwist", m_target.lowerLegTwist);
|
||||
EditorGUILayout.FloatField("feetSpacing", m_target.feetSpacing);
|
||||
EditorGUILayout.Toggle("hasTranslationDoF", m_target.hasTranslationDoF);
|
||||
//public BoneLimit[] human;
|
||||
}
|
||||
*/
|
||||
|
||||
EditorGUILayout.BeginHorizontal();
|
||||
EditorGUILayout.LabelField("Arm", EditorStyles.boldLabel, GUILayout.Width(LABEL_WIDTH));
|
||||
EditorGUILayout.LabelField("Left", EditorStyles.boldLabel, GUILayout.Width(40));
|
||||
EditorGUILayout.Space();
|
||||
EditorGUILayout.LabelField("Right", EditorStyles.boldLabel, GUILayout.Width(40));
|
||||
EditorGUILayout.EndHorizontal();
|
||||
BoneField(HumanBodyBones.LeftShoulder, HumanBodyBones.RightShoulder, bones);
|
||||
BoneField(HumanBodyBones.LeftUpperArm, HumanBodyBones.RightUpperArm, bones);
|
||||
BoneField(HumanBodyBones.LeftLowerArm, HumanBodyBones.RightLowerArm, bones);
|
||||
BoneField(HumanBodyBones.LeftHand, HumanBodyBones.RightHand, bones);
|
||||
|
||||
EditorGUILayout.LabelField("Body and Head", EditorStyles.boldLabel);
|
||||
BoneField(HumanBodyBones.Spine, bones);
|
||||
BoneField(HumanBodyBones.Chest, bones);
|
||||
#if UNITY_5_6_OR_NEWER
|
||||
BoneField(HumanBodyBones.UpperChest, bones);
|
||||
#endif
|
||||
BoneField(HumanBodyBones.Neck, bones);
|
||||
BoneField(HumanBodyBones.Head, bones);
|
||||
BoneField(HumanBodyBones.Jaw, bones);
|
||||
BoneField(HumanBodyBones.LeftEye, HumanBodyBones.RightEye, bones);
|
||||
|
||||
EditorGUILayout.BeginHorizontal();
|
||||
EditorGUILayout.LabelField("Leg", EditorStyles.boldLabel, GUILayout.Width(LABEL_WIDTH));
|
||||
EditorGUILayout.LabelField("Left", EditorStyles.boldLabel, GUILayout.Width(40));
|
||||
EditorGUILayout.Space();
|
||||
EditorGUILayout.LabelField("Right", EditorStyles.boldLabel, GUILayout.Width(40));
|
||||
EditorGUILayout.EndHorizontal();
|
||||
BoneField(HumanBodyBones.LeftUpperLeg, HumanBodyBones.RightUpperLeg, bones);
|
||||
BoneField(HumanBodyBones.LeftLowerLeg, HumanBodyBones.RightLowerLeg, bones);
|
||||
BoneField(HumanBodyBones.LeftFoot, HumanBodyBones.RightFoot, bones);
|
||||
BoneField(HumanBodyBones.LeftToes, HumanBodyBones.RightToes, bones);
|
||||
|
||||
m_handFoldout = EditorGUILayout.Foldout(m_handFoldout, "Hand");
|
||||
if (m_handFoldout)
|
||||
{
|
||||
EditorGUILayout.BeginHorizontal();
|
||||
EditorGUILayout.LabelField("Thumb", EditorStyles.boldLabel, GUILayout.Width(LABEL_WIDTH));
|
||||
EditorGUILayout.LabelField("Left", EditorStyles.boldLabel, GUILayout.Width(40));
|
||||
EditorGUILayout.Space();
|
||||
EditorGUILayout.LabelField("Right", EditorStyles.boldLabel, GUILayout.Width(40));
|
||||
EditorGUILayout.EndHorizontal();
|
||||
BoneField(HumanBodyBones.LeftThumbProximal, HumanBodyBones.RightThumbProximal, bones);
|
||||
BoneField(HumanBodyBones.LeftThumbIntermediate, HumanBodyBones.RightThumbIntermediate, bones);
|
||||
BoneField(HumanBodyBones.LeftThumbDistal, HumanBodyBones.RightThumbDistal, bones);
|
||||
|
||||
EditorGUILayout.BeginHorizontal();
|
||||
EditorGUILayout.LabelField("Index", EditorStyles.boldLabel, GUILayout.Width(LABEL_WIDTH));
|
||||
EditorGUILayout.LabelField("Left", EditorStyles.boldLabel, GUILayout.Width(40));
|
||||
EditorGUILayout.Space();
|
||||
EditorGUILayout.LabelField("Right", EditorStyles.boldLabel, GUILayout.Width(40));
|
||||
EditorGUILayout.EndHorizontal();
|
||||
BoneField(HumanBodyBones.LeftIndexProximal, HumanBodyBones.RightIndexProximal, bones);
|
||||
BoneField(HumanBodyBones.LeftIndexIntermediate, HumanBodyBones.RightIndexIntermediate, bones);
|
||||
BoneField(HumanBodyBones.LeftIndexDistal, HumanBodyBones.RightIndexDistal, bones);
|
||||
|
||||
EditorGUILayout.BeginHorizontal();
|
||||
EditorGUILayout.LabelField("Middle", EditorStyles.boldLabel, GUILayout.Width(LABEL_WIDTH));
|
||||
EditorGUILayout.LabelField("Left", EditorStyles.boldLabel, GUILayout.Width(40));
|
||||
EditorGUILayout.Space();
|
||||
EditorGUILayout.LabelField("Right", EditorStyles.boldLabel, GUILayout.Width(40));
|
||||
EditorGUILayout.EndHorizontal();
|
||||
BoneField(HumanBodyBones.LeftMiddleProximal, HumanBodyBones.RightMiddleProximal, bones);
|
||||
BoneField(HumanBodyBones.LeftMiddleIntermediate, HumanBodyBones.RightMiddleIntermediate, bones);
|
||||
BoneField(HumanBodyBones.LeftMiddleDistal, HumanBodyBones.RightMiddleDistal, bones);
|
||||
|
||||
EditorGUILayout.BeginHorizontal();
|
||||
EditorGUILayout.LabelField("Ring", EditorStyles.boldLabel, GUILayout.Width(LABEL_WIDTH));
|
||||
EditorGUILayout.LabelField("Left", EditorStyles.boldLabel, GUILayout.Width(40));
|
||||
EditorGUILayout.Space();
|
||||
EditorGUILayout.LabelField("Right", EditorStyles.boldLabel, GUILayout.Width(40));
|
||||
EditorGUILayout.EndHorizontal();
|
||||
BoneField(HumanBodyBones.LeftRingProximal, HumanBodyBones.RightRingProximal, bones);
|
||||
BoneField(HumanBodyBones.LeftRingIntermediate, HumanBodyBones.RightRingIntermediate, bones);
|
||||
BoneField(HumanBodyBones.LeftRingDistal, HumanBodyBones.RightRingDistal, bones);
|
||||
|
||||
EditorGUILayout.BeginHorizontal();
|
||||
EditorGUILayout.LabelField("Little", EditorStyles.boldLabel, GUILayout.Width(LABEL_WIDTH));
|
||||
EditorGUILayout.LabelField("Left", EditorStyles.boldLabel, GUILayout.Width(40));
|
||||
EditorGUILayout.Space();
|
||||
EditorGUILayout.LabelField("Right", EditorStyles.boldLabel, GUILayout.Width(40));
|
||||
EditorGUILayout.EndHorizontal();
|
||||
BoneField(HumanBodyBones.LeftLittleProximal, HumanBodyBones.RightLittleProximal, bones);
|
||||
BoneField(HumanBodyBones.LeftLittleIntermediate, HumanBodyBones.RightLittleIntermediate, bones);
|
||||
BoneField(HumanBodyBones.LeftLittleDistal, HumanBodyBones.RightLittleDistal, bones);
|
||||
}
|
||||
|
||||
EditorUtility.SetDirty(m_target);
|
||||
}
|
||||
|
||||
struct Bone
|
||||
{
|
||||
public Transform Head;
|
||||
public Transform Tail;
|
||||
|
||||
public Bone(Transform head, Transform tail)
|
||||
{
|
||||
Head = head;
|
||||
Tail = tail;
|
||||
}
|
||||
|
||||
public void Draw()
|
||||
{
|
||||
Handles.DrawLine(Head.transform.position, Tail.transform.position);
|
||||
}
|
||||
}
|
||||
|
||||
Bone[] m_bones;
|
||||
|
||||
struct BoneDef
|
||||
{
|
||||
public HumanBodyBones Head;
|
||||
public HumanBodyBones Tail;
|
||||
|
||||
public BoneDef(HumanBodyBones head, HumanBodyBones tail)
|
||||
{
|
||||
Head = head;
|
||||
Tail = tail;
|
||||
}
|
||||
}
|
||||
static readonly HumanBodyBones[][] BoneDefs =
|
||||
{
|
||||
new HumanBodyBones[]
|
||||
{
|
||||
HumanBodyBones.Hips,
|
||||
HumanBodyBones.Spine,
|
||||
HumanBodyBones.Chest,
|
||||
HumanBodyBones.Neck,
|
||||
HumanBodyBones.Head,
|
||||
},
|
||||
new HumanBodyBones[]
|
||||
{
|
||||
HumanBodyBones.Chest,
|
||||
HumanBodyBones.LeftShoulder,
|
||||
HumanBodyBones.LeftUpperArm,
|
||||
HumanBodyBones.LeftLowerArm,
|
||||
HumanBodyBones.LeftHand,
|
||||
},
|
||||
new HumanBodyBones[]
|
||||
{
|
||||
HumanBodyBones.Chest,
|
||||
HumanBodyBones.RightShoulder,
|
||||
HumanBodyBones.RightUpperArm,
|
||||
HumanBodyBones.RightLowerArm,
|
||||
HumanBodyBones.RightHand,
|
||||
},
|
||||
|
||||
new HumanBodyBones[]
|
||||
{
|
||||
HumanBodyBones.LeftThumbProximal,
|
||||
HumanBodyBones.LeftThumbIntermediate,
|
||||
HumanBodyBones.LeftThumbDistal,
|
||||
},
|
||||
new HumanBodyBones[]
|
||||
{
|
||||
HumanBodyBones.LeftIndexProximal,
|
||||
HumanBodyBones.LeftIndexIntermediate,
|
||||
HumanBodyBones.LeftIndexDistal,
|
||||
},
|
||||
new HumanBodyBones[]
|
||||
{
|
||||
HumanBodyBones.LeftMiddleProximal,
|
||||
HumanBodyBones.LeftMiddleIntermediate,
|
||||
HumanBodyBones.LeftMiddleDistal,
|
||||
},
|
||||
new HumanBodyBones[]
|
||||
{
|
||||
HumanBodyBones.LeftRingProximal,
|
||||
HumanBodyBones.LeftRingIntermediate,
|
||||
HumanBodyBones.LeftRingDistal,
|
||||
},
|
||||
new HumanBodyBones[]
|
||||
{
|
||||
HumanBodyBones.LeftLittleProximal,
|
||||
HumanBodyBones.LeftLittleIntermediate,
|
||||
HumanBodyBones.LeftLittleDistal,
|
||||
},
|
||||
|
||||
new HumanBodyBones[]
|
||||
{
|
||||
HumanBodyBones.RightThumbProximal,
|
||||
HumanBodyBones.RightThumbIntermediate,
|
||||
HumanBodyBones.RightThumbDistal,
|
||||
},
|
||||
new HumanBodyBones[]
|
||||
{
|
||||
HumanBodyBones.RightIndexProximal,
|
||||
HumanBodyBones.RightIndexIntermediate,
|
||||
HumanBodyBones.RightIndexDistal,
|
||||
},
|
||||
new HumanBodyBones[]
|
||||
{
|
||||
HumanBodyBones.RightMiddleProximal,
|
||||
HumanBodyBones.RightMiddleIntermediate,
|
||||
HumanBodyBones.RightMiddleDistal,
|
||||
},
|
||||
new HumanBodyBones[]
|
||||
{
|
||||
HumanBodyBones.RightRingProximal,
|
||||
HumanBodyBones.RightRingIntermediate,
|
||||
HumanBodyBones.RightRingDistal,
|
||||
},
|
||||
new HumanBodyBones[]
|
||||
{
|
||||
HumanBodyBones.RightLittleProximal,
|
||||
HumanBodyBones.RightLittleIntermediate,
|
||||
HumanBodyBones.RightLittleDistal,
|
||||
},
|
||||
|
||||
new HumanBodyBones[]
|
||||
{
|
||||
HumanBodyBones.LeftUpperLeg,
|
||||
HumanBodyBones.LeftLowerLeg,
|
||||
HumanBodyBones.LeftFoot,
|
||||
},
|
||||
|
||||
new HumanBodyBones[]
|
||||
{
|
||||
HumanBodyBones.RightUpperLeg,
|
||||
HumanBodyBones.RightLowerLeg,
|
||||
HumanBodyBones.RightFoot,
|
||||
},
|
||||
};
|
||||
static IEnumerable<BoneDef> EachBoneDefs
|
||||
{
|
||||
get
|
||||
{
|
||||
foreach (var x in BoneDefs)
|
||||
{
|
||||
var count = x.Length - 1;
|
||||
for (int i = 0; i < count; ++i)
|
||||
{
|
||||
yield return new BoneDef(x[i], x[i + 1]);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void DrawBone(HumanBodyBones bone, GameObject go)
|
||||
{
|
||||
if (go == null)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
Handles.Label(go.transform.position,
|
||||
go.name + "\n(" + bone.ToString() + ")");
|
||||
}
|
||||
|
||||
private void OnSceneGUI()
|
||||
{
|
||||
var bones = m_target.Bones;
|
||||
if (bones != null)
|
||||
{
|
||||
for (int i = 0; i < bones.Length; ++i)
|
||||
{
|
||||
DrawBone((HumanBodyBones)i, bones[i]);
|
||||
}
|
||||
foreach(var x in m_bones)
|
||||
{
|
||||
x.Draw();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
using System.Collections;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.IO;
|
||||
using UnityEditor;
|
||||
using UnityEngine;
|
||||
|
||||
|
||||
namespace UniHumanoid
|
||||
{
|
||||
[CustomEditor(typeof(BoneMapping))]
|
||||
public class BoneMappingEditor : Editor
|
||||
{
|
||||
BoneMapping m_target;
|
||||
|
||||
void OnEnable()
|
||||
{
|
||||
m_target = (BoneMapping)target;
|
||||
|
||||
var animator = m_target.GetComponent<Animator>();
|
||||
if (animator != null)
|
||||
{
|
||||
m_bones = EachBoneDefs.Select(x => new Bone(
|
||||
animator.GetBoneTransform(x.Head), animator.GetBoneTransform(x.Tail)))
|
||||
.Where(x => x.Head != null && x.Tail != null)
|
||||
.ToArray();
|
||||
}
|
||||
}
|
||||
|
||||
static GameObject ObjectField(GameObject obj)
|
||||
{
|
||||
return (GameObject)EditorGUILayout.ObjectField(obj, typeof(GameObject), true);
|
||||
}
|
||||
|
||||
static GameObject ObjectField(string label, GameObject obj)
|
||||
{
|
||||
return (GameObject)EditorGUILayout.ObjectField(label, obj, typeof(GameObject), true);
|
||||
}
|
||||
|
||||
const int LABEL_WIDTH = 100;
|
||||
|
||||
static void BoneField(HumanBodyBones bone, GameObject[] bones)
|
||||
{
|
||||
EditorGUILayout.BeginHorizontal();
|
||||
EditorGUILayout.LabelField(bone.ToString(), GUILayout.Width(LABEL_WIDTH));
|
||||
bones[(int)bone] = ObjectField(bones[(int)bone]);
|
||||
EditorGUILayout.EndHorizontal();
|
||||
}
|
||||
|
||||
static void BoneField(HumanBodyBones left, HumanBodyBones right, GameObject[] bones)
|
||||
{
|
||||
EditorGUILayout.BeginHorizontal();
|
||||
EditorGUILayout.LabelField(left.ToString().Substring(4), GUILayout.Width(LABEL_WIDTH)); // skip left
|
||||
bones[(int)left] = ObjectField(bones[(int)left]);
|
||||
bones[(int)right] = ObjectField(bones[(int)right]);
|
||||
EditorGUILayout.EndHorizontal();
|
||||
}
|
||||
|
||||
bool m_handFoldout;
|
||||
bool m_settingsFoldout;
|
||||
|
||||
public override void OnInspectorGUI()
|
||||
{
|
||||
var bones = m_target.Bones;
|
||||
if (bones == null)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
BoneField(HumanBodyBones.Hips, bones);
|
||||
|
||||
if (bones[(int)HumanBodyBones.Hips] == null)
|
||||
{
|
||||
EditorGUILayout.HelpBox(@"First, you set hips", MessageType.Warning);
|
||||
}
|
||||
else
|
||||
{
|
||||
if (GUILayout.Button("Guess bone mapping"))
|
||||
{
|
||||
m_target.GuessBoneMapping();
|
||||
}
|
||||
EditorGUILayout.HelpBox(@"Guess bones from hips", MessageType.Info);
|
||||
|
||||
if (GUILayout.Button("Ensure T-Pose"))
|
||||
{
|
||||
m_target.EnsureTPose();
|
||||
}
|
||||
EditorGUILayout.HelpBox(@"Arms to Horizontal", MessageType.Info);
|
||||
|
||||
if (GUILayout.Button("Create avatar"))
|
||||
{
|
||||
var description = AvatarDescription.Create(m_target.Description);
|
||||
BoneMapping.SetBonesToDescription(m_target, description);
|
||||
var avatar = description.CreateAvatarAndSetup(m_target.transform);
|
||||
if (avatar != null)
|
||||
{
|
||||
avatar.name = "avatar";
|
||||
#if UNITY_2018_2_OR_NEWER
|
||||
var prefabRoot = PrefabUtility.GetCorrespondingObjectFromSource(m_target.gameObject);
|
||||
#else
|
||||
var prefabRoot = PrefabUtility.GetPrefabParent(m_target.gameObject);
|
||||
#endif
|
||||
var prefabPath = AssetDatabase.GetAssetPath(prefabRoot);
|
||||
|
||||
var path = (string.IsNullOrEmpty(prefabPath))
|
||||
? string.Format("Assets/{0}.asset", avatar.name)
|
||||
: string.Format("{0}/{1}.asset", Path.GetDirectoryName(prefabPath), Path.GetFileNameWithoutExtension(prefabPath))
|
||||
;
|
||||
path = EditorUtility.SaveFilePanel(
|
||||
"Save avatar",
|
||||
Path.GetDirectoryName(path),
|
||||
string.Format("{0}.avatar.asset", serializedObject.targetObject.name),
|
||||
"asset");
|
||||
var assetPath = HumanPoseTransferEditor.ToAssetPath(path);
|
||||
if (!string.IsNullOrEmpty(assetPath))
|
||||
{
|
||||
AssetDatabase.CreateAsset(description, assetPath); // overwrite
|
||||
AssetDatabase.AddObjectToAsset(avatar, assetPath);
|
||||
|
||||
Debug.LogFormat("Create avatar {0}", path);
|
||||
AssetDatabase.ImportAsset(assetPath);
|
||||
Selection.activeObject = avatar;
|
||||
}
|
||||
else
|
||||
{
|
||||
Debug.LogWarning("fail to CreateAvatar");
|
||||
}
|
||||
}
|
||||
}
|
||||
EditorGUILayout.HelpBox(@"before create,
|
||||
|
||||
1. Model root transform should reset(origin without rotation)
|
||||
2. Model forward to Z+(rotate child of model root)
|
||||
3. Required bones filled
|
||||
", MessageType.Info);
|
||||
}
|
||||
|
||||
/*
|
||||
m_settingsFoldout = EditorGUILayout.Foldout(m_settingsFoldout, "AvatarSettings");
|
||||
if (m_settingsFoldout)
|
||||
{
|
||||
EditorGUILayout.FloatField("armStretch", m_target.armStretch);
|
||||
EditorGUILayout.FloatField("legStretch", m_target.legStretch);
|
||||
EditorGUILayout.FloatField("upperArmTwist", m_target.upperArmTwist);
|
||||
EditorGUILayout.FloatField("lowerArmTwist", m_target.lowerArmTwist);
|
||||
EditorGUILayout.FloatField("upperLegTwist", m_target.upperLegTwist);
|
||||
EditorGUILayout.FloatField("lowerLegTwist", m_target.lowerLegTwist);
|
||||
EditorGUILayout.FloatField("feetSpacing", m_target.feetSpacing);
|
||||
EditorGUILayout.Toggle("hasTranslationDoF", m_target.hasTranslationDoF);
|
||||
//public BoneLimit[] human;
|
||||
}
|
||||
*/
|
||||
|
||||
EditorGUILayout.BeginHorizontal();
|
||||
EditorGUILayout.LabelField("Arm", EditorStyles.boldLabel, GUILayout.Width(LABEL_WIDTH));
|
||||
EditorGUILayout.LabelField("Left", EditorStyles.boldLabel, GUILayout.Width(40));
|
||||
EditorGUILayout.Space();
|
||||
EditorGUILayout.LabelField("Right", EditorStyles.boldLabel, GUILayout.Width(40));
|
||||
EditorGUILayout.EndHorizontal();
|
||||
BoneField(HumanBodyBones.LeftShoulder, HumanBodyBones.RightShoulder, bones);
|
||||
BoneField(HumanBodyBones.LeftUpperArm, HumanBodyBones.RightUpperArm, bones);
|
||||
BoneField(HumanBodyBones.LeftLowerArm, HumanBodyBones.RightLowerArm, bones);
|
||||
BoneField(HumanBodyBones.LeftHand, HumanBodyBones.RightHand, bones);
|
||||
|
||||
EditorGUILayout.LabelField("Body and Head", EditorStyles.boldLabel);
|
||||
BoneField(HumanBodyBones.Spine, bones);
|
||||
BoneField(HumanBodyBones.Chest, bones);
|
||||
#if UNITY_5_6_OR_NEWER
|
||||
BoneField(HumanBodyBones.UpperChest, bones);
|
||||
#endif
|
||||
BoneField(HumanBodyBones.Neck, bones);
|
||||
BoneField(HumanBodyBones.Head, bones);
|
||||
BoneField(HumanBodyBones.Jaw, bones);
|
||||
BoneField(HumanBodyBones.LeftEye, HumanBodyBones.RightEye, bones);
|
||||
|
||||
EditorGUILayout.BeginHorizontal();
|
||||
EditorGUILayout.LabelField("Leg", EditorStyles.boldLabel, GUILayout.Width(LABEL_WIDTH));
|
||||
EditorGUILayout.LabelField("Left", EditorStyles.boldLabel, GUILayout.Width(40));
|
||||
EditorGUILayout.Space();
|
||||
EditorGUILayout.LabelField("Right", EditorStyles.boldLabel, GUILayout.Width(40));
|
||||
EditorGUILayout.EndHorizontal();
|
||||
BoneField(HumanBodyBones.LeftUpperLeg, HumanBodyBones.RightUpperLeg, bones);
|
||||
BoneField(HumanBodyBones.LeftLowerLeg, HumanBodyBones.RightLowerLeg, bones);
|
||||
BoneField(HumanBodyBones.LeftFoot, HumanBodyBones.RightFoot, bones);
|
||||
BoneField(HumanBodyBones.LeftToes, HumanBodyBones.RightToes, bones);
|
||||
|
||||
m_handFoldout = EditorGUILayout.Foldout(m_handFoldout, "Hand");
|
||||
if (m_handFoldout)
|
||||
{
|
||||
EditorGUILayout.BeginHorizontal();
|
||||
EditorGUILayout.LabelField("Thumb", EditorStyles.boldLabel, GUILayout.Width(LABEL_WIDTH));
|
||||
EditorGUILayout.LabelField("Left", EditorStyles.boldLabel, GUILayout.Width(40));
|
||||
EditorGUILayout.Space();
|
||||
EditorGUILayout.LabelField("Right", EditorStyles.boldLabel, GUILayout.Width(40));
|
||||
EditorGUILayout.EndHorizontal();
|
||||
BoneField(HumanBodyBones.LeftThumbProximal, HumanBodyBones.RightThumbProximal, bones);
|
||||
BoneField(HumanBodyBones.LeftThumbIntermediate, HumanBodyBones.RightThumbIntermediate, bones);
|
||||
BoneField(HumanBodyBones.LeftThumbDistal, HumanBodyBones.RightThumbDistal, bones);
|
||||
|
||||
EditorGUILayout.BeginHorizontal();
|
||||
EditorGUILayout.LabelField("Index", EditorStyles.boldLabel, GUILayout.Width(LABEL_WIDTH));
|
||||
EditorGUILayout.LabelField("Left", EditorStyles.boldLabel, GUILayout.Width(40));
|
||||
EditorGUILayout.Space();
|
||||
EditorGUILayout.LabelField("Right", EditorStyles.boldLabel, GUILayout.Width(40));
|
||||
EditorGUILayout.EndHorizontal();
|
||||
BoneField(HumanBodyBones.LeftIndexProximal, HumanBodyBones.RightIndexProximal, bones);
|
||||
BoneField(HumanBodyBones.LeftIndexIntermediate, HumanBodyBones.RightIndexIntermediate, bones);
|
||||
BoneField(HumanBodyBones.LeftIndexDistal, HumanBodyBones.RightIndexDistal, bones);
|
||||
|
||||
EditorGUILayout.BeginHorizontal();
|
||||
EditorGUILayout.LabelField("Middle", EditorStyles.boldLabel, GUILayout.Width(LABEL_WIDTH));
|
||||
EditorGUILayout.LabelField("Left", EditorStyles.boldLabel, GUILayout.Width(40));
|
||||
EditorGUILayout.Space();
|
||||
EditorGUILayout.LabelField("Right", EditorStyles.boldLabel, GUILayout.Width(40));
|
||||
EditorGUILayout.EndHorizontal();
|
||||
BoneField(HumanBodyBones.LeftMiddleProximal, HumanBodyBones.RightMiddleProximal, bones);
|
||||
BoneField(HumanBodyBones.LeftMiddleIntermediate, HumanBodyBones.RightMiddleIntermediate, bones);
|
||||
BoneField(HumanBodyBones.LeftMiddleDistal, HumanBodyBones.RightMiddleDistal, bones);
|
||||
|
||||
EditorGUILayout.BeginHorizontal();
|
||||
EditorGUILayout.LabelField("Ring", EditorStyles.boldLabel, GUILayout.Width(LABEL_WIDTH));
|
||||
EditorGUILayout.LabelField("Left", EditorStyles.boldLabel, GUILayout.Width(40));
|
||||
EditorGUILayout.Space();
|
||||
EditorGUILayout.LabelField("Right", EditorStyles.boldLabel, GUILayout.Width(40));
|
||||
EditorGUILayout.EndHorizontal();
|
||||
BoneField(HumanBodyBones.LeftRingProximal, HumanBodyBones.RightRingProximal, bones);
|
||||
BoneField(HumanBodyBones.LeftRingIntermediate, HumanBodyBones.RightRingIntermediate, bones);
|
||||
BoneField(HumanBodyBones.LeftRingDistal, HumanBodyBones.RightRingDistal, bones);
|
||||
|
||||
EditorGUILayout.BeginHorizontal();
|
||||
EditorGUILayout.LabelField("Little", EditorStyles.boldLabel, GUILayout.Width(LABEL_WIDTH));
|
||||
EditorGUILayout.LabelField("Left", EditorStyles.boldLabel, GUILayout.Width(40));
|
||||
EditorGUILayout.Space();
|
||||
EditorGUILayout.LabelField("Right", EditorStyles.boldLabel, GUILayout.Width(40));
|
||||
EditorGUILayout.EndHorizontal();
|
||||
BoneField(HumanBodyBones.LeftLittleProximal, HumanBodyBones.RightLittleProximal, bones);
|
||||
BoneField(HumanBodyBones.LeftLittleIntermediate, HumanBodyBones.RightLittleIntermediate, bones);
|
||||
BoneField(HumanBodyBones.LeftLittleDistal, HumanBodyBones.RightLittleDistal, bones);
|
||||
}
|
||||
|
||||
EditorUtility.SetDirty(m_target);
|
||||
}
|
||||
|
||||
struct Bone
|
||||
{
|
||||
public Transform Head;
|
||||
public Transform Tail;
|
||||
|
||||
public Bone(Transform head, Transform tail)
|
||||
{
|
||||
Head = head;
|
||||
Tail = tail;
|
||||
}
|
||||
|
||||
public void Draw()
|
||||
{
|
||||
Handles.DrawLine(Head.transform.position, Tail.transform.position);
|
||||
}
|
||||
}
|
||||
|
||||
Bone[] m_bones;
|
||||
|
||||
struct BoneDef
|
||||
{
|
||||
public HumanBodyBones Head;
|
||||
public HumanBodyBones Tail;
|
||||
|
||||
public BoneDef(HumanBodyBones head, HumanBodyBones tail)
|
||||
{
|
||||
Head = head;
|
||||
Tail = tail;
|
||||
}
|
||||
}
|
||||
static readonly HumanBodyBones[][] BoneDefs =
|
||||
{
|
||||
new HumanBodyBones[]
|
||||
{
|
||||
HumanBodyBones.Hips,
|
||||
HumanBodyBones.Spine,
|
||||
HumanBodyBones.Chest,
|
||||
HumanBodyBones.Neck,
|
||||
HumanBodyBones.Head,
|
||||
},
|
||||
new HumanBodyBones[]
|
||||
{
|
||||
HumanBodyBones.Chest,
|
||||
HumanBodyBones.LeftShoulder,
|
||||
HumanBodyBones.LeftUpperArm,
|
||||
HumanBodyBones.LeftLowerArm,
|
||||
HumanBodyBones.LeftHand,
|
||||
},
|
||||
new HumanBodyBones[]
|
||||
{
|
||||
HumanBodyBones.Chest,
|
||||
HumanBodyBones.RightShoulder,
|
||||
HumanBodyBones.RightUpperArm,
|
||||
HumanBodyBones.RightLowerArm,
|
||||
HumanBodyBones.RightHand,
|
||||
},
|
||||
|
||||
new HumanBodyBones[]
|
||||
{
|
||||
HumanBodyBones.LeftThumbProximal,
|
||||
HumanBodyBones.LeftThumbIntermediate,
|
||||
HumanBodyBones.LeftThumbDistal,
|
||||
},
|
||||
new HumanBodyBones[]
|
||||
{
|
||||
HumanBodyBones.LeftIndexProximal,
|
||||
HumanBodyBones.LeftIndexIntermediate,
|
||||
HumanBodyBones.LeftIndexDistal,
|
||||
},
|
||||
new HumanBodyBones[]
|
||||
{
|
||||
HumanBodyBones.LeftMiddleProximal,
|
||||
HumanBodyBones.LeftMiddleIntermediate,
|
||||
HumanBodyBones.LeftMiddleDistal,
|
||||
},
|
||||
new HumanBodyBones[]
|
||||
{
|
||||
HumanBodyBones.LeftRingProximal,
|
||||
HumanBodyBones.LeftRingIntermediate,
|
||||
HumanBodyBones.LeftRingDistal,
|
||||
},
|
||||
new HumanBodyBones[]
|
||||
{
|
||||
HumanBodyBones.LeftLittleProximal,
|
||||
HumanBodyBones.LeftLittleIntermediate,
|
||||
HumanBodyBones.LeftLittleDistal,
|
||||
},
|
||||
|
||||
new HumanBodyBones[]
|
||||
{
|
||||
HumanBodyBones.RightThumbProximal,
|
||||
HumanBodyBones.RightThumbIntermediate,
|
||||
HumanBodyBones.RightThumbDistal,
|
||||
},
|
||||
new HumanBodyBones[]
|
||||
{
|
||||
HumanBodyBones.RightIndexProximal,
|
||||
HumanBodyBones.RightIndexIntermediate,
|
||||
HumanBodyBones.RightIndexDistal,
|
||||
},
|
||||
new HumanBodyBones[]
|
||||
{
|
||||
HumanBodyBones.RightMiddleProximal,
|
||||
HumanBodyBones.RightMiddleIntermediate,
|
||||
HumanBodyBones.RightMiddleDistal,
|
||||
},
|
||||
new HumanBodyBones[]
|
||||
{
|
||||
HumanBodyBones.RightRingProximal,
|
||||
HumanBodyBones.RightRingIntermediate,
|
||||
HumanBodyBones.RightRingDistal,
|
||||
},
|
||||
new HumanBodyBones[]
|
||||
{
|
||||
HumanBodyBones.RightLittleProximal,
|
||||
HumanBodyBones.RightLittleIntermediate,
|
||||
HumanBodyBones.RightLittleDistal,
|
||||
},
|
||||
|
||||
new HumanBodyBones[]
|
||||
{
|
||||
HumanBodyBones.LeftUpperLeg,
|
||||
HumanBodyBones.LeftLowerLeg,
|
||||
HumanBodyBones.LeftFoot,
|
||||
},
|
||||
|
||||
new HumanBodyBones[]
|
||||
{
|
||||
HumanBodyBones.RightUpperLeg,
|
||||
HumanBodyBones.RightLowerLeg,
|
||||
HumanBodyBones.RightFoot,
|
||||
},
|
||||
};
|
||||
static IEnumerable<BoneDef> EachBoneDefs
|
||||
{
|
||||
get
|
||||
{
|
||||
foreach (var x in BoneDefs)
|
||||
{
|
||||
var count = x.Length - 1;
|
||||
for (int i = 0; i < count; ++i)
|
||||
{
|
||||
yield return new BoneDef(x[i], x[i + 1]);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void DrawBone(HumanBodyBones bone, GameObject go)
|
||||
{
|
||||
if (go == null)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
Handles.Label(go.transform.position,
|
||||
go.name + "\n(" + bone.ToString() + ")");
|
||||
}
|
||||
|
||||
private void OnSceneGUI()
|
||||
{
|
||||
var bones = m_target.Bones;
|
||||
if (bones != null)
|
||||
{
|
||||
for (int i = 0; i < bones.Length; ++i)
|
||||
{
|
||||
DrawBone((HumanBodyBones)i, bones[i]);
|
||||
}
|
||||
foreach(var x in m_bones)
|
||||
{
|
||||
x.Draw();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,151 +1,151 @@
|
||||
using System;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using UnityEditor;
|
||||
using UnityEngine;
|
||||
|
||||
|
||||
namespace UniHumanoid
|
||||
{
|
||||
[CustomEditor(typeof(HumanPoseTransfer))]
|
||||
public class HumanPoseTransferEditor : Editor
|
||||
{
|
||||
//HumanPoseTransfer m_target;
|
||||
SerializedProperty m_avatarProp;
|
||||
SerializedProperty m_typeProp;
|
||||
SerializedProperty m_clipProp;
|
||||
SerializedProperty m_transferProp;
|
||||
|
||||
static string[] SOURCE_TYPES = ((HumanPoseTransfer.HumanPoseTransferSourceType[])
|
||||
Enum.GetValues(typeof(HumanPoseTransfer.HumanPoseTransferSourceType)))
|
||||
.Select(x => x.ToString())
|
||||
.ToArray();
|
||||
|
||||
private void OnEnable()
|
||||
{
|
||||
//m_target = (HumanPoseTransfer)target;
|
||||
m_typeProp = serializedObject.FindProperty("SourceType");
|
||||
m_clipProp = serializedObject.FindProperty("PoseClip");
|
||||
m_avatarProp = serializedObject.FindProperty("Avatar");
|
||||
m_transferProp = serializedObject.FindProperty("Source");
|
||||
}
|
||||
|
||||
public override void OnInspectorGUI()
|
||||
{
|
||||
//base.OnInspectorGUI();
|
||||
serializedObject.Update();
|
||||
|
||||
EditorGUILayout.PropertyField(m_avatarProp);
|
||||
|
||||
/*
|
||||
m_typeProp.intValue =
|
||||
GUILayout.Toolbar(m_typeProp.intValue, SOURCE_TYPES);
|
||||
*/
|
||||
m_typeProp.intValue =
|
||||
EditorGUILayout.Popup("SourceType", m_typeProp.intValue, SOURCE_TYPES);
|
||||
|
||||
switch ((HumanPoseTransfer.HumanPoseTransferSourceType)m_typeProp.intValue)
|
||||
{
|
||||
case HumanPoseTransfer.HumanPoseTransferSourceType.None:
|
||||
serializedObject.ApplyModifiedProperties();
|
||||
break;
|
||||
|
||||
case HumanPoseTransfer.HumanPoseTransferSourceType.HumanPoseClip:
|
||||
PoseClipInspector();
|
||||
break;
|
||||
|
||||
case HumanPoseTransfer.HumanPoseTransferSourceType.HumanPoseTransfer:
|
||||
PoseHandler();
|
||||
break;
|
||||
}
|
||||
GUILayout.Space(20);
|
||||
|
||||
// CreatePose
|
||||
if (GUILayout.Button("Pose to HumanPoseClip"))
|
||||
{
|
||||
var path = EditorUtility.SaveFilePanel(
|
||||
"Save humanpose",
|
||||
Application.dataPath,
|
||||
string.Format("{0}.pose.asset", serializedObject.targetObject.name),
|
||||
"asset");
|
||||
var assetPath = ToAssetPath(path);
|
||||
if (!string.IsNullOrEmpty(path))
|
||||
{
|
||||
var pose = ((HumanPoseTransfer)serializedObject.targetObject).CreatePose();
|
||||
|
||||
var clip = ScriptableObject.CreateInstance<HumanPoseClip>();
|
||||
clip.ApplyPose(ref pose);
|
||||
|
||||
AssetDatabase.CreateAsset(clip, assetPath);
|
||||
Selection.activeObject = clip;
|
||||
}
|
||||
}
|
||||
|
||||
// CreatePose
|
||||
if (GUILayout.Button("Pose to AnimationClip"))
|
||||
{
|
||||
var path = EditorUtility.SaveFilePanel(
|
||||
"Save animnationClip",
|
||||
Application.dataPath,
|
||||
string.Format("{0}.pose.anim", serializedObject.targetObject.name),
|
||||
"anim");
|
||||
var assetPath = ToAssetPath(path);
|
||||
if (!string.IsNullOrEmpty(path))
|
||||
{
|
||||
var pose = ((HumanPoseTransfer)serializedObject.targetObject).CreatePose();
|
||||
var clip = AnimationClipUtility.CreateAnimationClipFromHumanPose(pose);
|
||||
AssetDatabase.CreateAsset(clip, assetPath);
|
||||
Selection.activeObject = clip;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public static string ToAssetPath(string src)
|
||||
{
|
||||
src = src.Replace("\\", "/");
|
||||
var basePath = Path.GetFullPath(Application.dataPath + "/..").Replace("\\", "/");
|
||||
if (!src.StartsWith(basePath))
|
||||
{
|
||||
return null;
|
||||
}
|
||||
return src.Substring(basePath.Length + 1);
|
||||
}
|
||||
|
||||
void PoseClipInspector()
|
||||
{
|
||||
var old = (HumanPoseClip)m_clipProp.objectReferenceValue;
|
||||
EditorGUILayout.PropertyField(m_clipProp);
|
||||
serializedObject.ApplyModifiedProperties();
|
||||
|
||||
var _target = (HumanPoseTransfer)target;
|
||||
if (_target.PoseClip != old)
|
||||
{
|
||||
//Debug.Log("clip != old");
|
||||
if (_target.PoseClip != null)
|
||||
{
|
||||
var pose = _target.PoseClip.GetPose();
|
||||
_target.SetPose(pose);
|
||||
}
|
||||
}
|
||||
|
||||
#if false
|
||||
if (_target.PoseClip != null)
|
||||
{
|
||||
if (GUILayout.Button("Apply PoseClip"))
|
||||
{
|
||||
Debug.Log("apply");
|
||||
var pose = default(HumanPose);
|
||||
_target.PoseClip.GetPose(out pose);
|
||||
_target.SetPose(pose);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
void PoseHandler()
|
||||
{
|
||||
EditorGUILayout.PropertyField(m_transferProp);
|
||||
serializedObject.ApplyModifiedProperties();
|
||||
}
|
||||
}
|
||||
}
|
||||
using System;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using UnityEditor;
|
||||
using UnityEngine;
|
||||
|
||||
|
||||
namespace UniHumanoid
|
||||
{
|
||||
[CustomEditor(typeof(HumanPoseTransfer))]
|
||||
public class HumanPoseTransferEditor : Editor
|
||||
{
|
||||
//HumanPoseTransfer m_target;
|
||||
SerializedProperty m_avatarProp;
|
||||
SerializedProperty m_typeProp;
|
||||
SerializedProperty m_clipProp;
|
||||
SerializedProperty m_transferProp;
|
||||
|
||||
static string[] SOURCE_TYPES = ((HumanPoseTransfer.HumanPoseTransferSourceType[])
|
||||
Enum.GetValues(typeof(HumanPoseTransfer.HumanPoseTransferSourceType)))
|
||||
.Select(x => x.ToString())
|
||||
.ToArray();
|
||||
|
||||
private void OnEnable()
|
||||
{
|
||||
//m_target = (HumanPoseTransfer)target;
|
||||
m_typeProp = serializedObject.FindProperty("SourceType");
|
||||
m_clipProp = serializedObject.FindProperty("PoseClip");
|
||||
m_avatarProp = serializedObject.FindProperty("Avatar");
|
||||
m_transferProp = serializedObject.FindProperty("Source");
|
||||
}
|
||||
|
||||
public override void OnInspectorGUI()
|
||||
{
|
||||
//base.OnInspectorGUI();
|
||||
serializedObject.Update();
|
||||
|
||||
EditorGUILayout.PropertyField(m_avatarProp);
|
||||
|
||||
/*
|
||||
m_typeProp.intValue =
|
||||
GUILayout.Toolbar(m_typeProp.intValue, SOURCE_TYPES);
|
||||
*/
|
||||
m_typeProp.intValue =
|
||||
EditorGUILayout.Popup("SourceType", m_typeProp.intValue, SOURCE_TYPES);
|
||||
|
||||
switch ((HumanPoseTransfer.HumanPoseTransferSourceType)m_typeProp.intValue)
|
||||
{
|
||||
case HumanPoseTransfer.HumanPoseTransferSourceType.None:
|
||||
serializedObject.ApplyModifiedProperties();
|
||||
break;
|
||||
|
||||
case HumanPoseTransfer.HumanPoseTransferSourceType.HumanPoseClip:
|
||||
PoseClipInspector();
|
||||
break;
|
||||
|
||||
case HumanPoseTransfer.HumanPoseTransferSourceType.HumanPoseTransfer:
|
||||
PoseHandler();
|
||||
break;
|
||||
}
|
||||
GUILayout.Space(20);
|
||||
|
||||
// CreatePose
|
||||
if (GUILayout.Button("Pose to HumanPoseClip"))
|
||||
{
|
||||
var path = EditorUtility.SaveFilePanel(
|
||||
"Save humanpose",
|
||||
Application.dataPath,
|
||||
string.Format("{0}.pose.asset", serializedObject.targetObject.name),
|
||||
"asset");
|
||||
var assetPath = ToAssetPath(path);
|
||||
if (!string.IsNullOrEmpty(path))
|
||||
{
|
||||
var pose = ((HumanPoseTransfer)serializedObject.targetObject).CreatePose();
|
||||
|
||||
var clip = ScriptableObject.CreateInstance<HumanPoseClip>();
|
||||
clip.ApplyPose(ref pose);
|
||||
|
||||
AssetDatabase.CreateAsset(clip, assetPath);
|
||||
Selection.activeObject = clip;
|
||||
}
|
||||
}
|
||||
|
||||
// CreatePose
|
||||
if (GUILayout.Button("Pose to AnimationClip"))
|
||||
{
|
||||
var path = EditorUtility.SaveFilePanel(
|
||||
"Save animnationClip",
|
||||
Application.dataPath,
|
||||
string.Format("{0}.pose.anim", serializedObject.targetObject.name),
|
||||
"anim");
|
||||
var assetPath = ToAssetPath(path);
|
||||
if (!string.IsNullOrEmpty(path))
|
||||
{
|
||||
var pose = ((HumanPoseTransfer)serializedObject.targetObject).CreatePose();
|
||||
var clip = AnimationClipUtility.CreateAnimationClipFromHumanPose(pose);
|
||||
AssetDatabase.CreateAsset(clip, assetPath);
|
||||
Selection.activeObject = clip;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public static string ToAssetPath(string src)
|
||||
{
|
||||
src = src.Replace("\\", "/");
|
||||
var basePath = Path.GetFullPath(Application.dataPath + "/..").Replace("\\", "/");
|
||||
if (!src.StartsWith(basePath))
|
||||
{
|
||||
return null;
|
||||
}
|
||||
return src.Substring(basePath.Length + 1);
|
||||
}
|
||||
|
||||
void PoseClipInspector()
|
||||
{
|
||||
var old = (HumanPoseClip)m_clipProp.objectReferenceValue;
|
||||
EditorGUILayout.PropertyField(m_clipProp);
|
||||
serializedObject.ApplyModifiedProperties();
|
||||
|
||||
var _target = (HumanPoseTransfer)target;
|
||||
if (_target.PoseClip != old)
|
||||
{
|
||||
//Debug.Log("clip != old");
|
||||
if (_target.PoseClip != null)
|
||||
{
|
||||
var pose = _target.PoseClip.GetPose();
|
||||
_target.SetPose(pose);
|
||||
}
|
||||
}
|
||||
|
||||
#if false
|
||||
if (_target.PoseClip != null)
|
||||
{
|
||||
if (GUILayout.Button("Apply PoseClip"))
|
||||
{
|
||||
Debug.Log("apply");
|
||||
var pose = default(HumanPose);
|
||||
_target.PoseClip.GetPose(out pose);
|
||||
_target.SetPose(pose);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
void PoseHandler()
|
||||
{
|
||||
EditorGUILayout.PropertyField(m_transferProp);
|
||||
serializedObject.ApplyModifiedProperties();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,36 +1,36 @@
|
||||
using System;
|
||||
using System.IO;
|
||||
using UnityEditor;
|
||||
using UnityEngine;
|
||||
|
||||
|
||||
namespace UniHumanoid
|
||||
{
|
||||
public class bvhAssetPostprocessor : AssetPostprocessor
|
||||
{
|
||||
static void OnPostprocessAllAssets(string[] importedAssets, string[] deletedAssets, string[] movedAssets, string[] movedFromAssetPaths)
|
||||
{
|
||||
foreach (string path in importedAssets)
|
||||
{
|
||||
var ext = Path.GetExtension(path).ToLower();
|
||||
if (ext == ".bvh")
|
||||
{
|
||||
Debug.LogFormat("ImportBvh: {0}", path);
|
||||
var context = new BvhImporterContext();
|
||||
try
|
||||
{
|
||||
context.Parse(path);
|
||||
context.Load();
|
||||
context.SaveAsAsset();
|
||||
context.Destroy(false);
|
||||
}
|
||||
catch(Exception ex)
|
||||
{
|
||||
Debug.LogError(ex);
|
||||
context.Destroy(true);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
using System;
|
||||
using System.IO;
|
||||
using UnityEditor;
|
||||
using UnityEngine;
|
||||
|
||||
|
||||
namespace UniHumanoid
|
||||
{
|
||||
public class bvhAssetPostprocessor : AssetPostprocessor
|
||||
{
|
||||
static void OnPostprocessAllAssets(string[] importedAssets, string[] deletedAssets, string[] movedAssets, string[] movedFromAssetPaths)
|
||||
{
|
||||
foreach (string path in importedAssets)
|
||||
{
|
||||
var ext = Path.GetExtension(path).ToLower();
|
||||
if (ext == ".bvh")
|
||||
{
|
||||
Debug.LogFormat("ImportBvh: {0}", path);
|
||||
var context = new BvhImporterContext();
|
||||
try
|
||||
{
|
||||
context.Parse(path);
|
||||
context.Load();
|
||||
context.SaveAsAsset();
|
||||
context.Destroy(false);
|
||||
}
|
||||
catch(Exception ex)
|
||||
{
|
||||
Debug.LogError(ex);
|
||||
context.Destroy(true);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,444 +1,444 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
|
||||
|
||||
namespace UniHumanoid
|
||||
{
|
||||
public class BvhException : Exception
|
||||
{
|
||||
public BvhException(string msg) : base(msg) { }
|
||||
}
|
||||
|
||||
public enum Channel
|
||||
{
|
||||
Xposition,
|
||||
Yposition,
|
||||
Zposition,
|
||||
Xrotation,
|
||||
Yrotation,
|
||||
Zrotation,
|
||||
}
|
||||
public static class ChannelExtensions
|
||||
{
|
||||
public static string ToProperty(this Channel ch)
|
||||
{
|
||||
switch (ch)
|
||||
{
|
||||
case Channel.Xposition: return "localPosition.x";
|
||||
case Channel.Yposition: return "localPosition.y";
|
||||
case Channel.Zposition: return "localPosition.z";
|
||||
case Channel.Xrotation: return "localEulerAnglesBaked.x";
|
||||
case Channel.Yrotation: return "localEulerAnglesBaked.y";
|
||||
case Channel.Zrotation: return "localEulerAnglesBaked.z";
|
||||
}
|
||||
|
||||
throw new BvhException("no property for " + ch);
|
||||
}
|
||||
|
||||
public static bool IsLocation(this Channel ch)
|
||||
{
|
||||
switch (ch)
|
||||
{
|
||||
case Channel.Xposition:
|
||||
case Channel.Yposition:
|
||||
case Channel.Zposition: return true;
|
||||
case Channel.Xrotation:
|
||||
case Channel.Yrotation:
|
||||
case Channel.Zrotation: return false;
|
||||
}
|
||||
|
||||
throw new BvhException("no property for " + ch);
|
||||
}
|
||||
}
|
||||
|
||||
public struct Single3
|
||||
{
|
||||
public Single x;
|
||||
public Single y;
|
||||
public Single z;
|
||||
|
||||
public Single3(Single _x, Single _y, Single _z)
|
||||
{
|
||||
x = _x;
|
||||
y = _y;
|
||||
z = _z;
|
||||
}
|
||||
}
|
||||
|
||||
public class BvhNode
|
||||
{
|
||||
public String Name
|
||||
{
|
||||
get;
|
||||
private set;
|
||||
}
|
||||
|
||||
public Single3 Offset
|
||||
{
|
||||
get;
|
||||
private set;
|
||||
}
|
||||
|
||||
public Channel[] Channels
|
||||
{
|
||||
get;
|
||||
private set;
|
||||
}
|
||||
|
||||
public List<BvhNode> Children
|
||||
{
|
||||
get;
|
||||
private set;
|
||||
}
|
||||
|
||||
public BvhNode(string name)
|
||||
{
|
||||
Name = name;
|
||||
Children = new List<BvhNode>();
|
||||
}
|
||||
|
||||
public virtual void Parse(StringReader r)
|
||||
{
|
||||
Offset = ParseOffset(r.ReadLine());
|
||||
|
||||
Channels = ParseChannel(r.ReadLine());
|
||||
}
|
||||
|
||||
static Single3 ParseOffset(string line)
|
||||
{
|
||||
var splited = line.Trim().Split();
|
||||
if (splited[0] != "OFFSET")
|
||||
{
|
||||
throw new BvhException("OFFSET is not found");
|
||||
}
|
||||
|
||||
var offset = splited.Skip(1).Where(x => !string.IsNullOrEmpty(x)).Select(x => float.Parse(x)).ToArray();
|
||||
return new Single3(offset[0], offset[1], offset[2]);
|
||||
}
|
||||
|
||||
static Channel[] ParseChannel(string line)
|
||||
{
|
||||
var splited = line.Trim().Split();
|
||||
if (splited[0] != "CHANNELS")
|
||||
{
|
||||
throw new BvhException("CHANNELS is not found");
|
||||
}
|
||||
var count = int.Parse(splited[1]);
|
||||
if (count + 2 != splited.Length)
|
||||
{
|
||||
throw new BvhException("channel count is not match with splited count");
|
||||
}
|
||||
return splited.Skip(2).Select(x => (Channel)Enum.Parse(typeof(Channel), x)).ToArray();
|
||||
}
|
||||
|
||||
public IEnumerable<BvhNode> Traverse()
|
||||
{
|
||||
yield return this;
|
||||
|
||||
foreach (var child in Children)
|
||||
{
|
||||
foreach (var descentant in child.Traverse())
|
||||
{
|
||||
yield return descentant;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public class EndSite : BvhNode
|
||||
{
|
||||
public EndSite(): base("")
|
||||
{
|
||||
}
|
||||
|
||||
public override void Parse(StringReader r)
|
||||
{
|
||||
r.ReadLine(); // offset
|
||||
}
|
||||
}
|
||||
|
||||
public class ChannelCurve
|
||||
{
|
||||
public float[] Keys
|
||||
{
|
||||
get;
|
||||
private set;
|
||||
}
|
||||
|
||||
public ChannelCurve(int frameCount)
|
||||
{
|
||||
Keys = new float[frameCount];
|
||||
}
|
||||
|
||||
public void SetKey(int frame, float value)
|
||||
{
|
||||
Keys[frame] = value;
|
||||
}
|
||||
}
|
||||
|
||||
public class Bvh
|
||||
{
|
||||
public BvhNode Root
|
||||
{
|
||||
get;
|
||||
private set;
|
||||
}
|
||||
|
||||
public TimeSpan FrameTime
|
||||
{
|
||||
get;
|
||||
private set;
|
||||
}
|
||||
|
||||
public ChannelCurve[] Channels
|
||||
{
|
||||
get;
|
||||
private set;
|
||||
}
|
||||
|
||||
int m_frames;
|
||||
public int FrameCount
|
||||
{
|
||||
get { return m_frames; }
|
||||
}
|
||||
|
||||
public struct PathWithProperty
|
||||
{
|
||||
public string Path;
|
||||
public string Property;
|
||||
public bool IsLocation;
|
||||
}
|
||||
|
||||
public bool TryGetPathWithPropertyFromChannel(ChannelCurve channel, out PathWithProperty pathWithProp)
|
||||
{
|
||||
var index = Channels.ToList().IndexOf(channel);
|
||||
if (index == -1)
|
||||
{
|
||||
pathWithProp = default(PathWithProperty);
|
||||
return false;
|
||||
}
|
||||
|
||||
foreach(var node in Root.Traverse())
|
||||
{
|
||||
for(int i=0; i<node.Channels.Length; ++i, --index)
|
||||
{
|
||||
if (index == 0)
|
||||
{
|
||||
pathWithProp = new PathWithProperty
|
||||
{
|
||||
Path=GetPath(node),
|
||||
Property=node.Channels[i].ToProperty(),
|
||||
IsLocation=node.Channels[i].IsLocation(),
|
||||
};
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
throw new BvhException("channel is not found");
|
||||
}
|
||||
|
||||
public string GetPath(BvhNode node)
|
||||
{
|
||||
var list = new List<string>() { node.Name };
|
||||
|
||||
var current = node;
|
||||
while (current!=null)
|
||||
{
|
||||
current = GetParent(current);
|
||||
if (current != null)
|
||||
{
|
||||
list.Insert(0, current.Name);
|
||||
}
|
||||
}
|
||||
|
||||
return String.Join("/", list.ToArray());
|
||||
}
|
||||
|
||||
BvhNode GetParent(BvhNode node)
|
||||
{
|
||||
foreach(var x in Root.Traverse())
|
||||
{
|
||||
if (x.Children.Contains(node))
|
||||
{
|
||||
return x;
|
||||
}
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
public ChannelCurve GetChannel(BvhNode target, Channel channel)
|
||||
{
|
||||
var index = 0;
|
||||
foreach (var node in Root.Traverse())
|
||||
{
|
||||
for (int i = 0; i < node.Channels.Length; ++i, ++index)
|
||||
{
|
||||
if(node==target && node.Channels[i] == channel)
|
||||
{
|
||||
return Channels[index];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
throw new BvhException("channel is not found");
|
||||
}
|
||||
|
||||
public override string ToString()
|
||||
{
|
||||
return string.Format("{0}nodes, {1}channels, {2}frames, {3:0.00}seconds"
|
||||
, Root.Traverse().Count()
|
||||
, Channels.Length
|
||||
, m_frames
|
||||
, m_frames * FrameTime.TotalSeconds);
|
||||
}
|
||||
|
||||
public Bvh(BvhNode root, int frames, float seconds)
|
||||
{
|
||||
Root = root;
|
||||
FrameTime = TimeSpan.FromSeconds(seconds);
|
||||
m_frames = frames;
|
||||
var channelCount = Root.Traverse()
|
||||
.Where(x => x.Channels!=null)
|
||||
.Select(x => x.Channels.Length)
|
||||
.Sum();
|
||||
Channels = Enumerable.Range(0, channelCount)
|
||||
.Select(x => new ChannelCurve(frames))
|
||||
.ToArray()
|
||||
;
|
||||
}
|
||||
|
||||
public void ParseFrame(int frame, string line)
|
||||
{
|
||||
var splited = line.Trim().Split().Where(x => !string.IsNullOrEmpty(x)).ToArray();
|
||||
if (splited.Length != Channels.Length)
|
||||
{
|
||||
throw new BvhException("frame key count is not match channel count");
|
||||
}
|
||||
for(int i=0; i<Channels.Length; ++i)
|
||||
{
|
||||
Channels[i].SetKey(frame, float.Parse(splited[i]));
|
||||
}
|
||||
}
|
||||
|
||||
public static Bvh Parse(string src)
|
||||
{
|
||||
using (var r = new StringReader(src))
|
||||
{
|
||||
if (r.ReadLine() != "HIERARCHY")
|
||||
{
|
||||
throw new BvhException("not start with HIERARCHY");
|
||||
}
|
||||
|
||||
var root = ParseNode(r);
|
||||
if (root == null)
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
var frames = 0;
|
||||
var frameTime = 0.0f;
|
||||
if (r.ReadLine() == "MOTION")
|
||||
{
|
||||
var frameSplited = r.ReadLine().Split(':');
|
||||
if (frameSplited[0] != "Frames")
|
||||
{
|
||||
throw new BvhException("Frames is not found");
|
||||
}
|
||||
frames = int.Parse(frameSplited[1]);
|
||||
|
||||
var frameTimeSplited = r.ReadLine().Split(':');
|
||||
if (frameTimeSplited[0] != "Frame Time")
|
||||
{
|
||||
throw new BvhException("Frame Time is not found");
|
||||
}
|
||||
frameTime = float.Parse(frameTimeSplited[1]);
|
||||
}
|
||||
|
||||
var bvh = new Bvh(root, frames, frameTime);
|
||||
|
||||
for(int i=0; i<frames; ++i)
|
||||
{
|
||||
var line = r.ReadLine();
|
||||
bvh.ParseFrame(i, line);
|
||||
}
|
||||
|
||||
return bvh;
|
||||
}
|
||||
}
|
||||
|
||||
static BvhNode ParseNode(StringReader r, int level = 0)
|
||||
{
|
||||
var firstline = r.ReadLine().Trim();
|
||||
var splited = firstline.Split();
|
||||
if (splited.Length != 2)
|
||||
{
|
||||
if (splited.Length == 1)
|
||||
{
|
||||
if(splited[0] == "}")
|
||||
{
|
||||
return null;
|
||||
}
|
||||
}
|
||||
throw new BvhException(String.Format("splited to {0}({1})", splited.Length, firstline));
|
||||
}
|
||||
|
||||
BvhNode node = null;
|
||||
if (splited[0] == "ROOT")
|
||||
{
|
||||
if (level != 0)
|
||||
{
|
||||
throw new BvhException("nested ROOT");
|
||||
}
|
||||
node = new BvhNode(splited[1]);
|
||||
}
|
||||
else if (splited[0] == "JOINT")
|
||||
{
|
||||
if (level == 0)
|
||||
{
|
||||
throw new BvhException("should ROOT, but JOINT");
|
||||
}
|
||||
node = new BvhNode(splited[1]);
|
||||
}
|
||||
else if (splited[0] == "End")
|
||||
{
|
||||
if (level == 0)
|
||||
{
|
||||
throw new BvhException("End in level 0");
|
||||
}
|
||||
node = new EndSite();
|
||||
}
|
||||
else
|
||||
{
|
||||
throw new BvhException("unknown type: " + splited[0]);
|
||||
}
|
||||
|
||||
if(r.ReadLine().Trim() != "{")
|
||||
{
|
||||
throw new BvhException("'{' is not found");
|
||||
}
|
||||
|
||||
node.Parse(r);
|
||||
|
||||
// child nodes
|
||||
while (true)
|
||||
{
|
||||
var child = ParseNode(r, level + 1);
|
||||
if (child == null)
|
||||
{
|
||||
break;
|
||||
}
|
||||
|
||||
if(!(child is EndSite))
|
||||
{
|
||||
node.Children.Add(child);
|
||||
}
|
||||
}
|
||||
|
||||
return node;
|
||||
}
|
||||
}
|
||||
}
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
|
||||
|
||||
namespace UniHumanoid
|
||||
{
|
||||
public class BvhException : Exception
|
||||
{
|
||||
public BvhException(string msg) : base(msg) { }
|
||||
}
|
||||
|
||||
public enum Channel
|
||||
{
|
||||
Xposition,
|
||||
Yposition,
|
||||
Zposition,
|
||||
Xrotation,
|
||||
Yrotation,
|
||||
Zrotation,
|
||||
}
|
||||
public static class ChannelExtensions
|
||||
{
|
||||
public static string ToProperty(this Channel ch)
|
||||
{
|
||||
switch (ch)
|
||||
{
|
||||
case Channel.Xposition: return "localPosition.x";
|
||||
case Channel.Yposition: return "localPosition.y";
|
||||
case Channel.Zposition: return "localPosition.z";
|
||||
case Channel.Xrotation: return "localEulerAnglesBaked.x";
|
||||
case Channel.Yrotation: return "localEulerAnglesBaked.y";
|
||||
case Channel.Zrotation: return "localEulerAnglesBaked.z";
|
||||
}
|
||||
|
||||
throw new BvhException("no property for " + ch);
|
||||
}
|
||||
|
||||
public static bool IsLocation(this Channel ch)
|
||||
{
|
||||
switch (ch)
|
||||
{
|
||||
case Channel.Xposition:
|
||||
case Channel.Yposition:
|
||||
case Channel.Zposition: return true;
|
||||
case Channel.Xrotation:
|
||||
case Channel.Yrotation:
|
||||
case Channel.Zrotation: return false;
|
||||
}
|
||||
|
||||
throw new BvhException("no property for " + ch);
|
||||
}
|
||||
}
|
||||
|
||||
public struct Single3
|
||||
{
|
||||
public Single x;
|
||||
public Single y;
|
||||
public Single z;
|
||||
|
||||
public Single3(Single _x, Single _y, Single _z)
|
||||
{
|
||||
x = _x;
|
||||
y = _y;
|
||||
z = _z;
|
||||
}
|
||||
}
|
||||
|
||||
public class BvhNode
|
||||
{
|
||||
public String Name
|
||||
{
|
||||
get;
|
||||
private set;
|
||||
}
|
||||
|
||||
public Single3 Offset
|
||||
{
|
||||
get;
|
||||
private set;
|
||||
}
|
||||
|
||||
public Channel[] Channels
|
||||
{
|
||||
get;
|
||||
private set;
|
||||
}
|
||||
|
||||
public List<BvhNode> Children
|
||||
{
|
||||
get;
|
||||
private set;
|
||||
}
|
||||
|
||||
public BvhNode(string name)
|
||||
{
|
||||
Name = name;
|
||||
Children = new List<BvhNode>();
|
||||
}
|
||||
|
||||
public virtual void Parse(StringReader r)
|
||||
{
|
||||
Offset = ParseOffset(r.ReadLine());
|
||||
|
||||
Channels = ParseChannel(r.ReadLine());
|
||||
}
|
||||
|
||||
static Single3 ParseOffset(string line)
|
||||
{
|
||||
var splited = line.Trim().Split();
|
||||
if (splited[0] != "OFFSET")
|
||||
{
|
||||
throw new BvhException("OFFSET is not found");
|
||||
}
|
||||
|
||||
var offset = splited.Skip(1).Where(x => !string.IsNullOrEmpty(x)).Select(x => float.Parse(x)).ToArray();
|
||||
return new Single3(offset[0], offset[1], offset[2]);
|
||||
}
|
||||
|
||||
static Channel[] ParseChannel(string line)
|
||||
{
|
||||
var splited = line.Trim().Split();
|
||||
if (splited[0] != "CHANNELS")
|
||||
{
|
||||
throw new BvhException("CHANNELS is not found");
|
||||
}
|
||||
var count = int.Parse(splited[1]);
|
||||
if (count + 2 != splited.Length)
|
||||
{
|
||||
throw new BvhException("channel count is not match with splited count");
|
||||
}
|
||||
return splited.Skip(2).Select(x => (Channel)Enum.Parse(typeof(Channel), x)).ToArray();
|
||||
}
|
||||
|
||||
public IEnumerable<BvhNode> Traverse()
|
||||
{
|
||||
yield return this;
|
||||
|
||||
foreach (var child in Children)
|
||||
{
|
||||
foreach (var descentant in child.Traverse())
|
||||
{
|
||||
yield return descentant;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public class EndSite : BvhNode
|
||||
{
|
||||
public EndSite(): base("")
|
||||
{
|
||||
}
|
||||
|
||||
public override void Parse(StringReader r)
|
||||
{
|
||||
r.ReadLine(); // offset
|
||||
}
|
||||
}
|
||||
|
||||
public class ChannelCurve
|
||||
{
|
||||
public float[] Keys
|
||||
{
|
||||
get;
|
||||
private set;
|
||||
}
|
||||
|
||||
public ChannelCurve(int frameCount)
|
||||
{
|
||||
Keys = new float[frameCount];
|
||||
}
|
||||
|
||||
public void SetKey(int frame, float value)
|
||||
{
|
||||
Keys[frame] = value;
|
||||
}
|
||||
}
|
||||
|
||||
public class Bvh
|
||||
{
|
||||
public BvhNode Root
|
||||
{
|
||||
get;
|
||||
private set;
|
||||
}
|
||||
|
||||
public TimeSpan FrameTime
|
||||
{
|
||||
get;
|
||||
private set;
|
||||
}
|
||||
|
||||
public ChannelCurve[] Channels
|
||||
{
|
||||
get;
|
||||
private set;
|
||||
}
|
||||
|
||||
int m_frames;
|
||||
public int FrameCount
|
||||
{
|
||||
get { return m_frames; }
|
||||
}
|
||||
|
||||
public struct PathWithProperty
|
||||
{
|
||||
public string Path;
|
||||
public string Property;
|
||||
public bool IsLocation;
|
||||
}
|
||||
|
||||
public bool TryGetPathWithPropertyFromChannel(ChannelCurve channel, out PathWithProperty pathWithProp)
|
||||
{
|
||||
var index = Channels.ToList().IndexOf(channel);
|
||||
if (index == -1)
|
||||
{
|
||||
pathWithProp = default(PathWithProperty);
|
||||
return false;
|
||||
}
|
||||
|
||||
foreach(var node in Root.Traverse())
|
||||
{
|
||||
for(int i=0; i<node.Channels.Length; ++i, --index)
|
||||
{
|
||||
if (index == 0)
|
||||
{
|
||||
pathWithProp = new PathWithProperty
|
||||
{
|
||||
Path=GetPath(node),
|
||||
Property=node.Channels[i].ToProperty(),
|
||||
IsLocation=node.Channels[i].IsLocation(),
|
||||
};
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
throw new BvhException("channel is not found");
|
||||
}
|
||||
|
||||
public string GetPath(BvhNode node)
|
||||
{
|
||||
var list = new List<string>() { node.Name };
|
||||
|
||||
var current = node;
|
||||
while (current!=null)
|
||||
{
|
||||
current = GetParent(current);
|
||||
if (current != null)
|
||||
{
|
||||
list.Insert(0, current.Name);
|
||||
}
|
||||
}
|
||||
|
||||
return String.Join("/", list.ToArray());
|
||||
}
|
||||
|
||||
BvhNode GetParent(BvhNode node)
|
||||
{
|
||||
foreach(var x in Root.Traverse())
|
||||
{
|
||||
if (x.Children.Contains(node))
|
||||
{
|
||||
return x;
|
||||
}
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
public ChannelCurve GetChannel(BvhNode target, Channel channel)
|
||||
{
|
||||
var index = 0;
|
||||
foreach (var node in Root.Traverse())
|
||||
{
|
||||
for (int i = 0; i < node.Channels.Length; ++i, ++index)
|
||||
{
|
||||
if(node==target && node.Channels[i] == channel)
|
||||
{
|
||||
return Channels[index];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
throw new BvhException("channel is not found");
|
||||
}
|
||||
|
||||
public override string ToString()
|
||||
{
|
||||
return string.Format("{0}nodes, {1}channels, {2}frames, {3:0.00}seconds"
|
||||
, Root.Traverse().Count()
|
||||
, Channels.Length
|
||||
, m_frames
|
||||
, m_frames * FrameTime.TotalSeconds);
|
||||
}
|
||||
|
||||
public Bvh(BvhNode root, int frames, float seconds)
|
||||
{
|
||||
Root = root;
|
||||
FrameTime = TimeSpan.FromSeconds(seconds);
|
||||
m_frames = frames;
|
||||
var channelCount = Root.Traverse()
|
||||
.Where(x => x.Channels!=null)
|
||||
.Select(x => x.Channels.Length)
|
||||
.Sum();
|
||||
Channels = Enumerable.Range(0, channelCount)
|
||||
.Select(x => new ChannelCurve(frames))
|
||||
.ToArray()
|
||||
;
|
||||
}
|
||||
|
||||
public void ParseFrame(int frame, string line)
|
||||
{
|
||||
var splited = line.Trim().Split().Where(x => !string.IsNullOrEmpty(x)).ToArray();
|
||||
if (splited.Length != Channels.Length)
|
||||
{
|
||||
throw new BvhException("frame key count is not match channel count");
|
||||
}
|
||||
for(int i=0; i<Channels.Length; ++i)
|
||||
{
|
||||
Channels[i].SetKey(frame, float.Parse(splited[i]));
|
||||
}
|
||||
}
|
||||
|
||||
public static Bvh Parse(string src)
|
||||
{
|
||||
using (var r = new StringReader(src))
|
||||
{
|
||||
if (r.ReadLine() != "HIERARCHY")
|
||||
{
|
||||
throw new BvhException("not start with HIERARCHY");
|
||||
}
|
||||
|
||||
var root = ParseNode(r);
|
||||
if (root == null)
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
var frames = 0;
|
||||
var frameTime = 0.0f;
|
||||
if (r.ReadLine() == "MOTION")
|
||||
{
|
||||
var frameSplited = r.ReadLine().Split(':');
|
||||
if (frameSplited[0] != "Frames")
|
||||
{
|
||||
throw new BvhException("Frames is not found");
|
||||
}
|
||||
frames = int.Parse(frameSplited[1]);
|
||||
|
||||
var frameTimeSplited = r.ReadLine().Split(':');
|
||||
if (frameTimeSplited[0] != "Frame Time")
|
||||
{
|
||||
throw new BvhException("Frame Time is not found");
|
||||
}
|
||||
frameTime = float.Parse(frameTimeSplited[1]);
|
||||
}
|
||||
|
||||
var bvh = new Bvh(root, frames, frameTime);
|
||||
|
||||
for(int i=0; i<frames; ++i)
|
||||
{
|
||||
var line = r.ReadLine();
|
||||
bvh.ParseFrame(i, line);
|
||||
}
|
||||
|
||||
return bvh;
|
||||
}
|
||||
}
|
||||
|
||||
static BvhNode ParseNode(StringReader r, int level = 0)
|
||||
{
|
||||
var firstline = r.ReadLine().Trim();
|
||||
var splited = firstline.Split();
|
||||
if (splited.Length != 2)
|
||||
{
|
||||
if (splited.Length == 1)
|
||||
{
|
||||
if(splited[0] == "}")
|
||||
{
|
||||
return null;
|
||||
}
|
||||
}
|
||||
throw new BvhException(String.Format("splited to {0}({1})", splited.Length, firstline));
|
||||
}
|
||||
|
||||
BvhNode node = null;
|
||||
if (splited[0] == "ROOT")
|
||||
{
|
||||
if (level != 0)
|
||||
{
|
||||
throw new BvhException("nested ROOT");
|
||||
}
|
||||
node = new BvhNode(splited[1]);
|
||||
}
|
||||
else if (splited[0] == "JOINT")
|
||||
{
|
||||
if (level == 0)
|
||||
{
|
||||
throw new BvhException("should ROOT, but JOINT");
|
||||
}
|
||||
node = new BvhNode(splited[1]);
|
||||
}
|
||||
else if (splited[0] == "End")
|
||||
{
|
||||
if (level == 0)
|
||||
{
|
||||
throw new BvhException("End in level 0");
|
||||
}
|
||||
node = new EndSite();
|
||||
}
|
||||
else
|
||||
{
|
||||
throw new BvhException("unknown type: " + splited[0]);
|
||||
}
|
||||
|
||||
if(r.ReadLine().Trim() != "{")
|
||||
{
|
||||
throw new BvhException("'{' is not found");
|
||||
}
|
||||
|
||||
node.Parse(r);
|
||||
|
||||
// child nodes
|
||||
while (true)
|
||||
{
|
||||
var child = ParseNode(r, level + 1);
|
||||
if (child == null)
|
||||
{
|
||||
break;
|
||||
}
|
||||
|
||||
if(!(child is EndSite))
|
||||
{
|
||||
node.Children.Add(child);
|
||||
}
|
||||
}
|
||||
|
||||
return node;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,33 +1,33 @@
|
||||
using UnityEngine;
|
||||
|
||||
|
||||
namespace UniHumanoid
|
||||
{
|
||||
public class HumanPoseClip : ScriptableObject
|
||||
{
|
||||
public const string TPoseResourcePath = "T-Pose.pose";
|
||||
|
||||
public Vector3 bodyPosition;
|
||||
|
||||
public Quaternion bodyRotation;
|
||||
|
||||
public float[] muscles;
|
||||
|
||||
public HumanPose GetPose()
|
||||
{
|
||||
return new HumanPose
|
||||
{
|
||||
bodyPosition = bodyPosition,
|
||||
bodyRotation = bodyRotation,
|
||||
muscles = muscles
|
||||
};
|
||||
}
|
||||
|
||||
public void ApplyPose(ref HumanPose pose)
|
||||
{
|
||||
bodyPosition = pose.bodyPosition;
|
||||
bodyRotation = pose.bodyRotation;
|
||||
muscles = (float[])pose.muscles.Clone();
|
||||
}
|
||||
}
|
||||
}
|
||||
using UnityEngine;
|
||||
|
||||
|
||||
namespace UniHumanoid
|
||||
{
|
||||
public class HumanPoseClip : ScriptableObject
|
||||
{
|
||||
public const string TPoseResourcePath = "T-Pose.pose";
|
||||
|
||||
public Vector3 bodyPosition;
|
||||
|
||||
public Quaternion bodyRotation;
|
||||
|
||||
public float[] muscles;
|
||||
|
||||
public HumanPose GetPose()
|
||||
{
|
||||
return new HumanPose
|
||||
{
|
||||
bodyPosition = bodyPosition,
|
||||
bodyRotation = bodyRotation,
|
||||
muscles = muscles
|
||||
};
|
||||
}
|
||||
|
||||
public void ApplyPose(ref HumanPose pose)
|
||||
{
|
||||
bodyPosition = pose.bodyPosition;
|
||||
bodyRotation = pose.bodyRotation;
|
||||
muscles = (float[])pose.muscles.Clone();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,143 +1,143 @@
|
||||
using UnityEngine;
|
||||
|
||||
|
||||
namespace UniHumanoid
|
||||
{
|
||||
public class HumanPoseTransfer : MonoBehaviour
|
||||
{
|
||||
public enum HumanPoseTransferSourceType
|
||||
{
|
||||
None,
|
||||
HumanPoseTransfer,
|
||||
HumanPoseClip,
|
||||
}
|
||||
|
||||
[SerializeField]
|
||||
public HumanPoseTransferSourceType SourceType;
|
||||
|
||||
[SerializeField]
|
||||
public Avatar Avatar;
|
||||
|
||||
#region Standalone
|
||||
public HumanPose CreatePose()
|
||||
{
|
||||
var handler = new HumanPoseHandler(Avatar, transform);
|
||||
var pose = default(HumanPose);
|
||||
handler.GetHumanPose(ref pose);
|
||||
return pose;
|
||||
}
|
||||
public void SetPose(HumanPose pose)
|
||||
{
|
||||
SetPose(Avatar, transform, pose);
|
||||
}
|
||||
public static void SetPose(Avatar avatar, Transform transform, HumanPose pose)
|
||||
{
|
||||
var handler = new HumanPoseHandler(avatar, transform);
|
||||
handler.SetHumanPose(ref pose);
|
||||
}
|
||||
public static void SetTPose(Avatar avatar, Transform transform)
|
||||
{
|
||||
var humanPoseClip = Resources.Load<HumanPoseClip>(HumanPoseClip.TPoseResourcePath);
|
||||
var pose = humanPoseClip.GetPose();
|
||||
HumanPoseTransfer.SetPose(avatar, transform, pose);
|
||||
}
|
||||
#endregion
|
||||
|
||||
private void Reset()
|
||||
{
|
||||
var animator = GetComponent<Animator>();
|
||||
if (animator != null)
|
||||
{
|
||||
Avatar = animator.avatar;
|
||||
}
|
||||
}
|
||||
|
||||
[SerializeField]
|
||||
public HumanPoseTransfer Source;
|
||||
|
||||
[SerializeField]
|
||||
public HumanPoseClip PoseClip;
|
||||
|
||||
[ContextMenu("Set T-Pose")]
|
||||
void SetTPose()
|
||||
{
|
||||
if (Avatar == null) return;
|
||||
SetTPose(Avatar, transform);
|
||||
}
|
||||
|
||||
HumanPoseHandler m_handler;
|
||||
public void OnEnable()
|
||||
{
|
||||
var animator = GetComponent<Animator>();
|
||||
if (animator != null)
|
||||
{
|
||||
Avatar = animator.avatar;
|
||||
}
|
||||
|
||||
Setup();
|
||||
}
|
||||
|
||||
public void Setup()
|
||||
{
|
||||
if (Avatar == null)
|
||||
{
|
||||
return;
|
||||
}
|
||||
m_handler = new HumanPoseHandler(Avatar, transform);
|
||||
}
|
||||
|
||||
HumanPose m_pose;
|
||||
|
||||
int m_lastFrameCount = -1;
|
||||
|
||||
public bool GetPose(int frameCount, ref HumanPose pose)
|
||||
{
|
||||
if (PoseClip != null)
|
||||
{
|
||||
pose = PoseClip.GetPose();
|
||||
return true;
|
||||
}
|
||||
|
||||
if (m_handler == null)
|
||||
{
|
||||
pose = m_pose;
|
||||
return false;
|
||||
}
|
||||
|
||||
if (frameCount != m_lastFrameCount)
|
||||
{
|
||||
m_handler.GetHumanPose(ref m_pose);
|
||||
m_lastFrameCount = frameCount;
|
||||
}
|
||||
pose = m_pose;
|
||||
return true;
|
||||
}
|
||||
|
||||
private void Update()
|
||||
{
|
||||
switch (SourceType)
|
||||
{
|
||||
case HumanPoseTransferSourceType.None:
|
||||
break;
|
||||
|
||||
case HumanPoseTransferSourceType.HumanPoseTransfer:
|
||||
if (Source != null && m_handler != null)
|
||||
{
|
||||
if (Source.GetPose(Time.frameCount, ref m_pose))
|
||||
{
|
||||
m_handler.SetHumanPose(ref m_pose);
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
case HumanPoseTransferSourceType.HumanPoseClip:
|
||||
if (PoseClip != null)
|
||||
{
|
||||
var pose = PoseClip.GetPose();
|
||||
m_handler.SetHumanPose(ref pose);
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
using UnityEngine;
|
||||
|
||||
|
||||
namespace UniHumanoid
|
||||
{
|
||||
public class HumanPoseTransfer : MonoBehaviour
|
||||
{
|
||||
public enum HumanPoseTransferSourceType
|
||||
{
|
||||
None,
|
||||
HumanPoseTransfer,
|
||||
HumanPoseClip,
|
||||
}
|
||||
|
||||
[SerializeField]
|
||||
public HumanPoseTransferSourceType SourceType;
|
||||
|
||||
[SerializeField]
|
||||
public Avatar Avatar;
|
||||
|
||||
#region Standalone
|
||||
public HumanPose CreatePose()
|
||||
{
|
||||
var handler = new HumanPoseHandler(Avatar, transform);
|
||||
var pose = default(HumanPose);
|
||||
handler.GetHumanPose(ref pose);
|
||||
return pose;
|
||||
}
|
||||
public void SetPose(HumanPose pose)
|
||||
{
|
||||
SetPose(Avatar, transform, pose);
|
||||
}
|
||||
public static void SetPose(Avatar avatar, Transform transform, HumanPose pose)
|
||||
{
|
||||
var handler = new HumanPoseHandler(avatar, transform);
|
||||
handler.SetHumanPose(ref pose);
|
||||
}
|
||||
public static void SetTPose(Avatar avatar, Transform transform)
|
||||
{
|
||||
var humanPoseClip = Resources.Load<HumanPoseClip>(HumanPoseClip.TPoseResourcePath);
|
||||
var pose = humanPoseClip.GetPose();
|
||||
HumanPoseTransfer.SetPose(avatar, transform, pose);
|
||||
}
|
||||
#endregion
|
||||
|
||||
private void Reset()
|
||||
{
|
||||
var animator = GetComponent<Animator>();
|
||||
if (animator != null)
|
||||
{
|
||||
Avatar = animator.avatar;
|
||||
}
|
||||
}
|
||||
|
||||
[SerializeField]
|
||||
public HumanPoseTransfer Source;
|
||||
|
||||
[SerializeField]
|
||||
public HumanPoseClip PoseClip;
|
||||
|
||||
[ContextMenu("Set T-Pose")]
|
||||
void SetTPose()
|
||||
{
|
||||
if (Avatar == null) return;
|
||||
SetTPose(Avatar, transform);
|
||||
}
|
||||
|
||||
HumanPoseHandler m_handler;
|
||||
public void OnEnable()
|
||||
{
|
||||
var animator = GetComponent<Animator>();
|
||||
if (animator != null)
|
||||
{
|
||||
Avatar = animator.avatar;
|
||||
}
|
||||
|
||||
Setup();
|
||||
}
|
||||
|
||||
public void Setup()
|
||||
{
|
||||
if (Avatar == null)
|
||||
{
|
||||
return;
|
||||
}
|
||||
m_handler = new HumanPoseHandler(Avatar, transform);
|
||||
}
|
||||
|
||||
HumanPose m_pose;
|
||||
|
||||
int m_lastFrameCount = -1;
|
||||
|
||||
public bool GetPose(int frameCount, ref HumanPose pose)
|
||||
{
|
||||
if (PoseClip != null)
|
||||
{
|
||||
pose = PoseClip.GetPose();
|
||||
return true;
|
||||
}
|
||||
|
||||
if (m_handler == null)
|
||||
{
|
||||
pose = m_pose;
|
||||
return false;
|
||||
}
|
||||
|
||||
if (frameCount != m_lastFrameCount)
|
||||
{
|
||||
m_handler.GetHumanPose(ref m_pose);
|
||||
m_lastFrameCount = frameCount;
|
||||
}
|
||||
pose = m_pose;
|
||||
return true;
|
||||
}
|
||||
|
||||
private void Update()
|
||||
{
|
||||
switch (SourceType)
|
||||
{
|
||||
case HumanPoseTransferSourceType.None:
|
||||
break;
|
||||
|
||||
case HumanPoseTransferSourceType.HumanPoseTransfer:
|
||||
if (Source != null && m_handler != null)
|
||||
{
|
||||
if (Source.GetPose(Time.frameCount, ref m_pose))
|
||||
{
|
||||
m_handler.SetHumanPose(ref m_pose);
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
case HumanPoseTransferSourceType.HumanPoseClip:
|
||||
if (PoseClip != null)
|
||||
{
|
||||
var pose = PoseClip.GetPose();
|
||||
m_handler.SetHumanPose(ref pose);
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,41 +1,41 @@
|
||||
using System.Collections.Generic;
|
||||
using UnityEngine;
|
||||
|
||||
|
||||
namespace UniHumanoid
|
||||
{
|
||||
public interface IBone
|
||||
{
|
||||
string Name { get; }
|
||||
Vector3 SkeletonLocalPosition { get; }
|
||||
IBone Parent { get; }
|
||||
IList<IBone> Children { get; }
|
||||
}
|
||||
|
||||
public static class IBoneExtensions
|
||||
{
|
||||
public static IEnumerable<IBone> Traverse(this IBone self)
|
||||
{
|
||||
yield return self;
|
||||
foreach (var child in self.Children)
|
||||
{
|
||||
foreach (var x in child.Traverse())
|
||||
{
|
||||
yield return x;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public static Vector3 CenterOfDescendant(this IBone self)
|
||||
{
|
||||
var sum = Vector3.zero;
|
||||
int i = 0;
|
||||
foreach (var x in self.Traverse())
|
||||
{
|
||||
sum += x.SkeletonLocalPosition;
|
||||
++i;
|
||||
}
|
||||
return sum / i;
|
||||
}
|
||||
}
|
||||
}
|
||||
using System.Collections.Generic;
|
||||
using UnityEngine;
|
||||
|
||||
|
||||
namespace UniHumanoid
|
||||
{
|
||||
public interface IBone
|
||||
{
|
||||
string Name { get; }
|
||||
Vector3 SkeletonLocalPosition { get; }
|
||||
IBone Parent { get; }
|
||||
IList<IBone> Children { get; }
|
||||
}
|
||||
|
||||
public static class IBoneExtensions
|
||||
{
|
||||
public static IEnumerable<IBone> Traverse(this IBone self)
|
||||
{
|
||||
yield return self;
|
||||
foreach (var child in self.Children)
|
||||
{
|
||||
foreach (var x in child.Traverse())
|
||||
{
|
||||
yield return x;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public static Vector3 CenterOfDescendant(this IBone self)
|
||||
{
|
||||
var sum = Vector3.zero;
|
||||
int i = 0;
|
||||
foreach (var x in self.Traverse())
|
||||
{
|
||||
sum += x.SkeletonLocalPosition;
|
||||
++i;
|
||||
}
|
||||
return sum / i;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,131 +1,131 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using UnityEngine;
|
||||
|
||||
|
||||
namespace UniHumanoid
|
||||
{
|
||||
public static class BvhAnimation
|
||||
{
|
||||
class CurveSet
|
||||
{
|
||||
BvhNode Node;
|
||||
Func<float, float, float, Quaternion> EulerToRotation;
|
||||
public CurveSet(BvhNode node)
|
||||
{
|
||||
Node = node;
|
||||
}
|
||||
|
||||
public ChannelCurve PositionX;
|
||||
public ChannelCurve PositionY;
|
||||
public ChannelCurve PositionZ;
|
||||
public Vector3 GetPosition(int i)
|
||||
{
|
||||
return new Vector3(
|
||||
PositionX.Keys[i],
|
||||
PositionY.Keys[i],
|
||||
PositionZ.Keys[i]);
|
||||
}
|
||||
|
||||
public ChannelCurve RotationX;
|
||||
public ChannelCurve RotationY;
|
||||
public ChannelCurve RotationZ;
|
||||
public Quaternion GetRotation(int i)
|
||||
{
|
||||
if (EulerToRotation == null)
|
||||
{
|
||||
EulerToRotation = Node.GetEulerToRotation();
|
||||
}
|
||||
return EulerToRotation(
|
||||
RotationX.Keys[i],
|
||||
RotationY.Keys[i],
|
||||
RotationZ.Keys[i]
|
||||
);
|
||||
}
|
||||
|
||||
static void AddCurve(Bvh bvh, AnimationClip clip, ChannelCurve ch, float scaling)
|
||||
{
|
||||
if (ch == null) return;
|
||||
var pathWithProp = default(Bvh.PathWithProperty);
|
||||
bvh.TryGetPathWithPropertyFromChannel(ch, out pathWithProp);
|
||||
var curve = new AnimationCurve();
|
||||
for (int i = 0; i < bvh.FrameCount; ++i)
|
||||
{
|
||||
var time = (float)(i * bvh.FrameTime.TotalSeconds);
|
||||
var value = ch.Keys[i] * scaling;
|
||||
curve.AddKey(time, value);
|
||||
}
|
||||
clip.SetCurve(pathWithProp.Path, typeof(Transform), pathWithProp.Property, curve);
|
||||
}
|
||||
|
||||
public void AddCurves(Bvh bvh, AnimationClip clip, float scaling)
|
||||
{
|
||||
AddCurve(bvh, clip, PositionX, -scaling);
|
||||
AddCurve(bvh, clip, PositionY, scaling);
|
||||
AddCurve(bvh, clip, PositionZ, scaling);
|
||||
|
||||
var pathWithProp = default(Bvh.PathWithProperty);
|
||||
bvh.TryGetPathWithPropertyFromChannel(RotationX, out pathWithProp);
|
||||
|
||||
// rotation
|
||||
var curveX = new AnimationCurve();
|
||||
var curveY = new AnimationCurve();
|
||||
var curveZ = new AnimationCurve();
|
||||
var curveW = new AnimationCurve();
|
||||
for (int i = 0; i < bvh.FrameCount; ++i)
|
||||
{
|
||||
var time = (float)(i * bvh.FrameTime.TotalSeconds);
|
||||
var q = GetRotation(i).ReverseX();
|
||||
curveX.AddKey(time, q.x);
|
||||
curveY.AddKey(time, q.y);
|
||||
curveZ.AddKey(time, q.z);
|
||||
curveW.AddKey(time, q.w);
|
||||
}
|
||||
clip.SetCurve(pathWithProp.Path, typeof(Transform), "localRotation.x", curveX);
|
||||
clip.SetCurve(pathWithProp.Path, typeof(Transform), "localRotation.y", curveY);
|
||||
clip.SetCurve(pathWithProp.Path, typeof(Transform), "localRotation.z", curveZ);
|
||||
clip.SetCurve(pathWithProp.Path, typeof(Transform), "localRotation.w", curveW);
|
||||
}
|
||||
}
|
||||
|
||||
public static AnimationClip CreateAnimationClip(Bvh bvh, float scaling)
|
||||
{
|
||||
var clip = new AnimationClip();
|
||||
clip.legacy = true;
|
||||
|
||||
var curveMap = new Dictionary<BvhNode, CurveSet>();
|
||||
|
||||
int j = 0;
|
||||
foreach (var node in bvh.Root.Traverse())
|
||||
{
|
||||
var set = new CurveSet(node);
|
||||
curveMap[node] = set;
|
||||
|
||||
for (int i = 0; i < node.Channels.Length; ++i, ++j)
|
||||
{
|
||||
var curve = bvh.Channels[j];
|
||||
switch (node.Channels[i])
|
||||
{
|
||||
case Channel.Xposition: set.PositionX = curve; break;
|
||||
case Channel.Yposition: set.PositionY = curve; break;
|
||||
case Channel.Zposition: set.PositionZ = curve; break;
|
||||
case Channel.Xrotation: set.RotationX = curve; break;
|
||||
case Channel.Yrotation: set.RotationY = curve; break;
|
||||
case Channel.Zrotation: set.RotationZ = curve; break;
|
||||
default: throw new Exception();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
foreach (var set in curveMap)
|
||||
{
|
||||
set.Value.AddCurves(bvh, clip, scaling);
|
||||
}
|
||||
|
||||
clip.EnsureQuaternionContinuity();
|
||||
|
||||
return clip;
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using UnityEngine;
|
||||
|
||||
|
||||
namespace UniHumanoid
|
||||
{
|
||||
public static class BvhAnimation
|
||||
{
|
||||
class CurveSet
|
||||
{
|
||||
BvhNode Node;
|
||||
Func<float, float, float, Quaternion> EulerToRotation;
|
||||
public CurveSet(BvhNode node)
|
||||
{
|
||||
Node = node;
|
||||
}
|
||||
|
||||
public ChannelCurve PositionX;
|
||||
public ChannelCurve PositionY;
|
||||
public ChannelCurve PositionZ;
|
||||
public Vector3 GetPosition(int i)
|
||||
{
|
||||
return new Vector3(
|
||||
PositionX.Keys[i],
|
||||
PositionY.Keys[i],
|
||||
PositionZ.Keys[i]);
|
||||
}
|
||||
|
||||
public ChannelCurve RotationX;
|
||||
public ChannelCurve RotationY;
|
||||
public ChannelCurve RotationZ;
|
||||
public Quaternion GetRotation(int i)
|
||||
{
|
||||
if (EulerToRotation == null)
|
||||
{
|
||||
EulerToRotation = Node.GetEulerToRotation();
|
||||
}
|
||||
return EulerToRotation(
|
||||
RotationX.Keys[i],
|
||||
RotationY.Keys[i],
|
||||
RotationZ.Keys[i]
|
||||
);
|
||||
}
|
||||
|
||||
static void AddCurve(Bvh bvh, AnimationClip clip, ChannelCurve ch, float scaling)
|
||||
{
|
||||
if (ch == null) return;
|
||||
var pathWithProp = default(Bvh.PathWithProperty);
|
||||
bvh.TryGetPathWithPropertyFromChannel(ch, out pathWithProp);
|
||||
var curve = new AnimationCurve();
|
||||
for (int i = 0; i < bvh.FrameCount; ++i)
|
||||
{
|
||||
var time = (float)(i * bvh.FrameTime.TotalSeconds);
|
||||
var value = ch.Keys[i] * scaling;
|
||||
curve.AddKey(time, value);
|
||||
}
|
||||
clip.SetCurve(pathWithProp.Path, typeof(Transform), pathWithProp.Property, curve);
|
||||
}
|
||||
|
||||
public void AddCurves(Bvh bvh, AnimationClip clip, float scaling)
|
||||
{
|
||||
AddCurve(bvh, clip, PositionX, -scaling);
|
||||
AddCurve(bvh, clip, PositionY, scaling);
|
||||
AddCurve(bvh, clip, PositionZ, scaling);
|
||||
|
||||
var pathWithProp = default(Bvh.PathWithProperty);
|
||||
bvh.TryGetPathWithPropertyFromChannel(RotationX, out pathWithProp);
|
||||
|
||||
// rotation
|
||||
var curveX = new AnimationCurve();
|
||||
var curveY = new AnimationCurve();
|
||||
var curveZ = new AnimationCurve();
|
||||
var curveW = new AnimationCurve();
|
||||
for (int i = 0; i < bvh.FrameCount; ++i)
|
||||
{
|
||||
var time = (float)(i * bvh.FrameTime.TotalSeconds);
|
||||
var q = GetRotation(i).ReverseX();
|
||||
curveX.AddKey(time, q.x);
|
||||
curveY.AddKey(time, q.y);
|
||||
curveZ.AddKey(time, q.z);
|
||||
curveW.AddKey(time, q.w);
|
||||
}
|
||||
clip.SetCurve(pathWithProp.Path, typeof(Transform), "localRotation.x", curveX);
|
||||
clip.SetCurve(pathWithProp.Path, typeof(Transform), "localRotation.y", curveY);
|
||||
clip.SetCurve(pathWithProp.Path, typeof(Transform), "localRotation.z", curveZ);
|
||||
clip.SetCurve(pathWithProp.Path, typeof(Transform), "localRotation.w", curveW);
|
||||
}
|
||||
}
|
||||
|
||||
public static AnimationClip CreateAnimationClip(Bvh bvh, float scaling)
|
||||
{
|
||||
var clip = new AnimationClip();
|
||||
clip.legacy = true;
|
||||
|
||||
var curveMap = new Dictionary<BvhNode, CurveSet>();
|
||||
|
||||
int j = 0;
|
||||
foreach (var node in bvh.Root.Traverse())
|
||||
{
|
||||
var set = new CurveSet(node);
|
||||
curveMap[node] = set;
|
||||
|
||||
for (int i = 0; i < node.Channels.Length; ++i, ++j)
|
||||
{
|
||||
var curve = bvh.Channels[j];
|
||||
switch (node.Channels[i])
|
||||
{
|
||||
case Channel.Xposition: set.PositionX = curve; break;
|
||||
case Channel.Yposition: set.PositionY = curve; break;
|
||||
case Channel.Zposition: set.PositionZ = curve; break;
|
||||
case Channel.Xrotation: set.RotationX = curve; break;
|
||||
case Channel.Yrotation: set.RotationY = curve; break;
|
||||
case Channel.Zrotation: set.RotationZ = curve; break;
|
||||
default: throw new Exception();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
foreach (var set in curveMap)
|
||||
{
|
||||
set.Value.AddCurves(bvh, clip, scaling);
|
||||
}
|
||||
|
||||
clip.EnsureQuaternionContinuity();
|
||||
|
||||
return clip;
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
@@ -1,15 +1,15 @@
|
||||
using System;
|
||||
|
||||
|
||||
namespace UniHumanoid
|
||||
{
|
||||
public static class BvhImporter
|
||||
{
|
||||
[Obsolete("use BvhImporter.Parse(path), then BvhImporter.Load()")]
|
||||
public static void Import(BvhImporterContext context)
|
||||
{
|
||||
context.Parse(context.Path);
|
||||
context.Load();
|
||||
}
|
||||
}
|
||||
}
|
||||
using System;
|
||||
|
||||
|
||||
namespace UniHumanoid
|
||||
{
|
||||
public static class BvhImporter
|
||||
{
|
||||
[Obsolete("use BvhImporter.Parse(path), then BvhImporter.Load()")]
|
||||
public static void Import(BvhImporterContext context)
|
||||
{
|
||||
context.Parse(context.Path);
|
||||
context.Load();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,247 +1,247 @@
|
||||
using System;
|
||||
using System.Linq;
|
||||
using System.Collections.Generic;
|
||||
using UnityEngine;
|
||||
using System.IO;
|
||||
using System.Text;
|
||||
#if UNITY_EDITOR
|
||||
using UnityEditor;
|
||||
#endif
|
||||
|
||||
|
||||
namespace UniHumanoid
|
||||
{
|
||||
[Obsolete("use BvhImporterContext")]
|
||||
public class ImporterContext: BvhImporterContext
|
||||
{
|
||||
}
|
||||
|
||||
public class BvhImporterContext
|
||||
{
|
||||
#region Source
|
||||
String m_path;
|
||||
public String Path
|
||||
{
|
||||
get { return m_path; }
|
||||
set
|
||||
{
|
||||
if (m_path == value) return;
|
||||
m_path = value;
|
||||
}
|
||||
}
|
||||
public String Source; // source
|
||||
public Bvh Bvh;
|
||||
#endregion
|
||||
|
||||
#region Imported
|
||||
public GameObject Root;
|
||||
public List<Transform> Nodes = new List<Transform>();
|
||||
public AnimationClip Animation;
|
||||
public AvatarDescription AvatarDescription;
|
||||
public Avatar Avatar;
|
||||
public Mesh Mesh;
|
||||
public Material Material;
|
||||
#endregion
|
||||
|
||||
#region Load
|
||||
[Obsolete("use Load(path)")]
|
||||
public void Parse()
|
||||
{
|
||||
Parse(Path);
|
||||
}
|
||||
|
||||
public void Parse(string path)
|
||||
{
|
||||
Path = path;
|
||||
Source = File.ReadAllText(Path, Encoding.UTF8);
|
||||
Bvh = Bvh.Parse(Source);
|
||||
}
|
||||
|
||||
public void Load()
|
||||
{
|
||||
//
|
||||
// build hierarchy
|
||||
//
|
||||
Root = new GameObject(System.IO.Path.GetFileNameWithoutExtension(Path));
|
||||
var hips = BuildHierarchy(Root.transform, Bvh.Root, 1.0f);
|
||||
var skeleton = Skeleton.Estimate(hips);
|
||||
var description = AvatarDescription.Create(hips.Traverse().ToArray(), skeleton);
|
||||
|
||||
//
|
||||
// scaling. reposition
|
||||
//
|
||||
float scaling = 1.0f;
|
||||
{
|
||||
//var foot = animator.GetBoneTransform(HumanBodyBones.LeftFoot);
|
||||
var foot = hips.Traverse().Skip(skeleton.GetBoneIndex(HumanBodyBones.LeftFoot)).First();
|
||||
var hipHeight = hips.position.y - foot.position.y;
|
||||
// hips height to a meter
|
||||
scaling = 1.0f / hipHeight;
|
||||
foreach (var x in Root.transform.Traverse())
|
||||
{
|
||||
x.localPosition *= scaling;
|
||||
}
|
||||
|
||||
var scaledHeight = hipHeight * scaling;
|
||||
hips.position = new Vector3(0, scaledHeight, 0); // foot to ground
|
||||
}
|
||||
|
||||
//
|
||||
// avatar
|
||||
//
|
||||
Avatar = description.CreateAvatar(Root.transform);
|
||||
Avatar.name = "Avatar";
|
||||
AvatarDescription = description;
|
||||
var animator = Root.AddComponent<Animator>();
|
||||
animator.avatar = Avatar;
|
||||
|
||||
//
|
||||
// create AnimationClip
|
||||
//
|
||||
Animation = BvhAnimation.CreateAnimationClip(Bvh, scaling);
|
||||
Animation.name = Root.name;
|
||||
Animation.legacy = true;
|
||||
Animation.wrapMode = WrapMode.Loop;
|
||||
|
||||
var animation = Root.AddComponent<Animation>();
|
||||
animation.AddClip(Animation, Animation.name);
|
||||
animation.clip = Animation;
|
||||
animation.Play();
|
||||
|
||||
var humanPoseTransfer = Root.AddComponent<HumanPoseTransfer>();
|
||||
humanPoseTransfer.Avatar = Avatar;
|
||||
|
||||
// create SkinnedMesh for bone visualize
|
||||
var renderer = SkeletonMeshUtility.CreateRenderer(animator);
|
||||
Material = new Material(Shader.Find("Standard"));
|
||||
renderer.sharedMaterial = Material;
|
||||
Mesh = renderer.sharedMesh;
|
||||
Mesh.name = "box-man";
|
||||
|
||||
Root.AddComponent<BoneMapping>();
|
||||
|
||||
}
|
||||
|
||||
static Transform BuildHierarchy(Transform parent, BvhNode node, float toMeter)
|
||||
{
|
||||
var go = new GameObject(node.Name);
|
||||
go.transform.localPosition = node.Offset.ToXReversedVector3() * toMeter;
|
||||
go.transform.SetParent(parent, false);
|
||||
|
||||
//var gizmo = go.AddComponent<BoneGizmoDrawer>();
|
||||
//gizmo.Draw = true;
|
||||
|
||||
foreach (var child in node.Children)
|
||||
{
|
||||
BuildHierarchy(go.transform, child, toMeter);
|
||||
}
|
||||
|
||||
return go.transform;
|
||||
}
|
||||
#endregion
|
||||
|
||||
#if UNITY_EDITOR
|
||||
protected virtual string GetPrefabPath()
|
||||
{
|
||||
var dir = System.IO.Path.GetDirectoryName(Path);
|
||||
var name = System.IO.Path.GetFileNameWithoutExtension(Path);
|
||||
var prefabPath = string.Format("{0}/{1}.prefab", dir, name);
|
||||
if (!Application.isPlaying && File.Exists(prefabPath))
|
||||
{
|
||||
// already exists
|
||||
if (IsOwn(prefabPath))
|
||||
{
|
||||
//Debug.LogFormat("already exist. own: {0}", prefabPath);
|
||||
}
|
||||
else
|
||||
{
|
||||
// but unknown prefab
|
||||
var unique = AssetDatabase.GenerateUniqueAssetPath(prefabPath);
|
||||
//Debug.LogFormat("already exist: {0} => {1}", prefabPath, unique);
|
||||
prefabPath = unique;
|
||||
}
|
||||
}
|
||||
return prefabPath;
|
||||
}
|
||||
|
||||
#region Assets
|
||||
IEnumerable<UnityEngine.Object> GetSubAssets(string path)
|
||||
{
|
||||
return AssetDatabase.LoadAllAssetsAtPath(path);
|
||||
}
|
||||
|
||||
protected virtual bool IsOwn(string path)
|
||||
{
|
||||
foreach (var x in GetSubAssets(path))
|
||||
{
|
||||
//if (x is Transform) continue;
|
||||
if (x is GameObject) continue;
|
||||
if (x is Component) continue;
|
||||
if (AssetDatabase.IsSubAsset(x))
|
||||
{
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
IEnumerable<UnityEngine.Object> ObjectsForSubAsset()
|
||||
{
|
||||
if (Animation != null) yield return Animation;
|
||||
if (AvatarDescription != null) yield return AvatarDescription;
|
||||
if (Avatar != null) yield return Avatar;
|
||||
if (Mesh != null) yield return Mesh;
|
||||
if (Material != null) yield return Material;
|
||||
}
|
||||
|
||||
public void SaveAsAsset()
|
||||
{
|
||||
var path = GetPrefabPath();
|
||||
if (File.Exists(path))
|
||||
{
|
||||
// clear SubAssets
|
||||
foreach (var x in GetSubAssets(path).Where(x => !(x is GameObject) && !(x is Component)))
|
||||
{
|
||||
GameObject.DestroyImmediate(x, true);
|
||||
}
|
||||
}
|
||||
|
||||
// Add SubAsset
|
||||
foreach (var o in ObjectsForSubAsset())
|
||||
{
|
||||
AssetDatabase.AddObjectToAsset(o, path);
|
||||
}
|
||||
|
||||
// Create or upate Main Asset
|
||||
if (File.Exists(path))
|
||||
{
|
||||
Debug.LogFormat("replace prefab: {0}", path);
|
||||
var prefab = AssetDatabase.LoadAssetAtPath<GameObject>(path);
|
||||
PrefabUtility.ReplacePrefab(Root, prefab, ReplacePrefabOptions.ReplaceNameBased);
|
||||
}
|
||||
else
|
||||
{
|
||||
Debug.LogFormat("create prefab: {0}", path);
|
||||
PrefabUtility.CreatePrefab(path, Root);
|
||||
}
|
||||
|
||||
AssetDatabase.ImportAsset(path);
|
||||
}
|
||||
#endregion
|
||||
#endif
|
||||
|
||||
public void Destroy(bool destroySubAssets)
|
||||
{
|
||||
if (Root != null) GameObject.DestroyImmediate(Root);
|
||||
if (destroySubAssets)
|
||||
{
|
||||
#if UNITY_EDITOR
|
||||
foreach (var o in ObjectsForSubAsset())
|
||||
{
|
||||
UnityEngine.Object.DestroyImmediate(o, true);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
using System;
|
||||
using System.Linq;
|
||||
using System.Collections.Generic;
|
||||
using UnityEngine;
|
||||
using System.IO;
|
||||
using System.Text;
|
||||
#if UNITY_EDITOR
|
||||
using UnityEditor;
|
||||
#endif
|
||||
|
||||
|
||||
namespace UniHumanoid
|
||||
{
|
||||
[Obsolete("use BvhImporterContext")]
|
||||
public class ImporterContext: BvhImporterContext
|
||||
{
|
||||
}
|
||||
|
||||
public class BvhImporterContext
|
||||
{
|
||||
#region Source
|
||||
String m_path;
|
||||
public String Path
|
||||
{
|
||||
get { return m_path; }
|
||||
set
|
||||
{
|
||||
if (m_path == value) return;
|
||||
m_path = value;
|
||||
}
|
||||
}
|
||||
public String Source; // source
|
||||
public Bvh Bvh;
|
||||
#endregion
|
||||
|
||||
#region Imported
|
||||
public GameObject Root;
|
||||
public List<Transform> Nodes = new List<Transform>();
|
||||
public AnimationClip Animation;
|
||||
public AvatarDescription AvatarDescription;
|
||||
public Avatar Avatar;
|
||||
public Mesh Mesh;
|
||||
public Material Material;
|
||||
#endregion
|
||||
|
||||
#region Load
|
||||
[Obsolete("use Load(path)")]
|
||||
public void Parse()
|
||||
{
|
||||
Parse(Path);
|
||||
}
|
||||
|
||||
public void Parse(string path)
|
||||
{
|
||||
Path = path;
|
||||
Source = File.ReadAllText(Path, Encoding.UTF8);
|
||||
Bvh = Bvh.Parse(Source);
|
||||
}
|
||||
|
||||
public void Load()
|
||||
{
|
||||
//
|
||||
// build hierarchy
|
||||
//
|
||||
Root = new GameObject(System.IO.Path.GetFileNameWithoutExtension(Path));
|
||||
var hips = BuildHierarchy(Root.transform, Bvh.Root, 1.0f);
|
||||
var skeleton = Skeleton.Estimate(hips);
|
||||
var description = AvatarDescription.Create(hips.Traverse().ToArray(), skeleton);
|
||||
|
||||
//
|
||||
// scaling. reposition
|
||||
//
|
||||
float scaling = 1.0f;
|
||||
{
|
||||
//var foot = animator.GetBoneTransform(HumanBodyBones.LeftFoot);
|
||||
var foot = hips.Traverse().Skip(skeleton.GetBoneIndex(HumanBodyBones.LeftFoot)).First();
|
||||
var hipHeight = hips.position.y - foot.position.y;
|
||||
// hips height to a meter
|
||||
scaling = 1.0f / hipHeight;
|
||||
foreach (var x in Root.transform.Traverse())
|
||||
{
|
||||
x.localPosition *= scaling;
|
||||
}
|
||||
|
||||
var scaledHeight = hipHeight * scaling;
|
||||
hips.position = new Vector3(0, scaledHeight, 0); // foot to ground
|
||||
}
|
||||
|
||||
//
|
||||
// avatar
|
||||
//
|
||||
Avatar = description.CreateAvatar(Root.transform);
|
||||
Avatar.name = "Avatar";
|
||||
AvatarDescription = description;
|
||||
var animator = Root.AddComponent<Animator>();
|
||||
animator.avatar = Avatar;
|
||||
|
||||
//
|
||||
// create AnimationClip
|
||||
//
|
||||
Animation = BvhAnimation.CreateAnimationClip(Bvh, scaling);
|
||||
Animation.name = Root.name;
|
||||
Animation.legacy = true;
|
||||
Animation.wrapMode = WrapMode.Loop;
|
||||
|
||||
var animation = Root.AddComponent<Animation>();
|
||||
animation.AddClip(Animation, Animation.name);
|
||||
animation.clip = Animation;
|
||||
animation.Play();
|
||||
|
||||
var humanPoseTransfer = Root.AddComponent<HumanPoseTransfer>();
|
||||
humanPoseTransfer.Avatar = Avatar;
|
||||
|
||||
// create SkinnedMesh for bone visualize
|
||||
var renderer = SkeletonMeshUtility.CreateRenderer(animator);
|
||||
Material = new Material(Shader.Find("Standard"));
|
||||
renderer.sharedMaterial = Material;
|
||||
Mesh = renderer.sharedMesh;
|
||||
Mesh.name = "box-man";
|
||||
|
||||
Root.AddComponent<BoneMapping>();
|
||||
|
||||
}
|
||||
|
||||
static Transform BuildHierarchy(Transform parent, BvhNode node, float toMeter)
|
||||
{
|
||||
var go = new GameObject(node.Name);
|
||||
go.transform.localPosition = node.Offset.ToXReversedVector3() * toMeter;
|
||||
go.transform.SetParent(parent, false);
|
||||
|
||||
//var gizmo = go.AddComponent<BoneGizmoDrawer>();
|
||||
//gizmo.Draw = true;
|
||||
|
||||
foreach (var child in node.Children)
|
||||
{
|
||||
BuildHierarchy(go.transform, child, toMeter);
|
||||
}
|
||||
|
||||
return go.transform;
|
||||
}
|
||||
#endregion
|
||||
|
||||
#if UNITY_EDITOR
|
||||
protected virtual string GetPrefabPath()
|
||||
{
|
||||
var dir = System.IO.Path.GetDirectoryName(Path);
|
||||
var name = System.IO.Path.GetFileNameWithoutExtension(Path);
|
||||
var prefabPath = string.Format("{0}/{1}.prefab", dir, name);
|
||||
if (!Application.isPlaying && File.Exists(prefabPath))
|
||||
{
|
||||
// already exists
|
||||
if (IsOwn(prefabPath))
|
||||
{
|
||||
//Debug.LogFormat("already exist. own: {0}", prefabPath);
|
||||
}
|
||||
else
|
||||
{
|
||||
// but unknown prefab
|
||||
var unique = AssetDatabase.GenerateUniqueAssetPath(prefabPath);
|
||||
//Debug.LogFormat("already exist: {0} => {1}", prefabPath, unique);
|
||||
prefabPath = unique;
|
||||
}
|
||||
}
|
||||
return prefabPath;
|
||||
}
|
||||
|
||||
#region Assets
|
||||
IEnumerable<UnityEngine.Object> GetSubAssets(string path)
|
||||
{
|
||||
return AssetDatabase.LoadAllAssetsAtPath(path);
|
||||
}
|
||||
|
||||
protected virtual bool IsOwn(string path)
|
||||
{
|
||||
foreach (var x in GetSubAssets(path))
|
||||
{
|
||||
//if (x is Transform) continue;
|
||||
if (x is GameObject) continue;
|
||||
if (x is Component) continue;
|
||||
if (AssetDatabase.IsSubAsset(x))
|
||||
{
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
IEnumerable<UnityEngine.Object> ObjectsForSubAsset()
|
||||
{
|
||||
if (Animation != null) yield return Animation;
|
||||
if (AvatarDescription != null) yield return AvatarDescription;
|
||||
if (Avatar != null) yield return Avatar;
|
||||
if (Mesh != null) yield return Mesh;
|
||||
if (Material != null) yield return Material;
|
||||
}
|
||||
|
||||
public void SaveAsAsset()
|
||||
{
|
||||
var path = GetPrefabPath();
|
||||
if (File.Exists(path))
|
||||
{
|
||||
// clear SubAssets
|
||||
foreach (var x in GetSubAssets(path).Where(x => !(x is GameObject) && !(x is Component)))
|
||||
{
|
||||
GameObject.DestroyImmediate(x, true);
|
||||
}
|
||||
}
|
||||
|
||||
// Add SubAsset
|
||||
foreach (var o in ObjectsForSubAsset())
|
||||
{
|
||||
AssetDatabase.AddObjectToAsset(o, path);
|
||||
}
|
||||
|
||||
// Create or upate Main Asset
|
||||
if (File.Exists(path))
|
||||
{
|
||||
Debug.LogFormat("replace prefab: {0}", path);
|
||||
var prefab = AssetDatabase.LoadAssetAtPath<GameObject>(path);
|
||||
PrefabUtility.ReplacePrefab(Root, prefab, ReplacePrefabOptions.ReplaceNameBased);
|
||||
}
|
||||
else
|
||||
{
|
||||
Debug.LogFormat("create prefab: {0}", path);
|
||||
PrefabUtility.CreatePrefab(path, Root);
|
||||
}
|
||||
|
||||
AssetDatabase.ImportAsset(path);
|
||||
}
|
||||
#endregion
|
||||
#endif
|
||||
|
||||
public void Destroy(bool destroySubAssets)
|
||||
{
|
||||
if (Root != null) GameObject.DestroyImmediate(Root);
|
||||
if (destroySubAssets)
|
||||
{
|
||||
#if UNITY_EDITOR
|
||||
foreach (var o in ObjectsForSubAsset())
|
||||
{
|
||||
UnityEngine.Object.DestroyImmediate(o, true);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,45 +1,45 @@
|
||||
using System;
|
||||
using System.Linq;
|
||||
using UnityEngine;
|
||||
|
||||
|
||||
namespace UniHumanoid
|
||||
{
|
||||
public static class BvhExtensions
|
||||
{
|
||||
public static Func<float, float, float, Quaternion> GetEulerToRotation(this BvhNode bvh)
|
||||
{
|
||||
var order = bvh.Channels.Where(x => x == Channel.Xrotation || x == Channel.Yrotation || x == Channel.Zrotation).ToArray();
|
||||
|
||||
return (x, y, z) =>
|
||||
{
|
||||
var xRot = Quaternion.Euler(x, 0, 0);
|
||||
var yRot = Quaternion.Euler(0, y, 0);
|
||||
var zRot = Quaternion.Euler(0, 0, z);
|
||||
|
||||
var r = Quaternion.identity;
|
||||
foreach (var ch in order)
|
||||
{
|
||||
switch (ch)
|
||||
{
|
||||
case Channel.Xrotation: r = r * xRot; break;
|
||||
case Channel.Yrotation: r = r * yRot; break;
|
||||
case Channel.Zrotation: r = r * zRot; break;
|
||||
default: throw new BvhException("no rotation");
|
||||
}
|
||||
}
|
||||
return r;
|
||||
};
|
||||
}
|
||||
|
||||
public static Vector3 ToVector3(this Single3 s3)
|
||||
{
|
||||
return new Vector3(s3.x, s3.y, s3.z);
|
||||
}
|
||||
|
||||
public static Vector3 ToXReversedVector3(this Single3 s3)
|
||||
{
|
||||
return new Vector3(-s3.x, s3.y, s3.z);
|
||||
}
|
||||
}
|
||||
}
|
||||
using System;
|
||||
using System.Linq;
|
||||
using UnityEngine;
|
||||
|
||||
|
||||
namespace UniHumanoid
|
||||
{
|
||||
public static class BvhExtensions
|
||||
{
|
||||
public static Func<float, float, float, Quaternion> GetEulerToRotation(this BvhNode bvh)
|
||||
{
|
||||
var order = bvh.Channels.Where(x => x == Channel.Xrotation || x == Channel.Yrotation || x == Channel.Zrotation).ToArray();
|
||||
|
||||
return (x, y, z) =>
|
||||
{
|
||||
var xRot = Quaternion.Euler(x, 0, 0);
|
||||
var yRot = Quaternion.Euler(0, y, 0);
|
||||
var zRot = Quaternion.Euler(0, 0, z);
|
||||
|
||||
var r = Quaternion.identity;
|
||||
foreach (var ch in order)
|
||||
{
|
||||
switch (ch)
|
||||
{
|
||||
case Channel.Xrotation: r = r * xRot; break;
|
||||
case Channel.Yrotation: r = r * yRot; break;
|
||||
case Channel.Zrotation: r = r * zRot; break;
|
||||
default: throw new BvhException("no rotation");
|
||||
}
|
||||
}
|
||||
return r;
|
||||
};
|
||||
}
|
||||
|
||||
public static Vector3 ToVector3(this Single3 s3)
|
||||
{
|
||||
return new Vector3(s3.x, s3.y, s3.z);
|
||||
}
|
||||
|
||||
public static Vector3 ToXReversedVector3(this Single3 s3)
|
||||
{
|
||||
return new Vector3(-s3.x, s3.y, s3.z);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,49 +1,49 @@
|
||||
using System.Collections.Generic;
|
||||
using UnityEngine;
|
||||
|
||||
|
||||
namespace UniHumanoid
|
||||
{
|
||||
public static class UnityExtensions
|
||||
{
|
||||
public static Quaternion ReverseX(this Quaternion quaternion)
|
||||
{
|
||||
float angle;
|
||||
Vector3 axis;
|
||||
quaternion.ToAngleAxis(out angle, out axis);
|
||||
|
||||
return Quaternion.AngleAxis(-angle, new Vector3(-axis.x, axis.y, axis.z));
|
||||
}
|
||||
|
||||
public static IEnumerable<Transform> GetChildren(this Transform parent)
|
||||
{
|
||||
foreach (Transform child in parent)
|
||||
{
|
||||
yield return child;
|
||||
}
|
||||
}
|
||||
|
||||
public static IEnumerable<Transform> Traverse(this Transform parent)
|
||||
{
|
||||
yield return parent;
|
||||
|
||||
foreach (Transform child in parent)
|
||||
{
|
||||
foreach (Transform descendant in Traverse(child))
|
||||
{
|
||||
yield return descendant;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public static SkeletonBone ToSkeletonBone(this Transform t)
|
||||
{
|
||||
var sb = new SkeletonBone();
|
||||
sb.name = t.name;
|
||||
sb.position = t.localPosition;
|
||||
sb.rotation = t.localRotation;
|
||||
sb.scale = t.localScale;
|
||||
return sb;
|
||||
}
|
||||
}
|
||||
}
|
||||
using System.Collections.Generic;
|
||||
using UnityEngine;
|
||||
|
||||
|
||||
namespace UniHumanoid
|
||||
{
|
||||
public static class UnityExtensions
|
||||
{
|
||||
public static Quaternion ReverseX(this Quaternion quaternion)
|
||||
{
|
||||
float angle;
|
||||
Vector3 axis;
|
||||
quaternion.ToAngleAxis(out angle, out axis);
|
||||
|
||||
return Quaternion.AngleAxis(-angle, new Vector3(-axis.x, axis.y, axis.z));
|
||||
}
|
||||
|
||||
public static IEnumerable<Transform> GetChildren(this Transform parent)
|
||||
{
|
||||
foreach (Transform child in parent)
|
||||
{
|
||||
yield return child;
|
||||
}
|
||||
}
|
||||
|
||||
public static IEnumerable<Transform> Traverse(this Transform parent)
|
||||
{
|
||||
yield return parent;
|
||||
|
||||
foreach (Transform child in parent)
|
||||
{
|
||||
foreach (Transform descendant in Traverse(child))
|
||||
{
|
||||
yield return descendant;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public static SkeletonBone ToSkeletonBone(this Transform t)
|
||||
{
|
||||
var sb = new SkeletonBone();
|
||||
sb.name = t.name;
|
||||
sb.position = t.localPosition;
|
||||
sb.rotation = t.localRotation;
|
||||
sb.scale = t.localScale;
|
||||
return sb;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,105 +1,105 @@
|
||||
using System;
|
||||
using System.Linq;
|
||||
using UnityEngine;
|
||||
#if UNITY_EDITOR
|
||||
using UnityEditor;
|
||||
#endif
|
||||
|
||||
|
||||
namespace UniHumanoid
|
||||
{
|
||||
public class MuscleDebug : MonoBehaviour
|
||||
{
|
||||
Avatar GetAvatar()
|
||||
{
|
||||
var animator = GetComponent<Animator>();
|
||||
if (animator != null && animator.avatar != null)
|
||||
{
|
||||
return animator.avatar;
|
||||
}
|
||||
|
||||
var transfer = GetComponent<HumanPoseTransfer>();
|
||||
if (transfer != null && transfer.Avatar != null)
|
||||
{
|
||||
return transfer.Avatar;
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
HumanPoseHandler m_handler;
|
||||
|
||||
public HumanPose m_pose;
|
||||
|
||||
[Serializable]
|
||||
public struct Muscle
|
||||
{
|
||||
public int Index;
|
||||
public string Name;
|
||||
public float Value;
|
||||
}
|
||||
|
||||
public Vector3 BodyPosition;
|
||||
|
||||
public Muscle[] Muscles;
|
||||
|
||||
private void OnEnable()
|
||||
{
|
||||
var avatar = GetAvatar();
|
||||
if (avatar == null)
|
||||
{
|
||||
enabled = false;
|
||||
return;
|
||||
}
|
||||
|
||||
m_handler = new HumanPoseHandler(avatar, transform);
|
||||
|
||||
Muscles = HumanTrait.MuscleName.Select((x, i) =>
|
||||
{
|
||||
return new Muscle
|
||||
{
|
||||
Index = i,
|
||||
Name = x,
|
||||
};
|
||||
})
|
||||
.ToArray()
|
||||
;
|
||||
}
|
||||
|
||||
private void OnDisable()
|
||||
{
|
||||
}
|
||||
|
||||
private void Update()
|
||||
{
|
||||
m_handler.GetHumanPose(ref m_pose);
|
||||
|
||||
BodyPosition = m_pose.bodyPosition;
|
||||
|
||||
for (int i = 0; i < m_pose.muscles.Length; ++i)
|
||||
{
|
||||
Muscles[i].Value = m_pose.muscles[i];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#if UNITY_EDITOR
|
||||
[CustomPropertyDrawer(typeof(MuscleDebug.Muscle))]
|
||||
public class MuscleDrawer : PropertyDrawer
|
||||
{
|
||||
public override void OnGUI(Rect position,
|
||||
SerializedProperty property, GUIContent label)
|
||||
{
|
||||
var nameProp = property.FindPropertyRelative("Name");
|
||||
var valueProp = property.FindPropertyRelative("Value");
|
||||
/*
|
||||
var labl = string.Format("{0}: {1}",
|
||||
nameProp.stringValue,
|
||||
valueProp.floatValue
|
||||
);
|
||||
*/
|
||||
EditorGUI.LabelField(position, nameProp.stringValue, string.Format("{0:0.00}", valueProp.floatValue));
|
||||
}
|
||||
}
|
||||
#endif
|
||||
}
|
||||
using System;
|
||||
using System.Linq;
|
||||
using UnityEngine;
|
||||
#if UNITY_EDITOR
|
||||
using UnityEditor;
|
||||
#endif
|
||||
|
||||
|
||||
namespace UniHumanoid
|
||||
{
|
||||
public class MuscleDebug : MonoBehaviour
|
||||
{
|
||||
Avatar GetAvatar()
|
||||
{
|
||||
var animator = GetComponent<Animator>();
|
||||
if (animator != null && animator.avatar != null)
|
||||
{
|
||||
return animator.avatar;
|
||||
}
|
||||
|
||||
var transfer = GetComponent<HumanPoseTransfer>();
|
||||
if (transfer != null && transfer.Avatar != null)
|
||||
{
|
||||
return transfer.Avatar;
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
HumanPoseHandler m_handler;
|
||||
|
||||
public HumanPose m_pose;
|
||||
|
||||
[Serializable]
|
||||
public struct Muscle
|
||||
{
|
||||
public int Index;
|
||||
public string Name;
|
||||
public float Value;
|
||||
}
|
||||
|
||||
public Vector3 BodyPosition;
|
||||
|
||||
public Muscle[] Muscles;
|
||||
|
||||
private void OnEnable()
|
||||
{
|
||||
var avatar = GetAvatar();
|
||||
if (avatar == null)
|
||||
{
|
||||
enabled = false;
|
||||
return;
|
||||
}
|
||||
|
||||
m_handler = new HumanPoseHandler(avatar, transform);
|
||||
|
||||
Muscles = HumanTrait.MuscleName.Select((x, i) =>
|
||||
{
|
||||
return new Muscle
|
||||
{
|
||||
Index = i,
|
||||
Name = x,
|
||||
};
|
||||
})
|
||||
.ToArray()
|
||||
;
|
||||
}
|
||||
|
||||
private void OnDisable()
|
||||
{
|
||||
}
|
||||
|
||||
private void Update()
|
||||
{
|
||||
m_handler.GetHumanPose(ref m_pose);
|
||||
|
||||
BodyPosition = m_pose.bodyPosition;
|
||||
|
||||
for (int i = 0; i < m_pose.muscles.Length; ++i)
|
||||
{
|
||||
Muscles[i].Value = m_pose.muscles[i];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#if UNITY_EDITOR
|
||||
[CustomPropertyDrawer(typeof(MuscleDebug.Muscle))]
|
||||
public class MuscleDrawer : PropertyDrawer
|
||||
{
|
||||
public override void OnGUI(Rect position,
|
||||
SerializedProperty property, GUIContent label)
|
||||
{
|
||||
var nameProp = property.FindPropertyRelative("Name");
|
||||
var valueProp = property.FindPropertyRelative("Value");
|
||||
/*
|
||||
var labl = string.Format("{0}: {1}",
|
||||
nameProp.stringValue,
|
||||
valueProp.floatValue
|
||||
);
|
||||
*/
|
||||
EditorGUI.LabelField(position, nameProp.stringValue, string.Format("{0:0.00}", valueProp.floatValue));
|
||||
}
|
||||
}
|
||||
#endif
|
||||
}
|
||||
@@ -1,92 +1,92 @@
|
||||
using System.Collections.Generic;
|
||||
using UnityEngine;
|
||||
|
||||
|
||||
namespace UniHumanoid
|
||||
{
|
||||
/// <summary>
|
||||
/// Mapping HumanBodyBones to BoneIndex
|
||||
/// </summary>
|
||||
public struct Skeleton
|
||||
{
|
||||
Dictionary<HumanBodyBones, int> m_indexMap;
|
||||
public Dictionary<HumanBodyBones, int> Bones
|
||||
{
|
||||
get { return m_indexMap; }
|
||||
}
|
||||
public int GetBoneIndex(HumanBodyBones bone)
|
||||
{
|
||||
int index;
|
||||
if (m_indexMap.TryGetValue(bone, out index))
|
||||
{
|
||||
return index;
|
||||
}
|
||||
else
|
||||
{
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
#if UNITY_EDITOR
|
||||
/// <summary>
|
||||
/// For UnitTest
|
||||
/// </summary>
|
||||
Dictionary<HumanBodyBones, string> m_nameMap;
|
||||
/// <summary>
|
||||
/// ForTest
|
||||
/// </summary>
|
||||
/// <param name="bone"></param>
|
||||
/// <returns></returns>
|
||||
public string GetBoneName(HumanBodyBones bone)
|
||||
{
|
||||
string name;
|
||||
if (m_nameMap.TryGetValue(bone, out name))
|
||||
{
|
||||
return name;
|
||||
}
|
||||
else
|
||||
{
|
||||
return null;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
public static Skeleton Estimate(Transform hips)
|
||||
{
|
||||
var estimater = new BvhSkeletonEstimator();
|
||||
return estimater.Detect(hips);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Register bone's HumanBodyBones
|
||||
/// </summary>
|
||||
/// <param name="bone"></param>
|
||||
/// <param name="bones"></param>
|
||||
/// <param name="b"></param>
|
||||
public void Set(HumanBodyBones bone, IList<IBone> bones, IBone b)
|
||||
{
|
||||
if (b != null)
|
||||
{
|
||||
Set(bone, bones.IndexOf(b), b.Name);
|
||||
}
|
||||
}
|
||||
|
||||
public void Set(HumanBodyBones bone, int index, string name)
|
||||
{
|
||||
if (m_indexMap == null)
|
||||
{
|
||||
m_indexMap = new Dictionary<HumanBodyBones, int>();
|
||||
}
|
||||
m_indexMap[bone] = index;
|
||||
|
||||
#if UNITY_EDITOR
|
||||
if (m_nameMap == null)
|
||||
{
|
||||
m_nameMap = new Dictionary<HumanBodyBones, string>();
|
||||
}
|
||||
m_nameMap[bone] = name;
|
||||
#endif
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
using System.Collections.Generic;
|
||||
using UnityEngine;
|
||||
|
||||
|
||||
namespace UniHumanoid
|
||||
{
|
||||
/// <summary>
|
||||
/// Mapping HumanBodyBones to BoneIndex
|
||||
/// </summary>
|
||||
public struct Skeleton
|
||||
{
|
||||
Dictionary<HumanBodyBones, int> m_indexMap;
|
||||
public Dictionary<HumanBodyBones, int> Bones
|
||||
{
|
||||
get { return m_indexMap; }
|
||||
}
|
||||
public int GetBoneIndex(HumanBodyBones bone)
|
||||
{
|
||||
int index;
|
||||
if (m_indexMap.TryGetValue(bone, out index))
|
||||
{
|
||||
return index;
|
||||
}
|
||||
else
|
||||
{
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
#if UNITY_EDITOR
|
||||
/// <summary>
|
||||
/// For UnitTest
|
||||
/// </summary>
|
||||
Dictionary<HumanBodyBones, string> m_nameMap;
|
||||
/// <summary>
|
||||
/// ForTest
|
||||
/// </summary>
|
||||
/// <param name="bone"></param>
|
||||
/// <returns></returns>
|
||||
public string GetBoneName(HumanBodyBones bone)
|
||||
{
|
||||
string name;
|
||||
if (m_nameMap.TryGetValue(bone, out name))
|
||||
{
|
||||
return name;
|
||||
}
|
||||
else
|
||||
{
|
||||
return null;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
public static Skeleton Estimate(Transform hips)
|
||||
{
|
||||
var estimater = new BvhSkeletonEstimator();
|
||||
return estimater.Detect(hips);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Register bone's HumanBodyBones
|
||||
/// </summary>
|
||||
/// <param name="bone"></param>
|
||||
/// <param name="bones"></param>
|
||||
/// <param name="b"></param>
|
||||
public void Set(HumanBodyBones bone, IList<IBone> bones, IBone b)
|
||||
{
|
||||
if (b != null)
|
||||
{
|
||||
Set(bone, bones.IndexOf(b), b.Name);
|
||||
}
|
||||
}
|
||||
|
||||
public void Set(HumanBodyBones bone, int index, string name)
|
||||
{
|
||||
if (m_indexMap == null)
|
||||
{
|
||||
m_indexMap = new Dictionary<HumanBodyBones, int>();
|
||||
}
|
||||
m_indexMap[bone] = index;
|
||||
|
||||
#if UNITY_EDITOR
|
||||
if (m_nameMap == null)
|
||||
{
|
||||
m_nameMap = new Dictionary<HumanBodyBones, string>();
|
||||
}
|
||||
m_nameMap[bone] = name;
|
||||
#endif
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
@@ -1,244 +1,244 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using UnityEngine;
|
||||
|
||||
|
||||
namespace UniHumanoid
|
||||
{
|
||||
public interface ISkeletonDetector
|
||||
{
|
||||
Skeleton Detect(IList<IBone> bones);
|
||||
}
|
||||
|
||||
|
||||
public class BvhSkeletonEstimator : ISkeletonDetector
|
||||
{
|
||||
static IBone GetRoot(IList<IBone> bones)
|
||||
{
|
||||
var hips = bones.Where(x => x.Parent == null).ToArray();
|
||||
if (hips.Length != 1)
|
||||
{
|
||||
throw new System.Exception("Require unique root");
|
||||
}
|
||||
return hips[0];
|
||||
}
|
||||
|
||||
static IBone SelectBone(Func<IBone, IBone, IBone> selector, IList<IBone> bones)
|
||||
{
|
||||
if (bones == null || bones.Count == 0) throw new Exception("no bones");
|
||||
var current = bones[0];
|
||||
for (var i = 1; i < bones.Count; ++i)
|
||||
{
|
||||
current = selector(current, bones[i]);
|
||||
}
|
||||
return current;
|
||||
}
|
||||
|
||||
static void GetSpineAndHips(IBone hips, out IBone spine, out IBone leg_L, out IBone leg_R)
|
||||
{
|
||||
if (hips.Children.Count != 3) throw new System.Exception("Hips require 3 children");
|
||||
spine = SelectBone((l, r) => l.CenterOfDescendant().y > r.CenterOfDescendant().y ? l : r, hips.Children);
|
||||
leg_L = SelectBone((l, r) => l.CenterOfDescendant().x < r.CenterOfDescendant().x ? l : r, hips.Children);
|
||||
leg_R = SelectBone((l, r) => l.CenterOfDescendant().x > r.CenterOfDescendant().x ? l : r, hips.Children);
|
||||
}
|
||||
|
||||
static void GetNeckAndArms(IBone chest, out IBone neck, out IBone arm_L, out IBone arm_R)
|
||||
{
|
||||
if (chest.Children.Count != 3) throw new System.Exception("Chest require 3 children");
|
||||
neck = SelectBone((l, r) => l.CenterOfDescendant().y > r.CenterOfDescendant().y ? l : r, chest.Children);
|
||||
arm_L = SelectBone((l, r) => l.CenterOfDescendant().x < r.CenterOfDescendant().x ? l : r, chest.Children);
|
||||
arm_R = SelectBone((l, r) => l.CenterOfDescendant().x > r.CenterOfDescendant().x ? l : r, chest.Children);
|
||||
}
|
||||
|
||||
struct Arm
|
||||
{
|
||||
public IBone Shoulder;
|
||||
public IBone UpperArm;
|
||||
public IBone LowerArm;
|
||||
public IBone Hand;
|
||||
}
|
||||
|
||||
Arm GetArm(IBone shoulder)
|
||||
{
|
||||
var bones = shoulder.Traverse().ToArray();
|
||||
switch (bones.Length)
|
||||
{
|
||||
case 0:
|
||||
case 1:
|
||||
case 2:
|
||||
case 3:
|
||||
throw new NotImplementedException();
|
||||
|
||||
default:
|
||||
return new Arm
|
||||
{
|
||||
Shoulder = bones[0],
|
||||
UpperArm = bones[1],
|
||||
LowerArm = bones[2],
|
||||
Hand = bones[3],
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
struct Leg
|
||||
{
|
||||
public IBone UpperLeg;
|
||||
public IBone LowerLeg;
|
||||
public IBone Foot;
|
||||
public IBone Toes;
|
||||
}
|
||||
|
||||
Leg GetLeg(IBone leg)
|
||||
{
|
||||
var bones = leg.Traverse().Where(x => !x.Name.ToLower().Contains("buttock")).ToArray();
|
||||
switch (bones.Length)
|
||||
{
|
||||
case 0:
|
||||
case 1:
|
||||
case 2:
|
||||
throw new NotImplementedException();
|
||||
|
||||
case 3:
|
||||
return new Leg
|
||||
{
|
||||
UpperLeg = bones[0],
|
||||
LowerLeg = bones[1],
|
||||
Foot = bones[2],
|
||||
};
|
||||
|
||||
default:
|
||||
return new Leg
|
||||
{
|
||||
UpperLeg = bones[bones.Length - 4],
|
||||
LowerLeg = bones[bones.Length - 3],
|
||||
Foot = bones[bones.Length - 2],
|
||||
Toes = bones[bones.Length - 1],
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
public Skeleton Detect(IList<IBone> bones)
|
||||
{
|
||||
//
|
||||
// search bones
|
||||
//
|
||||
var root = GetRoot(bones);
|
||||
var hips = root.Traverse().First(x => x.Children.Count == 3);
|
||||
|
||||
IBone spine, hip_L, hip_R;
|
||||
GetSpineAndHips(hips, out spine, out hip_L, out hip_R);
|
||||
var legLeft = GetLeg(hip_L);
|
||||
var legRight = GetLeg(hip_R);
|
||||
|
||||
var spineToChest = new List<IBone>();
|
||||
foreach(var x in spine.Traverse())
|
||||
{
|
||||
spineToChest.Add(x);
|
||||
if (x.Children.Count == 3) break;
|
||||
}
|
||||
|
||||
IBone neck, shoulder_L, shoulder_R;
|
||||
GetNeckAndArms(spineToChest.Last(), out neck, out shoulder_L, out shoulder_R);
|
||||
var armLeft = GetArm(shoulder_L);
|
||||
var armRight = GetArm(shoulder_R);
|
||||
|
||||
var neckToHead = neck.Traverse().ToArray();
|
||||
|
||||
//
|
||||
// set result
|
||||
//
|
||||
var skeleton = new Skeleton();
|
||||
skeleton.Set(HumanBodyBones.Hips, bones, hips);
|
||||
|
||||
switch (spineToChest.Count)
|
||||
{
|
||||
case 0:
|
||||
throw new Exception();
|
||||
|
||||
case 1:
|
||||
skeleton.Set(HumanBodyBones.Spine, bones, spineToChest[0]);
|
||||
break;
|
||||
|
||||
case 2:
|
||||
skeleton.Set(HumanBodyBones.Spine, bones, spineToChest[0]);
|
||||
skeleton.Set(HumanBodyBones.Chest, bones, spineToChest[1]);
|
||||
break;
|
||||
|
||||
#if UNITY_5_6_OR_NEWER
|
||||
case 3:
|
||||
skeleton.Set(HumanBodyBones.Spine, bones, spineToChest[0]);
|
||||
skeleton.Set(HumanBodyBones.Chest, bones, spineToChest[1]);
|
||||
skeleton.Set(HumanBodyBones.UpperChest, bones, spineToChest[2]);
|
||||
break;
|
||||
#endif
|
||||
|
||||
default:
|
||||
skeleton.Set(HumanBodyBones.Spine, bones, spineToChest[0]);
|
||||
#if UNITY_5_6_OR_NEWER
|
||||
skeleton.Set(HumanBodyBones.Chest, bones, spineToChest[1]);
|
||||
skeleton.Set(HumanBodyBones.UpperChest, bones, spineToChest.Last());
|
||||
#else
|
||||
skeleton.Set(HumanBodyBones.Chest, bones, spineToChest.Last());
|
||||
#endif
|
||||
break;
|
||||
}
|
||||
|
||||
switch (neckToHead.Length)
|
||||
{
|
||||
case 0:
|
||||
throw new Exception();
|
||||
|
||||
case 1:
|
||||
skeleton.Set(HumanBodyBones.Head, bones, neckToHead[0]);
|
||||
break;
|
||||
|
||||
case 2:
|
||||
skeleton.Set(HumanBodyBones.Neck, bones, neckToHead[0]);
|
||||
skeleton.Set(HumanBodyBones.Head, bones, neckToHead[1]);
|
||||
break;
|
||||
|
||||
default:
|
||||
skeleton.Set(HumanBodyBones.Neck, bones, neckToHead[0]);
|
||||
skeleton.Set(HumanBodyBones.Head, bones, neckToHead.Where(x => x.Parent.Children.Count==1).Last());
|
||||
break;
|
||||
}
|
||||
|
||||
skeleton.Set(HumanBodyBones.LeftUpperLeg, bones, legLeft.UpperLeg);
|
||||
skeleton.Set(HumanBodyBones.LeftLowerLeg, bones, legLeft.LowerLeg);
|
||||
skeleton.Set(HumanBodyBones.LeftFoot, bones, legLeft.Foot);
|
||||
skeleton.Set(HumanBodyBones.LeftToes, bones, legLeft.Toes);
|
||||
|
||||
skeleton.Set(HumanBodyBones.RightUpperLeg, bones, legRight.UpperLeg);
|
||||
skeleton.Set(HumanBodyBones.RightLowerLeg, bones, legRight.LowerLeg);
|
||||
skeleton.Set(HumanBodyBones.RightFoot, bones, legRight.Foot);
|
||||
skeleton.Set(HumanBodyBones.RightToes, bones, legRight.Toes);
|
||||
|
||||
skeleton.Set(HumanBodyBones.LeftShoulder, bones, armLeft.Shoulder);
|
||||
skeleton.Set(HumanBodyBones.LeftUpperArm, bones, armLeft.UpperArm);
|
||||
skeleton.Set(HumanBodyBones.LeftLowerArm, bones, armLeft.LowerArm);
|
||||
skeleton.Set(HumanBodyBones.LeftHand, bones, armLeft.Hand);
|
||||
|
||||
skeleton.Set(HumanBodyBones.RightShoulder, bones, armRight.Shoulder);
|
||||
skeleton.Set(HumanBodyBones.RightUpperArm, bones, armRight.UpperArm);
|
||||
skeleton.Set(HumanBodyBones.RightLowerArm, bones, armRight.LowerArm);
|
||||
skeleton.Set(HumanBodyBones.RightHand, bones, armRight.Hand);
|
||||
|
||||
return skeleton;
|
||||
}
|
||||
|
||||
public Skeleton Detect(Bvh bvh)
|
||||
{
|
||||
var root = new BvhBone(bvh.Root.Name, Vector3.zero);
|
||||
root.Build(bvh.Root);
|
||||
return Detect(root.Traverse().Select(x => (IBone)x).ToList());
|
||||
}
|
||||
|
||||
public Skeleton Detect(Transform t)
|
||||
{
|
||||
var root = new BvhBone(t.name, Vector3.zero);
|
||||
root.Build(t);
|
||||
return Detect(root.Traverse().Select(x => (IBone)x).ToList());
|
||||
}
|
||||
}
|
||||
}
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using UnityEngine;
|
||||
|
||||
|
||||
namespace UniHumanoid
|
||||
{
|
||||
public interface ISkeletonDetector
|
||||
{
|
||||
Skeleton Detect(IList<IBone> bones);
|
||||
}
|
||||
|
||||
|
||||
public class BvhSkeletonEstimator : ISkeletonDetector
|
||||
{
|
||||
static IBone GetRoot(IList<IBone> bones)
|
||||
{
|
||||
var hips = bones.Where(x => x.Parent == null).ToArray();
|
||||
if (hips.Length != 1)
|
||||
{
|
||||
throw new System.Exception("Require unique root");
|
||||
}
|
||||
return hips[0];
|
||||
}
|
||||
|
||||
static IBone SelectBone(Func<IBone, IBone, IBone> selector, IList<IBone> bones)
|
||||
{
|
||||
if (bones == null || bones.Count == 0) throw new Exception("no bones");
|
||||
var current = bones[0];
|
||||
for (var i = 1; i < bones.Count; ++i)
|
||||
{
|
||||
current = selector(current, bones[i]);
|
||||
}
|
||||
return current;
|
||||
}
|
||||
|
||||
static void GetSpineAndHips(IBone hips, out IBone spine, out IBone leg_L, out IBone leg_R)
|
||||
{
|
||||
if (hips.Children.Count != 3) throw new System.Exception("Hips require 3 children");
|
||||
spine = SelectBone((l, r) => l.CenterOfDescendant().y > r.CenterOfDescendant().y ? l : r, hips.Children);
|
||||
leg_L = SelectBone((l, r) => l.CenterOfDescendant().x < r.CenterOfDescendant().x ? l : r, hips.Children);
|
||||
leg_R = SelectBone((l, r) => l.CenterOfDescendant().x > r.CenterOfDescendant().x ? l : r, hips.Children);
|
||||
}
|
||||
|
||||
static void GetNeckAndArms(IBone chest, out IBone neck, out IBone arm_L, out IBone arm_R)
|
||||
{
|
||||
if (chest.Children.Count != 3) throw new System.Exception("Chest require 3 children");
|
||||
neck = SelectBone((l, r) => l.CenterOfDescendant().y > r.CenterOfDescendant().y ? l : r, chest.Children);
|
||||
arm_L = SelectBone((l, r) => l.CenterOfDescendant().x < r.CenterOfDescendant().x ? l : r, chest.Children);
|
||||
arm_R = SelectBone((l, r) => l.CenterOfDescendant().x > r.CenterOfDescendant().x ? l : r, chest.Children);
|
||||
}
|
||||
|
||||
struct Arm
|
||||
{
|
||||
public IBone Shoulder;
|
||||
public IBone UpperArm;
|
||||
public IBone LowerArm;
|
||||
public IBone Hand;
|
||||
}
|
||||
|
||||
Arm GetArm(IBone shoulder)
|
||||
{
|
||||
var bones = shoulder.Traverse().ToArray();
|
||||
switch (bones.Length)
|
||||
{
|
||||
case 0:
|
||||
case 1:
|
||||
case 2:
|
||||
case 3:
|
||||
throw new NotImplementedException();
|
||||
|
||||
default:
|
||||
return new Arm
|
||||
{
|
||||
Shoulder = bones[0],
|
||||
UpperArm = bones[1],
|
||||
LowerArm = bones[2],
|
||||
Hand = bones[3],
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
struct Leg
|
||||
{
|
||||
public IBone UpperLeg;
|
||||
public IBone LowerLeg;
|
||||
public IBone Foot;
|
||||
public IBone Toes;
|
||||
}
|
||||
|
||||
Leg GetLeg(IBone leg)
|
||||
{
|
||||
var bones = leg.Traverse().Where(x => !x.Name.ToLower().Contains("buttock")).ToArray();
|
||||
switch (bones.Length)
|
||||
{
|
||||
case 0:
|
||||
case 1:
|
||||
case 2:
|
||||
throw new NotImplementedException();
|
||||
|
||||
case 3:
|
||||
return new Leg
|
||||
{
|
||||
UpperLeg = bones[0],
|
||||
LowerLeg = bones[1],
|
||||
Foot = bones[2],
|
||||
};
|
||||
|
||||
default:
|
||||
return new Leg
|
||||
{
|
||||
UpperLeg = bones[bones.Length - 4],
|
||||
LowerLeg = bones[bones.Length - 3],
|
||||
Foot = bones[bones.Length - 2],
|
||||
Toes = bones[bones.Length - 1],
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
public Skeleton Detect(IList<IBone> bones)
|
||||
{
|
||||
//
|
||||
// search bones
|
||||
//
|
||||
var root = GetRoot(bones);
|
||||
var hips = root.Traverse().First(x => x.Children.Count == 3);
|
||||
|
||||
IBone spine, hip_L, hip_R;
|
||||
GetSpineAndHips(hips, out spine, out hip_L, out hip_R);
|
||||
var legLeft = GetLeg(hip_L);
|
||||
var legRight = GetLeg(hip_R);
|
||||
|
||||
var spineToChest = new List<IBone>();
|
||||
foreach(var x in spine.Traverse())
|
||||
{
|
||||
spineToChest.Add(x);
|
||||
if (x.Children.Count == 3) break;
|
||||
}
|
||||
|
||||
IBone neck, shoulder_L, shoulder_R;
|
||||
GetNeckAndArms(spineToChest.Last(), out neck, out shoulder_L, out shoulder_R);
|
||||
var armLeft = GetArm(shoulder_L);
|
||||
var armRight = GetArm(shoulder_R);
|
||||
|
||||
var neckToHead = neck.Traverse().ToArray();
|
||||
|
||||
//
|
||||
// set result
|
||||
//
|
||||
var skeleton = new Skeleton();
|
||||
skeleton.Set(HumanBodyBones.Hips, bones, hips);
|
||||
|
||||
switch (spineToChest.Count)
|
||||
{
|
||||
case 0:
|
||||
throw new Exception();
|
||||
|
||||
case 1:
|
||||
skeleton.Set(HumanBodyBones.Spine, bones, spineToChest[0]);
|
||||
break;
|
||||
|
||||
case 2:
|
||||
skeleton.Set(HumanBodyBones.Spine, bones, spineToChest[0]);
|
||||
skeleton.Set(HumanBodyBones.Chest, bones, spineToChest[1]);
|
||||
break;
|
||||
|
||||
#if UNITY_5_6_OR_NEWER
|
||||
case 3:
|
||||
skeleton.Set(HumanBodyBones.Spine, bones, spineToChest[0]);
|
||||
skeleton.Set(HumanBodyBones.Chest, bones, spineToChest[1]);
|
||||
skeleton.Set(HumanBodyBones.UpperChest, bones, spineToChest[2]);
|
||||
break;
|
||||
#endif
|
||||
|
||||
default:
|
||||
skeleton.Set(HumanBodyBones.Spine, bones, spineToChest[0]);
|
||||
#if UNITY_5_6_OR_NEWER
|
||||
skeleton.Set(HumanBodyBones.Chest, bones, spineToChest[1]);
|
||||
skeleton.Set(HumanBodyBones.UpperChest, bones, spineToChest.Last());
|
||||
#else
|
||||
skeleton.Set(HumanBodyBones.Chest, bones, spineToChest.Last());
|
||||
#endif
|
||||
break;
|
||||
}
|
||||
|
||||
switch (neckToHead.Length)
|
||||
{
|
||||
case 0:
|
||||
throw new Exception();
|
||||
|
||||
case 1:
|
||||
skeleton.Set(HumanBodyBones.Head, bones, neckToHead[0]);
|
||||
break;
|
||||
|
||||
case 2:
|
||||
skeleton.Set(HumanBodyBones.Neck, bones, neckToHead[0]);
|
||||
skeleton.Set(HumanBodyBones.Head, bones, neckToHead[1]);
|
||||
break;
|
||||
|
||||
default:
|
||||
skeleton.Set(HumanBodyBones.Neck, bones, neckToHead[0]);
|
||||
skeleton.Set(HumanBodyBones.Head, bones, neckToHead.Where(x => x.Parent.Children.Count==1).Last());
|
||||
break;
|
||||
}
|
||||
|
||||
skeleton.Set(HumanBodyBones.LeftUpperLeg, bones, legLeft.UpperLeg);
|
||||
skeleton.Set(HumanBodyBones.LeftLowerLeg, bones, legLeft.LowerLeg);
|
||||
skeleton.Set(HumanBodyBones.LeftFoot, bones, legLeft.Foot);
|
||||
skeleton.Set(HumanBodyBones.LeftToes, bones, legLeft.Toes);
|
||||
|
||||
skeleton.Set(HumanBodyBones.RightUpperLeg, bones, legRight.UpperLeg);
|
||||
skeleton.Set(HumanBodyBones.RightLowerLeg, bones, legRight.LowerLeg);
|
||||
skeleton.Set(HumanBodyBones.RightFoot, bones, legRight.Foot);
|
||||
skeleton.Set(HumanBodyBones.RightToes, bones, legRight.Toes);
|
||||
|
||||
skeleton.Set(HumanBodyBones.LeftShoulder, bones, armLeft.Shoulder);
|
||||
skeleton.Set(HumanBodyBones.LeftUpperArm, bones, armLeft.UpperArm);
|
||||
skeleton.Set(HumanBodyBones.LeftLowerArm, bones, armLeft.LowerArm);
|
||||
skeleton.Set(HumanBodyBones.LeftHand, bones, armLeft.Hand);
|
||||
|
||||
skeleton.Set(HumanBodyBones.RightShoulder, bones, armRight.Shoulder);
|
||||
skeleton.Set(HumanBodyBones.RightUpperArm, bones, armRight.UpperArm);
|
||||
skeleton.Set(HumanBodyBones.RightLowerArm, bones, armRight.LowerArm);
|
||||
skeleton.Set(HumanBodyBones.RightHand, bones, armRight.Hand);
|
||||
|
||||
return skeleton;
|
||||
}
|
||||
|
||||
public Skeleton Detect(Bvh bvh)
|
||||
{
|
||||
var root = new BvhBone(bvh.Root.Name, Vector3.zero);
|
||||
root.Build(bvh.Root);
|
||||
return Detect(root.Traverse().Select(x => (IBone)x).ToList());
|
||||
}
|
||||
|
||||
public Skeleton Detect(Transform t)
|
||||
{
|
||||
var root = new BvhBone(t.name, Vector3.zero);
|
||||
root.Build(t);
|
||||
return Detect(root.Traverse().Select(x => (IBone)x).ToList());
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,232 +1,232 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using UnityEngine;
|
||||
|
||||
|
||||
namespace UniHumanoid
|
||||
{
|
||||
public static class SkeletonMeshUtility
|
||||
{
|
||||
class MeshBuilder
|
||||
{
|
||||
List<Vector3> m_positioins = 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 xWidth, float zWidth)
|
||||
{
|
||||
var dir = (tail - head).normalized;
|
||||
Vector3 xaxis;
|
||||
Vector3 zaxis;
|
||||
if (Vector3.Dot(dir, Vector3.forward) >= 1.0f - float.Epsilon)
|
||||
{
|
||||
xaxis = Vector3.right;
|
||||
zaxis = Vector3.down;
|
||||
}
|
||||
else
|
||||
{
|
||||
xaxis = Vector3.Cross(dir, Vector3.forward).normalized;
|
||||
zaxis = Vector3.forward;
|
||||
}
|
||||
AddBox((head+tail)*0.5f,
|
||||
xaxis*xWidth,
|
||||
(tail-head)*0.5f,
|
||||
zaxis*zWidth,
|
||||
boneIndex);
|
||||
}
|
||||
|
||||
void AddBox(Vector3 center, Vector3 xaxis, Vector3 yaxis, Vector3 zaxis, int boneIndex)
|
||||
{
|
||||
AddQuad(
|
||||
center - yaxis - xaxis - zaxis,
|
||||
center - yaxis + xaxis - zaxis,
|
||||
center - yaxis + xaxis + zaxis,
|
||||
center - yaxis - xaxis + zaxis,
|
||||
boneIndex);
|
||||
AddQuad(
|
||||
center + yaxis - xaxis - zaxis,
|
||||
center + yaxis + xaxis - zaxis,
|
||||
center + yaxis + xaxis + zaxis,
|
||||
center + yaxis - xaxis + zaxis,
|
||||
boneIndex, true);
|
||||
AddQuad(
|
||||
center - xaxis - yaxis - zaxis,
|
||||
center - xaxis + yaxis - zaxis,
|
||||
center - xaxis + yaxis + zaxis,
|
||||
center - xaxis - yaxis + zaxis,
|
||||
boneIndex, true);
|
||||
AddQuad(
|
||||
center + xaxis - yaxis - zaxis,
|
||||
center + xaxis + yaxis - zaxis,
|
||||
center + xaxis + yaxis + zaxis,
|
||||
center + xaxis - yaxis + zaxis,
|
||||
boneIndex);
|
||||
AddQuad(
|
||||
center - zaxis - xaxis - yaxis,
|
||||
center - zaxis + xaxis - yaxis,
|
||||
center - zaxis + xaxis + yaxis,
|
||||
center - zaxis - xaxis + yaxis,
|
||||
boneIndex, true);
|
||||
AddQuad(
|
||||
center + zaxis - xaxis - yaxis,
|
||||
center + zaxis + xaxis - yaxis,
|
||||
center + zaxis + xaxis + yaxis,
|
||||
center + zaxis - xaxis + yaxis,
|
||||
boneIndex);
|
||||
}
|
||||
|
||||
void AddQuad(Vector3 v0, Vector3 v1, Vector3 v2, Vector3 v3, int boneIndex, bool reverse=false)
|
||||
{
|
||||
var i = m_positioins.Count;
|
||||
m_positioins.Add(v0);
|
||||
m_positioins.Add(v1);
|
||||
m_positioins.Add(v2);
|
||||
m_positioins.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);
|
||||
|
||||
if (reverse)
|
||||
{
|
||||
m_indices.Add(i + 3);
|
||||
m_indices.Add(i + 2);
|
||||
m_indices.Add(i + 1);
|
||||
|
||||
m_indices.Add(i + 1);
|
||||
m_indices.Add(i);
|
||||
m_indices.Add(i + 3);
|
||||
}
|
||||
else
|
||||
{
|
||||
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_positioins);
|
||||
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 XWidth;
|
||||
public float ZWidth;
|
||||
|
||||
public BoneHeadTail(HumanBodyBones head, HumanBodyBones tail, float xWidth = 0.05f, float zWidth = 0.05f)
|
||||
{
|
||||
Head = head;
|
||||
Tail = tail;
|
||||
TailOffset = Vector3.zero;
|
||||
XWidth = xWidth;
|
||||
ZWidth = zWidth;
|
||||
}
|
||||
|
||||
public BoneHeadTail(HumanBodyBones head, Vector3 tailOffset, float xWidth = 0.05f, float zWidth = 0.05f)
|
||||
{
|
||||
Head = head;
|
||||
Tail = HumanBodyBones.LastBone;
|
||||
TailOffset = tailOffset;
|
||||
XWidth = xWidth;
|
||||
ZWidth = zWidth;
|
||||
}
|
||||
}
|
||||
|
||||
static BoneHeadTail[] Bones = new BoneHeadTail[]
|
||||
{
|
||||
new BoneHeadTail(HumanBodyBones.Hips, HumanBodyBones.Spine, 0.1f, 0.06f),
|
||||
new BoneHeadTail(HumanBodyBones.Spine, HumanBodyBones.Chest),
|
||||
new BoneHeadTail(HumanBodyBones.Chest, HumanBodyBones.Neck, 0.1f, 0.06f),
|
||||
new BoneHeadTail(HumanBodyBones.Neck, HumanBodyBones.Head, 0.03f, 0.03f),
|
||||
new BoneHeadTail(HumanBodyBones.Head, new Vector3(0, 0.1f, 0), 0.1f, 0.1f),
|
||||
|
||||
new BoneHeadTail(HumanBodyBones.LeftShoulder, HumanBodyBones.LeftUpperArm),
|
||||
new BoneHeadTail(HumanBodyBones.LeftUpperArm, HumanBodyBones.LeftLowerArm),
|
||||
new BoneHeadTail(HumanBodyBones.LeftLowerArm, HumanBodyBones.LeftHand),
|
||||
new BoneHeadTail(HumanBodyBones.LeftHand, new Vector3(-0.1f, 0, 0)),
|
||||
|
||||
new BoneHeadTail(HumanBodyBones.LeftUpperLeg, HumanBodyBones.LeftLowerLeg),
|
||||
new BoneHeadTail(HumanBodyBones.LeftLowerLeg, HumanBodyBones.LeftFoot),
|
||||
new BoneHeadTail(HumanBodyBones.LeftFoot, HumanBodyBones.LeftToes),
|
||||
new BoneHeadTail(HumanBodyBones.LeftToes, new Vector3(0, 0, 0.1f)),
|
||||
|
||||
new BoneHeadTail(HumanBodyBones.RightShoulder, HumanBodyBones.RightUpperArm),
|
||||
new BoneHeadTail(HumanBodyBones.RightUpperArm, HumanBodyBones.RightLowerArm),
|
||||
new BoneHeadTail(HumanBodyBones.RightLowerArm, HumanBodyBones.RightHand),
|
||||
new BoneHeadTail(HumanBodyBones.RightHand, new Vector3(0.1f, 0, 0)),
|
||||
|
||||
new BoneHeadTail(HumanBodyBones.RightUpperLeg, HumanBodyBones.RightLowerLeg),
|
||||
new BoneHeadTail(HumanBodyBones.RightLowerLeg, HumanBodyBones.RightFoot),
|
||||
new BoneHeadTail(HumanBodyBones.RightFoot, HumanBodyBones.RightToes),
|
||||
new BoneHeadTail(HumanBodyBones.RightToes, new Vector3(0, 0, 0.1f)),
|
||||
};
|
||||
|
||||
public static SkinnedMeshRenderer CreateRenderer(Animator animator)
|
||||
{
|
||||
//var bodyBones = (HumanBodyBones[])Enum.GetValues(typeof(HumanBodyBones));
|
||||
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.XWidth, headTail.ZWidth);
|
||||
}
|
||||
else
|
||||
{
|
||||
builder.AddBone(head.position, head.position + headTail.TailOffset, bones.IndexOf(head), headTail.XWidth, headTail.ZWidth);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
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;
|
||||
}
|
||||
}
|
||||
}
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using UnityEngine;
|
||||
|
||||
|
||||
namespace UniHumanoid
|
||||
{
|
||||
public static class SkeletonMeshUtility
|
||||
{
|
||||
class MeshBuilder
|
||||
{
|
||||
List<Vector3> m_positioins = 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 xWidth, float zWidth)
|
||||
{
|
||||
var dir = (tail - head).normalized;
|
||||
Vector3 xaxis;
|
||||
Vector3 zaxis;
|
||||
if (Vector3.Dot(dir, Vector3.forward) >= 1.0f - float.Epsilon)
|
||||
{
|
||||
xaxis = Vector3.right;
|
||||
zaxis = Vector3.down;
|
||||
}
|
||||
else
|
||||
{
|
||||
xaxis = Vector3.Cross(dir, Vector3.forward).normalized;
|
||||
zaxis = Vector3.forward;
|
||||
}
|
||||
AddBox((head+tail)*0.5f,
|
||||
xaxis*xWidth,
|
||||
(tail-head)*0.5f,
|
||||
zaxis*zWidth,
|
||||
boneIndex);
|
||||
}
|
||||
|
||||
void AddBox(Vector3 center, Vector3 xaxis, Vector3 yaxis, Vector3 zaxis, int boneIndex)
|
||||
{
|
||||
AddQuad(
|
||||
center - yaxis - xaxis - zaxis,
|
||||
center - yaxis + xaxis - zaxis,
|
||||
center - yaxis + xaxis + zaxis,
|
||||
center - yaxis - xaxis + zaxis,
|
||||
boneIndex);
|
||||
AddQuad(
|
||||
center + yaxis - xaxis - zaxis,
|
||||
center + yaxis + xaxis - zaxis,
|
||||
center + yaxis + xaxis + zaxis,
|
||||
center + yaxis - xaxis + zaxis,
|
||||
boneIndex, true);
|
||||
AddQuad(
|
||||
center - xaxis - yaxis - zaxis,
|
||||
center - xaxis + yaxis - zaxis,
|
||||
center - xaxis + yaxis + zaxis,
|
||||
center - xaxis - yaxis + zaxis,
|
||||
boneIndex, true);
|
||||
AddQuad(
|
||||
center + xaxis - yaxis - zaxis,
|
||||
center + xaxis + yaxis - zaxis,
|
||||
center + xaxis + yaxis + zaxis,
|
||||
center + xaxis - yaxis + zaxis,
|
||||
boneIndex);
|
||||
AddQuad(
|
||||
center - zaxis - xaxis - yaxis,
|
||||
center - zaxis + xaxis - yaxis,
|
||||
center - zaxis + xaxis + yaxis,
|
||||
center - zaxis - xaxis + yaxis,
|
||||
boneIndex, true);
|
||||
AddQuad(
|
||||
center + zaxis - xaxis - yaxis,
|
||||
center + zaxis + xaxis - yaxis,
|
||||
center + zaxis + xaxis + yaxis,
|
||||
center + zaxis - xaxis + yaxis,
|
||||
boneIndex);
|
||||
}
|
||||
|
||||
void AddQuad(Vector3 v0, Vector3 v1, Vector3 v2, Vector3 v3, int boneIndex, bool reverse=false)
|
||||
{
|
||||
var i = m_positioins.Count;
|
||||
m_positioins.Add(v0);
|
||||
m_positioins.Add(v1);
|
||||
m_positioins.Add(v2);
|
||||
m_positioins.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);
|
||||
|
||||
if (reverse)
|
||||
{
|
||||
m_indices.Add(i + 3);
|
||||
m_indices.Add(i + 2);
|
||||
m_indices.Add(i + 1);
|
||||
|
||||
m_indices.Add(i + 1);
|
||||
m_indices.Add(i);
|
||||
m_indices.Add(i + 3);
|
||||
}
|
||||
else
|
||||
{
|
||||
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_positioins);
|
||||
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 XWidth;
|
||||
public float ZWidth;
|
||||
|
||||
public BoneHeadTail(HumanBodyBones head, HumanBodyBones tail, float xWidth = 0.05f, float zWidth = 0.05f)
|
||||
{
|
||||
Head = head;
|
||||
Tail = tail;
|
||||
TailOffset = Vector3.zero;
|
||||
XWidth = xWidth;
|
||||
ZWidth = zWidth;
|
||||
}
|
||||
|
||||
public BoneHeadTail(HumanBodyBones head, Vector3 tailOffset, float xWidth = 0.05f, float zWidth = 0.05f)
|
||||
{
|
||||
Head = head;
|
||||
Tail = HumanBodyBones.LastBone;
|
||||
TailOffset = tailOffset;
|
||||
XWidth = xWidth;
|
||||
ZWidth = zWidth;
|
||||
}
|
||||
}
|
||||
|
||||
static BoneHeadTail[] Bones = new BoneHeadTail[]
|
||||
{
|
||||
new BoneHeadTail(HumanBodyBones.Hips, HumanBodyBones.Spine, 0.1f, 0.06f),
|
||||
new BoneHeadTail(HumanBodyBones.Spine, HumanBodyBones.Chest),
|
||||
new BoneHeadTail(HumanBodyBones.Chest, HumanBodyBones.Neck, 0.1f, 0.06f),
|
||||
new BoneHeadTail(HumanBodyBones.Neck, HumanBodyBones.Head, 0.03f, 0.03f),
|
||||
new BoneHeadTail(HumanBodyBones.Head, new Vector3(0, 0.1f, 0), 0.1f, 0.1f),
|
||||
|
||||
new BoneHeadTail(HumanBodyBones.LeftShoulder, HumanBodyBones.LeftUpperArm),
|
||||
new BoneHeadTail(HumanBodyBones.LeftUpperArm, HumanBodyBones.LeftLowerArm),
|
||||
new BoneHeadTail(HumanBodyBones.LeftLowerArm, HumanBodyBones.LeftHand),
|
||||
new BoneHeadTail(HumanBodyBones.LeftHand, new Vector3(-0.1f, 0, 0)),
|
||||
|
||||
new BoneHeadTail(HumanBodyBones.LeftUpperLeg, HumanBodyBones.LeftLowerLeg),
|
||||
new BoneHeadTail(HumanBodyBones.LeftLowerLeg, HumanBodyBones.LeftFoot),
|
||||
new BoneHeadTail(HumanBodyBones.LeftFoot, HumanBodyBones.LeftToes),
|
||||
new BoneHeadTail(HumanBodyBones.LeftToes, new Vector3(0, 0, 0.1f)),
|
||||
|
||||
new BoneHeadTail(HumanBodyBones.RightShoulder, HumanBodyBones.RightUpperArm),
|
||||
new BoneHeadTail(HumanBodyBones.RightUpperArm, HumanBodyBones.RightLowerArm),
|
||||
new BoneHeadTail(HumanBodyBones.RightLowerArm, HumanBodyBones.RightHand),
|
||||
new BoneHeadTail(HumanBodyBones.RightHand, new Vector3(0.1f, 0, 0)),
|
||||
|
||||
new BoneHeadTail(HumanBodyBones.RightUpperLeg, HumanBodyBones.RightLowerLeg),
|
||||
new BoneHeadTail(HumanBodyBones.RightLowerLeg, HumanBodyBones.RightFoot),
|
||||
new BoneHeadTail(HumanBodyBones.RightFoot, HumanBodyBones.RightToes),
|
||||
new BoneHeadTail(HumanBodyBones.RightToes, new Vector3(0, 0, 0.1f)),
|
||||
};
|
||||
|
||||
public static SkinnedMeshRenderer CreateRenderer(Animator animator)
|
||||
{
|
||||
//var bodyBones = (HumanBodyBones[])Enum.GetValues(typeof(HumanBodyBones));
|
||||
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.XWidth, headTail.ZWidth);
|
||||
}
|
||||
else
|
||||
{
|
||||
builder.AddBone(head.position, head.position + headTail.TailOffset, bones.IndexOf(head), headTail.XWidth, headTail.ZWidth);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
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;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
Before Width: | Height: | Size: 64 KiB After Width: | Height: | Size: 64 KiB |
|
Before Width: | Height: | Size: 29 KiB After Width: | Height: | Size: 29 KiB |
|
Before Width: | Height: | Size: 7.6 KiB After Width: | Height: | Size: 7.6 KiB |
|
Before Width: | Height: | Size: 37 KiB After Width: | Height: | Size: 37 KiB |
|
Before Width: | Height: | Size: 28 KiB After Width: | Height: | Size: 28 KiB |
|
Before Width: | Height: | Size: 3.3 KiB After Width: | Height: | Size: 3.3 KiB |
|
Before Width: | Height: | Size: 696 KiB After Width: | Height: | Size: 696 KiB |
|
Before Width: | Height: | Size: 69 KiB After Width: | Height: | Size: 69 KiB |
|
Before Width: | Height: | Size: 38 KiB After Width: | Height: | Size: 38 KiB |
|
Before Width: | Height: | Size: 90 KiB After Width: | Height: | Size: 90 KiB |