sample の retarget を更新。

TPose を表現する empty クラスを追加。
This commit is contained in:
ousttrue
2023-08-21 16:25:49 +09:00
parent 70f101d434
commit 1d05e845c9
5 changed files with 90 additions and 61 deletions

View File

@@ -0,0 +1,70 @@
using System;
using System.Collections.Generic;
using UniGLTF.Utils;
using UnityEngine;
namespace UniVRM10
{
public class TPose : IVrm10Animation
{
public class NoRotation : INormalizedPoseProvider
{
readonly Vector3 m_hips;
public NoRotation(Vector3 hips)
{
m_hips = hips;
}
public Quaternion GetNormalizedLocalRotation(HumanBodyBones bone, HumanBodyBones parentBone)
{
return new Quaternion(0, 0, 0, 1);
}
public Vector3 GetRawHipsPosition()
{
return m_hips;
}
}
public class Skeleton : ITPoseProvider
{
Vector3 m_hips;
public Skeleton(Vector3 hips)
{
m_hips = hips;
}
public EuclideanTransform? GetWorldTransform(HumanBodyBones bone)
{
if (bone == HumanBodyBones.Hips)
{
return new EuclideanTransform(m_hips);
}
return default;
}
}
public (INormalizedPoseProvider, ITPoseProvider) m_controlRig;
public (INormalizedPoseProvider, ITPoseProvider) ControlRig => m_controlRig;
// empty
public IReadOnlyDictionary<ExpressionKey, Func<float>> ExpressionMap => new Dictionary<ExpressionKey, Func<float>>();
public LookAtInput? LookAt => default;
public TPose(Vector3 hips)
{
m_controlRig = (new NoRotation(hips), new Skeleton(hips));
}
public void Dispose()
{
}
public void ShowBoxMan(bool enable)
{
}
}
}

View File

@@ -1,5 +1,5 @@
fileFormatVersion: 2
guid: 49423dc9e9a224545a90221f41d975c8
guid: 90e77483e976b074db9a08fcdc1b5d40
MonoImporter:
externalObjects: {}
serializedVersion: 2

View File

@@ -13,7 +13,8 @@ namespace UniVRM10
}
// scaling hips position
var scaling = sink.TPose.GetWorldTransform(HumanBodyBones.LeftUpperLeg).Value.Translation.y / source.TPose.GetWorldTransform(HumanBodyBones.LeftUpperLeg).Value.Translation.y;
var scaleRef = HumanBodyBones.Hips;
var scaling = sink.TPose.GetWorldTransform(scaleRef).Value.Translation.y / source.TPose.GetWorldTransform(scaleRef).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);
}

View File

@@ -1,31 +0,0 @@
using UnityEngine;
namespace UniVRM10.VRM10Viewer
{
public static class VRM10Retarget
{
public static void Retarget((INormalizedPoseProvider Pose, ITPoseProvider TPose) source, (INormalizedPoseApplicable Pose, ITPoseProvider TPose) sink)
{
foreach (var (head, parent) in sink.TPose.EnumerateBoneParentPairs())
{
var q = source.Pose.GetNormalizedLocalRotation(head, parent);
sink.Pose.SetNormalizedLocalRotation(head, q);
}
// scaling hips position
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)
{
foreach (var (bone, parent) in sink.TPose.EnumerateBoneParentPairs())
{
sink.Pose.SetNormalizedLocalRotation(bone, Quaternion.identity);
}
sink.Pose.SetRawHipsPosition(sink.TPose.GetWorldTransform(HumanBodyBones.Hips).Value.Translation);
}
}
}

View File

@@ -61,9 +61,13 @@ namespace UniVRM10.VRM10Viewer
m_src.Dispose();
}
m_src = value;
TPose = new TPose(m_src.ControlRig.Item1.GetRawHipsPosition());
}
}
public IVrm10Animation TPose;
private CancellationTokenSource _cancellationTokenSource;
[Serializable]
@@ -209,13 +213,13 @@ namespace UniVRM10.VRM10Viewer
ToggleMotion = groups.First(x => x.name == "_Motion_");
}
public bool IsBvhEnabled
public bool IsTPose
{
get => ToggleMotion.ActiveToggles().FirstOrDefault() == ToggleMotionBVH;
get => ToggleMotion.ActiveToggles().FirstOrDefault() == ToggleMotionTPose;
set
{
ToggleMotionTPose.isOn = !value;
ToggleMotionBVH.isOn = value;
ToggleMotionTPose.isOn = value;
ToggleMotionBVH.isOn = !value;
}
}
}
@@ -331,7 +335,7 @@ namespace UniVRM10.VRM10Viewer
_cancellationTokenSource?.Dispose();
}
bool? m_lastUseBvh = default;
private void Update()
{
if (Input.GetKeyDown(KeyCode.Tab))
@@ -357,31 +361,19 @@ namespace UniVRM10.VRM10Viewer
m_loaded.EnableLipSyncValue = m_enableLipSync.isOn;
m_loaded.EnableBlinkValue = m_enableAutoBlink.isOn;
m_loaded.EnableAutoExpressionValue = m_enableAutoExpression.isOn;
}
var useBvh = Motion != null;
if (useBvh)
if (m_loaded != null)
{
if (m_ui.IsTPose)
{
// update humanoid
if (Motion.ControlRig.Item1 != null && Motion.ControlRig.Item2 != null)
{
VRM10Retarget.Retarget(Motion.ControlRig, (m_loaded.ControlRig, m_loaded.ControlRig));
}
// update expressions
foreach (var (k, v) in Motion.ExpressionMap)
{
// VRMA-expression use localPosition.x as expression weight
m_loaded.Runtime.Expression.SetWeight(k, v());
}
m_loaded.Runtime.VrmAnimation = TPose;
}
else
else if (Motion != null)
{
if (!m_lastUseBvh.HasValue || m_lastUseBvh.Value)
{
Debug.Log("SetPose");
VRM10Retarget.EnforceTPose((m_loaded.ControlRig, m_loaded.ControlRig));
}
// Automatically retarget in Vrm10Runtime.Process
m_loaded.Runtime.VrmAnimation = Motion;
}
m_lastUseBvh = useBvh;
}
}
@@ -446,9 +438,6 @@ namespace UniVRM10.VRM10Viewer
return;
}
m_ui.IsBvhEnabled = false;
m_lastUseBvh = false;
try
{
Motion = await Vrm10PoseLoader.LoadVrmAnimationPose(text);