Move UniHumanoid to Assets/*

This commit is contained in:
yutopp
2018-12-28 22:28:17 +09:00
parent e6f3576eb2
commit 75b4d54839
101 changed files with 4968 additions and 4968 deletions

View File

@@ -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;
}
}
}
}

View File

@@ -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);
}
}
}

View File

@@ -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);
}
}

View File

@@ -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
![humanpose transfer target](doc/humanpose_transfer_inspector.png)
![humanpose transfer](doc/humanpose_transfer.png)
# 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
![bvh prefab](doc/assets.png)
Instanciate prefab to scene.
![bvh gameobject](doc/mesh.png)
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.
![bvh bone mapping](doc/bvh_bonemapping.png)
These humanoids imported by [UniGLTF](https://github.com/ousttrue/UniGLTF) and created human avatar by BoneMapping.
![humanoid](doc/humanoid.gif)
# 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
![humanpose transfer target](doc/humanpose_transfer_inspector.png)
![humanpose transfer](doc/humanpose_transfer.png)
# 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
![bvh prefab](doc/assets.png)
Instanciate prefab to scene.
![bvh gameobject](doc/mesh.png)
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.
![bvh bone mapping](doc/bvh_bonemapping.png)
These humanoids imported by [UniGLTF](https://github.com/ousttrue/UniGLTF) and created human avatar by BoneMapping.
![humanoid](doc/humanoid.gif)
# 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/

View File

@@ -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;
}
}
}
}

View File

@@ -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;
}
}
}
}

View File

@@ -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;
}
}
}

View File

@@ -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
}
}

View File

@@ -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
}
}
}

View File

@@ -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();
}
}
}
}

View File

@@ -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;
}
}
}
}
}

View File

@@ -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();
}
}
}
}
}

View File

@@ -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();
}
}
}

View File

@@ -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);
}
}
}
}
}
}

View File

@@ -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;
}
}
}

View File

@@ -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();
}
}
}

View File

@@ -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;
}
}
}
}

View File

@@ -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;
}
}
}

View File

@@ -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;
}
}
}

View File

@@ -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();
}
}
}

View File

@@ -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
}
}
}
}

View File

@@ -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);
}
}
}

View File

@@ -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;
}
}
}

View File

@@ -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
}

View File

@@ -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
}
}
}

View File

@@ -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());
}
}
}

View File

@@ -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;
}
}
}

View File

Before

Width:  |  Height:  |  Size: 64 KiB

After

Width:  |  Height:  |  Size: 64 KiB

View File

Before

Width:  |  Height:  |  Size: 29 KiB

After

Width:  |  Height:  |  Size: 29 KiB

View File

Before

Width:  |  Height:  |  Size: 7.6 KiB

After

Width:  |  Height:  |  Size: 7.6 KiB

View File

Before

Width:  |  Height:  |  Size: 37 KiB

After

Width:  |  Height:  |  Size: 37 KiB

View File

Before

Width:  |  Height:  |  Size: 28 KiB

After

Width:  |  Height:  |  Size: 28 KiB

View File

Before

Width:  |  Height:  |  Size: 3.3 KiB

After

Width:  |  Height:  |  Size: 3.3 KiB

View File

Before

Width:  |  Height:  |  Size: 696 KiB

After

Width:  |  Height:  |  Size: 696 KiB

View File

Before

Width:  |  Height:  |  Size: 69 KiB

After

Width:  |  Height:  |  Size: 69 KiB

View File

Before

Width:  |  Height:  |  Size: 38 KiB

After

Width:  |  Height:  |  Size: 38 KiB

View File

Before

Width:  |  Height:  |  Size: 90 KiB

After

Width:  |  Height:  |  Size: 90 KiB

Some files were not shown because too many files have changed in this diff Show More