FkRetarget の初期実装。vrm-1.0 で 正規化をやめるので、従来の正規化済みTPoseに対する localRotation を変換して適用する機能です

This commit is contained in:
ousttrue 2022-08-23 15:53:21 +09:00
parent 64f5a05bc3
commit 2eb64b5f24
4 changed files with 71 additions and 41 deletions

View File

@ -56,6 +56,7 @@ namespace UniVRM10
public static Vrm10BoneWithAxis Build(UniHumanoid.Humanoid humanoid, Dictionary<HumanBodyBones, Vrm10BoneWithAxis> boneMap)
{
var hips = new Vrm10BoneWithAxis(humanoid.Hips, Quaternion.identity, HumanBodyBones.Hips);
boneMap.Add(HumanBodyBones.Hips, hips);
foreach (Transform child in humanoid.Hips)
{
@ -93,12 +94,7 @@ namespace UniVRM10
/// </summary>
public void ApplyRecursive(Quaternion worldParentRotation)
{
// var pose = InitialLocalRotation * Normalized.localRotation * Quaternion.Inverse(InitialLocalRotation);
// var pose = Quaternion.Inverse(InitialLocalRotation) * Normalized.localRotation * InitialLocalRotation;
Target.localRotation = InitialLocalRotation * Quaternion.Inverse(ToLocal) * Normalized.localRotation * ToLocal;
// Target.localRotation = InitialLocalRotation * Normalized.localRotation; // * Quaternion.Inverse(InitialLocalRotation);
// Target.localRotation = InitialLocalRotation;
foreach (var child in Children)
{
child.ApplyRecursive(Normalized.rotation);

View File

@ -9,12 +9,13 @@ namespace UniVRM10
Dictionary<HumanBodyBones, Vrm10BoneWithAxis> m_boneMap = new Dictionary<HumanBodyBones, Vrm10BoneWithAxis>();
Vector3 m_initialHipsPosition;
public readonly float InitialHipsHeight;
public Vrm10FkRetarget(UniHumanoid.Humanoid humanoid)
{
m_root = Vrm10BoneWithAxis.Build(humanoid, m_boneMap);
m_initialHipsPosition = m_root.Target.position;
InitialHipsHeight = m_root.Target.position.y;
Debug.Log($"InitialHipsHeight: {InitialHipsHeight}");
}
public void Apply()

View File

@ -107,16 +107,15 @@ namespace UniVRM10
gaze.SetParent(m_head);
gaze.localPosition = Vector3.forward;
}
switch (m_lookat.LookAtType)
// bone が無いときのエラー防止。マイグレーション失敗?
if (m_lookat.LookAtType == LookAtType.bone && m_leftEye != null && m_rightEye != null)
{
case LookAtType.bone:
_eyeDirectionApplicable = new LookAtEyeDirectionApplicableToBone(m_leftEye, m_rightEye, m_lookat.HorizontalOuter, m_lookat.HorizontalInner, m_lookat.VerticalDown, m_lookat.VerticalUp);
break;
case LookAtType.expression:
_eyeDirectionApplicable = new LookAtEyeDirectionApplicableToExpression(m_lookat.HorizontalOuter, m_lookat.HorizontalInner, m_lookat.VerticalDown, m_lookat.VerticalUp);
break;
default:
throw new ArgumentOutOfRangeException();
_eyeDirectionApplicable = new LookAtEyeDirectionApplicableToBone(m_leftEye, m_rightEye, m_lookat.HorizontalOuter, m_lookat.HorizontalInner, m_lookat.VerticalDown, m_lookat.VerticalUp);
}
else
{
_eyeDirectionApplicable = new LookAtEyeDirectionApplicableToExpression(m_lookat.HorizontalOuter, m_lookat.HorizontalInner, m_lookat.VerticalDown, m_lookat.VerticalUp);
}
}

View File

@ -39,7 +39,7 @@ namespace UniVRM10.VRM10Viewer
[Header("Runtime")]
[SerializeField]
HumanPoseTransfer m_src = default;
Animator m_src = default;
[SerializeField]
GameObject m_target = default;
@ -200,7 +200,7 @@ namespace UniVRM10.VRM10Viewer
var texts = GameObject.FindObjectsOfType<Text>();
m_version = texts.First(x => x.name == "Version");
m_src = GameObject.FindObjectOfType<HumanPoseTransfer>();
m_src = GameObject.FindObjectOfType<Animator>();
m_target = GameObject.FindObjectOfType<VRM10TargetMover>().gameObject;
}
@ -208,7 +208,7 @@ namespace UniVRM10.VRM10Viewer
class Loaded : IDisposable
{
RuntimeGltfInstance m_instance;
HumanPoseTransfer m_pose;
bool m_useBvh;
Vrm10Instance m_controller;
VRM10AIUEO m_lipSync;
@ -256,7 +256,7 @@ namespace UniVRM10.VRM10Viewer
}
}
public Loaded(RuntimeGltfInstance instance, HumanPoseTransfer src, Transform lookAtTarget)
public Loaded(RuntimeGltfInstance instance, Transform lookAtTarget)
{
m_instance = instance;
@ -266,10 +266,6 @@ namespace UniVRM10.VRM10Viewer
// VRM
m_controller.UpdateType = Vrm10Instance.UpdateTypes.LateUpdate; // after HumanPoseTransfer's setPose
{
m_pose = instance.gameObject.AddComponent<HumanPoseTransfer>();
m_pose.Source = src;
m_pose.SourceType = HumanPoseTransfer.HumanPoseTransferSourceType.HumanPoseTransfer;
m_lipSync = instance.gameObject.AddComponent<VRM10AIUEO>();
m_blink = instance.gameObject.AddComponent<VRM10Blinker>();
m_autoExpression = instance.gameObject.AddComponent<VRM10AutoExpression>();
@ -293,22 +289,57 @@ namespace UniVRM10.VRM10Viewer
GameObject.Destroy(m_instance.gameObject);
}
public void EnableBvh(HumanPoseTransfer src)
public void EnableBvh()
{
if (m_pose != null)
{
m_pose.Source = src;
m_pose.SourceType = HumanPoseTransfer.HumanPoseTransferSourceType.HumanPoseTransfer;
}
m_useBvh = true;
}
public void EnableTPose(HumanPoseClip pose)
public void EnableTPose()
{
if (m_pose != null)
m_useBvh = false;
}
public void UpdatePose(Animator pose)
{
var fkRetarget = m_controller.Runtime.GetOrCreateFkRetarget();
foreach (HumanBodyBones bone in Enum.GetValues(typeof(HumanBodyBones)))
{
m_pose.PoseClip = pose;
m_pose.SourceType = HumanPoseTransfer.HumanPoseTransferSourceType.HumanPoseClip;
if (bone == HumanBodyBones.LastBone)
{
continue;
}
var dst = fkRetarget.GetBoneTransform(bone);
if (dst == null)
{
continue;
}
if (m_useBvh)
{
var src = pose.GetBoneTransform(bone);
if (src != null)
{
// set normalized pose
dst.localRotation = src.localRotation;
}
if (bone == HumanBodyBones.Hips)
{
dst.position = src.position * fkRetarget.InitialHipsHeight;
}
}
else
{
// set TPose
dst.localRotation = Quaternion.identity;
if (bone == HumanBodyBones.Hips)
{
dst.position = Vector3.up * fkRetarget.InitialHipsHeight;
}
}
}
fkRetarget.Apply();
}
}
Loaded m_loaded;
@ -344,7 +375,7 @@ namespace UniVRM10.VRM10Viewer
var context = new UniHumanoid.BvhImporterContext();
context.Parse("tmp.bvh", source);
context.Load();
SetMotion(context.Root.GetComponent<HumanPoseTransfer>());
SetMotion(context.Root.GetComponent<Animator>());
}
private void Update()
@ -369,7 +400,12 @@ namespace UniVRM10.VRM10Viewer
}
}
m_ui.UpdateToggle(() => m_loaded?.EnableBvh(m_src), () => m_loaded?.EnableTPose(m_pose));
m_ui.UpdateToggle(() => m_loaded?.EnableBvh(), () => m_loaded?.EnableTPose());
if (m_loaded != null)
{
m_loaded.UpdatePose(m_src);
}
}
void OnOpenClicked()
@ -506,17 +542,15 @@ namespace UniVRM10.VRM10Viewer
instance.ShowMeshes();
instance.EnableUpdateWhenOffscreen();
m_loaded = new Loaded(instance, m_src, m_target.transform);
m_loaded = new Loaded(instance, m_target.transform);
}
void SetMotion(HumanPoseTransfer src)
void SetMotion(Animator src)
{
m_src = src;
src.GetComponent<Renderer>().enabled = false;
if (m_loaded != null)
{
m_loaded.EnableBvh(m_src);
m_loaded.EnableBvh();
}
}
}