Merge pull request #1996 from ousttrue/feature/EuclideanTransform

ITPoseProvider を縮小。EuclideanTransform 導入
This commit is contained in:
ousttrue
2023-02-27 19:29:35 +09:00
committed by GitHub
7 changed files with 126 additions and 81 deletions

View File

@@ -0,0 +1,31 @@
using UnityEngine;
namespace UniGLTF.Utils
{
public readonly struct EuclideanTransform
{
public readonly Quaternion Rotation;
public readonly Vector3 Translation;
public EuclideanTransform(Quaternion rotation, Vector3 translation)
{
Rotation = rotation;
Translation = translation;
}
public EuclideanTransform(Quaternion rotation)
{
Rotation = rotation;
Translation = Vector3.zero;
}
public EuclideanTransform(Vector3 translation)
{
Rotation = Quaternion.identity;
Translation = translation;
}
public EuclideanTransform(Matrix4x4 matrix)
{
Rotation = matrix.rotation;
Translation = matrix.GetColumn(3);
}
}
}

View File

@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: af1b96890351fa24e9a49e7c4a6c2185
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -3,6 +3,7 @@ using System.Collections.Generic;
using System.Linq;
using UniHumanoid;
using UnityEngine;
using UniGLTF.Utils;
namespace UniVRM10
{
@@ -68,53 +69,30 @@ namespace UniVRM10
}
}
#region INormalizedPoseApplicable
public void SetRawHipsPosition(Vector3 position)
void INormalizedPoseApplicable.SetRawHipsPosition(Vector3 position)
{
var world = _controlRigRoot.TransformPoint(position);
_hipBone.ControlBone.position = world;
}
public void SetNormalizedLocalRotation(HumanBodyBones bone, Quaternion normalizedLocalRotation)
void INormalizedPoseApplicable.SetNormalizedLocalRotation(HumanBodyBones bone, Quaternion normalizedLocalRotation)
{
if (_bones.TryGetValue(bone, out var t))
{
t.ControlBone.localRotation = normalizedLocalRotation;
}
}
#endregion
IEnumerable<(HumanBodyBones Head, HumanBodyBones Parent)> Traverse(Vrm10ControlBone bone, Vrm10ControlBone parent = null)
EuclideanTransform? ITPoseProvider.GetWorldTransform(HumanBodyBones bone)
{
yield return (bone.BoneType, parent != null ? parent.BoneType : HumanBodyBones.LastBone);
foreach (var child in bone.Children)
if (_bones.TryGetValue(bone, out var t))
{
foreach (var headParent in Traverse(child, bone))
{
yield return headParent;
}
return new EuclideanTransform(t.InitialTargetGlobalPosition);
}
else
{
return default;
}
}
#region ITPoseProvider
public IEnumerable<(HumanBodyBones Bone, HumanBodyBones Parent)> EnumerateBoneParentPairs()
{
foreach (var headParent in Traverse(_hipBone))
{
yield return headParent;
}
}
public Quaternion? GetBoneWorldRotation(HumanBodyBones bone)
{
return Quaternion.identity;
}
public Vector3? GetBoneWorldPosition(HumanBodyBones bone)
{
return _bones[bone].InitialTargetGlobalPosition;
}
#endregion
}
}

View File

@@ -1,5 +1,6 @@
using System;
using System.Collections.Generic;
using UniGLTF.Utils;
using UnityEngine;
namespace UniVRM10
@@ -16,7 +17,7 @@ namespace UniVRM10
{
Transform m_root;
Animator m_animator;
Dictionary<HumanBodyBones, Vector3> m_posMap = new Dictionary<HumanBodyBones, Vector3>();
Dictionary<HumanBodyBones, EuclideanTransform> m_posMap = new Dictionary<HumanBodyBones, EuclideanTransform>();
public AnimatorPoseProvider(Transform root, Animator animator)
{
@@ -24,24 +25,22 @@ namespace UniVRM10
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)
if (bone == HumanBodyBones.LastBone)
{
continue;
}
var t = animator.GetBoneTransform(bone);
if (t != null)
{
m_posMap[bone] = root.worldToLocalMatrix.MultiplyPoint(t.position);
m_posMap[bone] = new EuclideanTransform(root.worldToLocalMatrix * t.localToWorldMatrix);
}
}
}
#region INormalizedPoseProvider
public Quaternion GetNormalizedLocalRotation(HumanBodyBones bone, HumanBodyBones parentBone)
Quaternion INormalizedPoseProvider.GetNormalizedLocalRotation(HumanBodyBones bone, HumanBodyBones parentBone)
{
if (m_animator.GetBoneTransform(bone) is Transform t)
{
@@ -55,30 +54,22 @@ namespace UniVRM10
}
}
public Vector3 GetRawHipsPosition()
Vector3 INormalizedPoseProvider.GetRawHipsPosition()
{
// TODO: from model root ?
return m_animator.GetBoneTransform(HumanBodyBones.Hips).localPosition;
}
#endregion
#region ITPoseProvider
public Vector3 HipTPoseWorldPosition { get; }
public IEnumerable<(HumanBodyBones Bone, HumanBodyBones Parent)> EnumerateBoneParentPairs()
EuclideanTransform? ITPoseProvider.GetWorldTransform(HumanBodyBones bone)
{
throw new System.NotImplementedException();
if (m_posMap.TryGetValue(bone, out var t))
{
return t;
}
else
{
return default;
}
}
public Quaternion? GetBoneWorldRotation(HumanBodyBones bone)
{
throw new System.NotImplementedException();
}
public Vector3? GetBoneWorldPosition(HumanBodyBones bone)
{
return m_posMap[bone];
}
#endregion
}
}

View File

@@ -1,4 +1,6 @@
using System;
using System.Collections.Generic;
using UniGLTF.Utils;
using UnityEngine;
namespace UniVRM10
@@ -6,15 +8,56 @@ namespace UniVRM10
public interface ITPoseProvider
{
/// <summary>
/// このTPoseに含まれるボーンと親ボーンの組み合わせを列挙する
///
/// * Humanoidの木構造を深さ優先の順番で列挙する
///
/// TPose 時のモデルルートを基準とした world 回転と位置を返す
/// 該当する bone が無いときは null。
/// </summary>
/// <returns>hips の場合は parent は HumanBodyBones.LastBone で null を表す</returns>
IEnumerable<(HumanBodyBones Bone, HumanBodyBones Parent)> EnumerateBoneParentPairs();
EuclideanTransform? GetWorldTransform(HumanBodyBones bone);
}
Quaternion? GetBoneWorldRotation(HumanBodyBones bone);
Vector3? GetBoneWorldPosition(HumanBodyBones bone);
public static class ITPoseProviderExtensions
{
static HumanBodyBones GetParent(ITPoseProvider self, HumanBodyBones bone)
{
var current = bone;
// 無限ループ防止のため念のためカウンター付き
for (int i = 0; i < 100; ++i)
{
var vrmBone = Vrm10HumanoidBoneSpecification.ConvertFromUnityBone(current);
var def = Vrm10HumanoidBoneSpecification.GetDefine(vrmBone);
var parentBone = Vrm10HumanoidBoneSpecification.ConvertToUnityBone(def.ParentBone.Value);
if (self.GetWorldTransform(parentBone).HasValue)
{
return parentBone;
}
current = parentBone;
}
// Hips 以外は必ず親ボーンが有るはずなのでここには来ない
throw new Exception("parent not found");
}
public static IEnumerable<(HumanBodyBones Bone, HumanBodyBones Parent)> EnumerateBoneParentPairs(this ITPoseProvider self)
{
foreach (var bone in CachedEnum.GetValues<HumanBodyBones>())
{
if (bone == HumanBodyBones.LastBone)
{
continue;
}
if (!self.GetWorldTransform(bone).HasValue)
{
continue;
}
if (bone == HumanBodyBones.Hips)
{
yield return (bone, HumanBodyBones.LastBone);
}
else
{
yield return (bone, GetParent(self, bone));
}
}
}
}
}

View File

@@ -1,4 +1,5 @@
using System.Collections.Generic;
using UniGLTF.Utils;
using UnityEngine;
namespace UniVRM10
@@ -31,7 +32,7 @@ namespace UniVRM10
}
}
public Quaternion GetNormalizedLocalRotation(HumanBodyBones bone, HumanBodyBones parentBone)
Quaternion INormalizedPoseProvider.GetNormalizedLocalRotation(HumanBodyBones bone, HumanBodyBones parentBone)
{
if (m_bones.TryGetValue(bone, out var c))
{
@@ -44,7 +45,7 @@ namespace UniVRM10
}
}
public Vector3 GetRawHipsPosition()
Vector3 INormalizedPoseProvider.GetRawHipsPosition()
{
if (m_hips.parent == m_root)
{
@@ -56,17 +57,7 @@ namespace UniVRM10
}
}
public IEnumerable<(HumanBodyBones Bone, HumanBodyBones Parent)> EnumerateBoneParentPairs()
{
throw new System.NotImplementedException();
}
public Quaternion? GetBoneWorldRotation(HumanBodyBones bone)
{
throw new System.NotImplementedException();
}
public Vector3? GetBoneWorldPosition(HumanBodyBones bone)
EuclideanTransform? ITPoseProvider.GetWorldTransform(HumanBodyBones bone)
{
throw new System.NotImplementedException();
}

View File

@@ -13,9 +13,9 @@ namespace UniVRM10.VRM10Viewer
}
// scaling hips position
var scaling = sink.TPose.GetBoneWorldPosition(HumanBodyBones.LeftUpperLeg).Value.y / source.TPose.GetBoneWorldPosition(HumanBodyBones.LeftUpperLeg).Value.y;
var delta = source.Pose.GetRawHipsPosition() - source.TPose.GetBoneWorldPosition(HumanBodyBones.Hips).Value;
sink.Pose.SetRawHipsPosition(sink.TPose.GetBoneWorldPosition(HumanBodyBones.Hips).Value + delta * scaling);
var scaling = sink.TPose.GetWorldTransform(HumanBodyBones.LeftUpperLeg).Value.Translation.y / source.TPose.GetWorldTransform(HumanBodyBones.LeftUpperLeg).Value.Translation.y;
var delta = source.Pose.GetRawHipsPosition() - source.TPose.GetWorldTransform(HumanBodyBones.Hips).Value.Translation;
sink.Pose.SetRawHipsPosition(sink.TPose.GetWorldTransform(HumanBodyBones.Hips).Value.Translation + delta * scaling);
}
public static void EnforceTPose((INormalizedPoseApplicable Pose, ITPoseProvider TPose) sink)
@@ -25,7 +25,7 @@ namespace UniVRM10.VRM10Viewer
sink.Pose.SetNormalizedLocalRotation(bone, Quaternion.identity);
}
sink.Pose.SetRawHipsPosition(sink.TPose.GetBoneWorldPosition(HumanBodyBones.Hips).Value);
sink.Pose.SetRawHipsPosition(sink.TPose.GetWorldTransform(HumanBodyBones.Hips).Value.Translation);
}
}
}