mirror of
https://github.com/vrm-c/UniVRM.git
synced 2026-09-08 20:08:53 -05:00
rename NormalizedPoseProvider to AnimatorPoseProvider. fix Bvh height
This commit is contained in:
@@ -99,6 +99,18 @@ namespace UniHumanoid
|
||||
Children = new List<BvhNode>();
|
||||
}
|
||||
|
||||
public int GetChannelIndex(Channel channel)
|
||||
{
|
||||
for (int i = 0; i < Channels.Length; ++i)
|
||||
{
|
||||
if (channel == Channels[i])
|
||||
{
|
||||
return i;
|
||||
}
|
||||
}
|
||||
throw new KeyNotFoundException();
|
||||
}
|
||||
|
||||
public virtual void Parse(StringReader r)
|
||||
{
|
||||
Offset = ParseOffset(r.ReadLine());
|
||||
|
||||
@@ -75,11 +75,15 @@ namespace UniHumanoid
|
||||
//
|
||||
// scaling. reposition
|
||||
//
|
||||
var yCh = Bvh.Root.GetChannelIndex(Channel.Yposition);
|
||||
var curve = Bvh.Channels[yCh];
|
||||
var hipHeight = curve.Keys[0];
|
||||
|
||||
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;
|
||||
// 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())
|
||||
|
||||
@@ -33,10 +33,11 @@ namespace UniVRM10
|
||||
|
||||
private readonly Quaternion _initialTargetLocalRotation;
|
||||
private readonly Quaternion _initialTargetGlobalRotation;
|
||||
public Vector3 InitialTargetGlobalPosition { get; }
|
||||
private readonly List<Vrm10ControlBone> _children = new List<Vrm10ControlBone>();
|
||||
public IReadOnlyList<Vrm10ControlBone> Children => _children;
|
||||
|
||||
private Vrm10ControlBone(Transform controlTarget, HumanBodyBones boneType, Vrm10ControlBone parent)
|
||||
private Vrm10ControlBone(Transform controlTarget, HumanBodyBones boneType, Vrm10ControlBone parent, Transform root)
|
||||
{
|
||||
if (boneType == HumanBodyBones.LastBone)
|
||||
{
|
||||
@@ -62,6 +63,7 @@ namespace UniVRM10
|
||||
|
||||
_initialTargetLocalRotation = controlTarget.localRotation;
|
||||
_initialTargetGlobalRotation = controlTarget.rotation;
|
||||
InitialTargetGlobalPosition = root.worldToLocalMatrix.MultiplyPoint(controlTarget.position);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -76,32 +78,32 @@ namespace UniVRM10
|
||||
}
|
||||
}
|
||||
|
||||
public static Vrm10ControlBone Build(UniHumanoid.Humanoid humanoid, out Dictionary<HumanBodyBones, Vrm10ControlBone> boneMap)
|
||||
public static Vrm10ControlBone Build(UniHumanoid.Humanoid humanoid, out Dictionary<HumanBodyBones, Vrm10ControlBone> boneMap, Transform root)
|
||||
{
|
||||
var hips = new Vrm10ControlBone(humanoid.Hips, HumanBodyBones.Hips, null);
|
||||
var hips = new Vrm10ControlBone(humanoid.Hips, HumanBodyBones.Hips, null, root);
|
||||
boneMap = new Dictionary<HumanBodyBones, Vrm10ControlBone>();
|
||||
boneMap.Add(HumanBodyBones.Hips, hips);
|
||||
|
||||
foreach (Transform child in humanoid.Hips)
|
||||
{
|
||||
BuildRecursively(humanoid, child, hips, boneMap);
|
||||
BuildRecursively(humanoid, child, hips, boneMap, root);
|
||||
}
|
||||
|
||||
return hips;
|
||||
}
|
||||
|
||||
private static void BuildRecursively(UniHumanoid.Humanoid humanoid, Transform current, Vrm10ControlBone parent, Dictionary<HumanBodyBones, Vrm10ControlBone> boneMap)
|
||||
private static void BuildRecursively(UniHumanoid.Humanoid humanoid, Transform current, Vrm10ControlBone parent, Dictionary<HumanBodyBones, Vrm10ControlBone> boneMap, Transform root)
|
||||
{
|
||||
if (humanoid.TryGetBoneForTransform(current, out var bone))
|
||||
{
|
||||
var newBone = new Vrm10ControlBone(current, bone, parent);
|
||||
var newBone = new Vrm10ControlBone(current, bone, parent, root);
|
||||
parent = newBone;
|
||||
boneMap.Add(bone, newBone);
|
||||
}
|
||||
|
||||
foreach (Transform child in current)
|
||||
{
|
||||
BuildRecursively(humanoid, child, parent, boneMap);
|
||||
BuildRecursively(humanoid, child, parent, boneMap, root);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -35,7 +35,7 @@ namespace UniVRM10
|
||||
_controlRigRoot = new GameObject("Runtime Control Rig").transform;
|
||||
_controlRigRoot.SetParent(vrmRoot);
|
||||
|
||||
_hipBone = Vrm10ControlBone.Build(humanoid, out _bones);
|
||||
_hipBone = Vrm10ControlBone.Build(humanoid, out _bones, _controlRigRoot);
|
||||
_hipBone.ControlBone.SetParent(_controlRigRoot);
|
||||
|
||||
HipTPoseWorldPosition = vrmRoot.worldToLocalMatrix.MultiplyPoint(_hipBone.ControlTarget.position);
|
||||
@@ -72,19 +72,11 @@ namespace UniVRM10
|
||||
}
|
||||
}
|
||||
|
||||
public void EnforceTPose()
|
||||
{
|
||||
SetHipsPosition(_hipBone.ControlBone.position);
|
||||
foreach (var bone in _bones.Values)
|
||||
{
|
||||
bone.ControlBone.localRotation = Quaternion.identity;
|
||||
}
|
||||
}
|
||||
|
||||
#region INormalizedPoseApplicable
|
||||
public void SetHipsPosition(Vector3 position)
|
||||
{
|
||||
// TODO: scale model local position
|
||||
_hipBone.ControlTarget.position = position;
|
||||
var world = _controlRigRoot.TransformPoint(position);
|
||||
_hipBone.ControlBone.position = world;
|
||||
}
|
||||
|
||||
public void SetNormalizedLocalRotation(HumanBodyBones bone, Quaternion normalizedLocalRotation)
|
||||
@@ -94,6 +86,7 @@ namespace UniVRM10
|
||||
t.ControlBone.localRotation = normalizedLocalRotation;
|
||||
}
|
||||
}
|
||||
#endregion
|
||||
|
||||
IEnumerable<(HumanBodyBones Head, HumanBodyBones Parent)> Traverse(Vrm10ControlBone bone, Vrm10ControlBone parent = null)
|
||||
{
|
||||
@@ -108,6 +101,7 @@ namespace UniVRM10
|
||||
}
|
||||
}
|
||||
|
||||
#region ITPoseProvider
|
||||
public IEnumerable<(HumanBodyBones Head, HumanBodyBones Parent)> EnumerateBones()
|
||||
{
|
||||
foreach (var headParent in Traverse(_hipBone))
|
||||
@@ -122,5 +116,11 @@ namespace UniVRM10
|
||||
{
|
||||
return Quaternion.identity;
|
||||
}
|
||||
|
||||
public Vector3 GetBoneTPoseWorldPosition(HumanBodyBones bone)
|
||||
{
|
||||
return _bones[bone].InitialTargetGlobalPosition;
|
||||
}
|
||||
#endregion
|
||||
}
|
||||
}
|
||||
|
||||
84
Assets/VRM10/Runtime/ControlRig/AnimatorPoseProvider.cs
Normal file
84
Assets/VRM10/Runtime/ControlRig/AnimatorPoseProvider.cs
Normal file
@@ -0,0 +1,84 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using UnityEngine;
|
||||
|
||||
namespace UniVRM10
|
||||
{
|
||||
/// <summary>
|
||||
/// Animator から Pose 供給する。
|
||||
/// この Animator は以下の条件を満たすこと。
|
||||
///
|
||||
/// * TPoseであること
|
||||
/// * 正規化済みであること
|
||||
///
|
||||
/// </summary>
|
||||
public sealed class AnimatorPoseProvider : INormalizedPoseProvider, ITPoseProvider
|
||||
{
|
||||
Transform m_root;
|
||||
Animator m_animator;
|
||||
Dictionary<HumanBodyBones, Vector3> m_posMap = new Dictionary<HumanBodyBones, Vector3>();
|
||||
|
||||
public AnimatorPoseProvider(Transform root, Animator animator)
|
||||
{
|
||||
m_root = root;
|
||||
m_animator = animator;
|
||||
|
||||
var hips = animator.GetBoneTransform(HumanBodyBones.Hips);
|
||||
HipTPoseWorldPosition = root.worldToLocalMatrix.MultiplyPoint(hips.position);
|
||||
|
||||
foreach (HumanBodyBones bone in Enum.GetValues(typeof(HumanBodyBones)))
|
||||
{
|
||||
if(bone==HumanBodyBones.LastBone)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
var t = animator.GetBoneTransform(bone);
|
||||
if (t != null)
|
||||
{
|
||||
m_posMap[bone] = root.worldToLocalMatrix.MultiplyPoint(t.position);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#region INormalizedPoseProvider
|
||||
public Quaternion GetNormalizedLocalRotation(HumanBodyBones bone, HumanBodyBones parentBone)
|
||||
{
|
||||
if (m_animator.GetBoneTransform(bone) is Transform t)
|
||||
{
|
||||
// TODO: parentBone relative
|
||||
return t.localRotation;
|
||||
}
|
||||
else
|
||||
{
|
||||
// Debug.LogWarning($"{bone} not found");
|
||||
return Quaternion.identity;
|
||||
}
|
||||
}
|
||||
|
||||
public Vector3 GetHipsPosition()
|
||||
{
|
||||
// TODO: from model root ?
|
||||
return m_animator.GetBoneTransform(HumanBodyBones.Hips).localPosition;
|
||||
}
|
||||
#endregion
|
||||
|
||||
#region ITPoseProvider
|
||||
public Vector3 HipTPoseWorldPosition { get; }
|
||||
|
||||
public Quaternion GetBoneTPoseWorldRotation(HumanBodyBones bone)
|
||||
{
|
||||
throw new System.NotImplementedException();
|
||||
}
|
||||
|
||||
public IEnumerable<(HumanBodyBones Head, HumanBodyBones Parent)> EnumerateBones()
|
||||
{
|
||||
throw new System.NotImplementedException();
|
||||
}
|
||||
|
||||
public Vector3 GetBoneTPoseWorldPosition(HumanBodyBones bone)
|
||||
{
|
||||
return m_posMap[bone];
|
||||
}
|
||||
#endregion
|
||||
}
|
||||
}
|
||||
@@ -12,12 +12,20 @@ namespace UniVRM10
|
||||
|
||||
/// <summary>
|
||||
/// * world は ModelRoot を意図していることに注意
|
||||
/// * bone 無いときはどう振る舞うべきか
|
||||
/// * bone 無いときは Quaternion.Identity ?
|
||||
/// </summary>
|
||||
/// <param name="bone"></param>
|
||||
/// <returns></returns>
|
||||
Quaternion GetBoneTPoseWorldRotation(HumanBodyBones bone);
|
||||
|
||||
/// <summary>
|
||||
/// * world は ModelRoot を意図していることに注意
|
||||
/// * bone 無いときは Vector3.zero ?
|
||||
/// </summary>
|
||||
/// <param name="bone"></param>
|
||||
/// <returns></returns>
|
||||
Vector3 GetBoneTPoseWorldPosition(HumanBodyBones bone);
|
||||
|
||||
/// <summary>
|
||||
/// ボーンを親ボーンとセットで列挙する</returns>
|
||||
/// </summary>
|
||||
|
||||
@@ -65,5 +65,10 @@ namespace UniVRM10
|
||||
{
|
||||
throw new System.NotImplementedException();
|
||||
}
|
||||
|
||||
public Vector3 GetBoneTPoseWorldPosition(HumanBodyBones bone)
|
||||
{
|
||||
throw new System.NotImplementedException();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,54 +0,0 @@
|
||||
using System.Collections.Generic;
|
||||
using UnityEngine;
|
||||
|
||||
namespace UniVRM10
|
||||
{
|
||||
/// <summary>
|
||||
/// 正規化済みのヒエラルキーの getter。
|
||||
/// localRotation をコピーするだけなのだが、
|
||||
/// GetNormalizedLocalRotation にて、ボーンの有無(upperChestなど)の違いの対応をする予定(未実装)。
|
||||
/// </summary>
|
||||
public sealed class NormalizedPoseProvider : INormalizedPoseProvider, ITPoseProvider
|
||||
{
|
||||
Transform m_root;
|
||||
Animator m_animator;
|
||||
|
||||
public Vector3 HipTPoseWorldPosition => throw new System.NotImplementedException();
|
||||
|
||||
public NormalizedPoseProvider(Transform root, Animator animator)
|
||||
{
|
||||
m_root = root;
|
||||
m_animator = animator;
|
||||
}
|
||||
|
||||
public Quaternion GetNormalizedLocalRotation(HumanBodyBones bone, HumanBodyBones parentBone)
|
||||
{
|
||||
if (m_animator.GetBoneTransform(bone) is Transform t)
|
||||
{
|
||||
// TODO: parentBone relative
|
||||
return t.localRotation;
|
||||
}
|
||||
else
|
||||
{
|
||||
// Debug.LogWarning($"{bone} not found");
|
||||
return Quaternion.identity;
|
||||
}
|
||||
}
|
||||
|
||||
public Vector3 GetHipsPosition()
|
||||
{
|
||||
// TODO: from model root ?
|
||||
return m_animator.GetBoneTransform(HumanBodyBones.Hips).localPosition;
|
||||
}
|
||||
|
||||
public Quaternion GetBoneTPoseWorldRotation(HumanBodyBones bone)
|
||||
{
|
||||
throw new System.NotImplementedException();
|
||||
}
|
||||
|
||||
public IEnumerable<(HumanBodyBones Head, HumanBodyBones Parent)> EnumerateBones()
|
||||
{
|
||||
throw new System.NotImplementedException();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -88,11 +88,5 @@ namespace UniVRM10.VRM10Viewer
|
||||
// destroy GameObject
|
||||
GameObject.Destroy(m_instance.gameObject);
|
||||
}
|
||||
|
||||
public void TPoseControlRig()
|
||||
{
|
||||
var controlRig = m_controller.Runtime.ControlRig;
|
||||
controlRig.EnforceTPose();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -23,7 +23,7 @@ namespace UniVRM10.VRM10Viewer
|
||||
public VRM10Motion(UniHumanoid.BvhImporterContext context)
|
||||
{
|
||||
m_context = context;
|
||||
var provider = new NormalizedPoseProvider(m_context.Root.transform, m_context.Root.GetComponent<Animator>());
|
||||
var provider = new AnimatorPoseProvider(m_context.Root.transform, m_context.Root.GetComponent<Animator>());
|
||||
ControlRig = (provider, provider);
|
||||
}
|
||||
|
||||
@@ -199,10 +199,5 @@ namespace UniVRM10.VRM10Viewer
|
||||
return motion;
|
||||
}
|
||||
}
|
||||
|
||||
public void Retarget(Vrm10RuntimeControlRig dst)
|
||||
{
|
||||
VRM10Retarget.Retarget(ControlRig, (dst, dst));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,3 +1,5 @@
|
||||
using UnityEngine;
|
||||
|
||||
namespace UniVRM10
|
||||
{
|
||||
public static class VRM10Retarget
|
||||
@@ -9,7 +11,21 @@ namespace UniVRM10
|
||||
var q = source.Pose.GetNormalizedLocalRotation(head, parent);
|
||||
sink.Pose.SetNormalizedLocalRotation(head, q);
|
||||
}
|
||||
sink.Pose.SetHipsPosition(source.Pose.GetHipsPosition());
|
||||
|
||||
// scaling hips position
|
||||
var scaling = sink.TPose.GetBoneTPoseWorldPosition(HumanBodyBones.LeftUpperLeg).y / source.TPose.GetBoneTPoseWorldPosition(HumanBodyBones.LeftUpperLeg).y;
|
||||
var delta = source.Pose.GetHipsPosition() - source.TPose.HipTPoseWorldPosition;
|
||||
sink.Pose.SetHipsPosition(sink.TPose.HipTPoseWorldPosition + delta * scaling);
|
||||
}
|
||||
|
||||
public static void EnforceTPose((INormalizedPoseApplicable Pose, ITPoseProvider TPose) sink)
|
||||
{
|
||||
foreach (var (head, parent) in sink.TPose.EnumerateBones())
|
||||
{
|
||||
sink.Pose.SetNormalizedLocalRotation(head, Quaternion.identity);
|
||||
}
|
||||
|
||||
sink.Pose.SetHipsPosition(sink.TPose.HipTPoseWorldPosition);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -237,11 +237,11 @@ namespace UniVRM10.VRM10Viewer
|
||||
{
|
||||
if (m_ui.IsBvhEnabled && m_src != null)
|
||||
{
|
||||
m_src.Retarget(m_loaded.ControlRig);
|
||||
VRM10Retarget.Retarget(m_src.ControlRig, (m_loaded.ControlRig, m_loaded.ControlRig));
|
||||
}
|
||||
else
|
||||
{
|
||||
m_loaded.TPoseControlRig();
|
||||
VRM10Retarget.EnforceTPose((m_loaded.ControlRig, m_loaded.ControlRig));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user