mirror of
https://github.com/vrm-c/UniVRM.git
synced 2026-05-15 07:00:10 -05:00
use VRM10Retarget.Retarget
This commit is contained in:
parent
5235a9b837
commit
0502f30588
|
|
@ -9,6 +9,7 @@ namespace UniVRM10.VRM10Viewer
|
|||
{
|
||||
RuntimeGltfInstance m_instance;
|
||||
Vrm10Instance m_controller;
|
||||
public Vrm10RuntimeControlRig ControlRig => m_controller.Runtime.ControlRig;
|
||||
|
||||
VRM10AIUEO m_lipSync;
|
||||
bool m_enableLipSyncValue;
|
||||
|
|
@ -88,110 +89,6 @@ namespace UniVRM10.VRM10Viewer
|
|||
GameObject.Destroy(m_instance.gameObject);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// from v0.103
|
||||
/// </summary>
|
||||
/// <param name="src"></param>
|
||||
public void UpdateControlRigExplicit(Animator src)
|
||||
{
|
||||
var controlRig = m_controller.Runtime.ControlRig;
|
||||
|
||||
foreach (HumanBodyBones bone in CachedEnum.GetValues<HumanBodyBones>())
|
||||
{
|
||||
if (bone == HumanBodyBones.LastBone)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
var controlRigBone = controlRig.GetBoneTransform(bone);
|
||||
if (controlRigBone == null)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
var bvhBone = src.GetBoneTransform(bone);
|
||||
if (bvhBone != null)
|
||||
{
|
||||
// set normalized pose
|
||||
controlRigBone.localRotation = bvhBone.localRotation;
|
||||
}
|
||||
|
||||
if (bone == HumanBodyBones.Hips)
|
||||
{
|
||||
controlRigBone.localPosition = bvhBone.localPosition * controlRig.InitialHipsHeight;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// from v0.104
|
||||
/// </summary>
|
||||
public void UpdateControlRigImplicit(Animator src)
|
||||
{
|
||||
var dst = m_controller.GetComponent<Animator>();
|
||||
|
||||
foreach (HumanBodyBones bone in CachedEnum.GetValues<HumanBodyBones>())
|
||||
{
|
||||
if (bone == HumanBodyBones.LastBone)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
var boneTransform = dst.GetBoneTransform(bone);
|
||||
if (boneTransform == null)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
var bvhBone = src.GetBoneTransform(bone);
|
||||
if (bvhBone != null)
|
||||
{
|
||||
// set normalized pose
|
||||
boneTransform.localRotation = bvhBone.localRotation;
|
||||
}
|
||||
|
||||
if (bone == HumanBodyBones.Hips)
|
||||
{
|
||||
// TODO: hips position scaling ?
|
||||
boneTransform.localPosition = bvhBone.localPosition;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// from v0.108
|
||||
/// </summary>
|
||||
public void UpdateControlRigImplicit(UniHumanoid.Humanoid src)
|
||||
{
|
||||
var dst = m_controller.GetComponent<Animator>();
|
||||
|
||||
foreach (HumanBodyBones bone in CachedEnum.GetValues<HumanBodyBones>())
|
||||
{
|
||||
if (bone == HumanBodyBones.LastBone)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
var boneTransform = dst.GetBoneTransform(bone);
|
||||
if (boneTransform == null)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
var bvhBone = src.GetBoneTransform(bone);
|
||||
if (bvhBone != null)
|
||||
{
|
||||
// set normalized pose
|
||||
boneTransform.localRotation = bvhBone.localRotation;
|
||||
if (bone == HumanBodyBones.Hips)
|
||||
{
|
||||
// TODO: hips position scaling ?
|
||||
boneTransform.localPosition = bvhBone.localPosition;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void TPoseControlRig()
|
||||
{
|
||||
var controlRig = m_controller.Runtime.ControlRig;
|
||||
|
|
|
|||
208
Assets/VRM10_Samples/VRM10Viewer/VRM10Motion.cs
Normal file
208
Assets/VRM10_Samples/VRM10Viewer/VRM10Motion.cs
Normal file
|
|
@ -0,0 +1,208 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Threading.Tasks;
|
||||
using UniGLTF;
|
||||
using UniHumanoid;
|
||||
using UniJSON;
|
||||
using UnityEngine;
|
||||
using VRMShaders;
|
||||
|
||||
namespace UniVRM10.VRM10Viewer
|
||||
{
|
||||
public class VRM10Motion
|
||||
{
|
||||
public (INormalizedPoseProvider, ITPoseProvider) ControlRig;
|
||||
|
||||
UniHumanoid.BvhImporterContext m_context;
|
||||
UniGLTF.RuntimeGltfInstance m_instance;
|
||||
|
||||
public Transform Root => m_context?.Root.transform;
|
||||
|
||||
public VRM10Motion(UniHumanoid.BvhImporterContext context)
|
||||
{
|
||||
m_context = context;
|
||||
var provider = new NormalizedPoseProvider(m_context.Root.transform, m_context.Root.GetComponent<Animator>());
|
||||
ControlRig = (provider, provider);
|
||||
}
|
||||
|
||||
public VRM10Motion(UniGLTF.RuntimeGltfInstance instance)
|
||||
{
|
||||
m_instance = instance;
|
||||
if (instance.GetComponent<Animation>() is Animation animation)
|
||||
{
|
||||
animation.Play();
|
||||
}
|
||||
}
|
||||
|
||||
public void ShowBoxMan(bool showBoxMan)
|
||||
{
|
||||
if (m_context != null)
|
||||
{
|
||||
m_context.Root.GetComponent<SkinnedMeshRenderer>().enabled = showBoxMan;
|
||||
}
|
||||
}
|
||||
|
||||
public static VRM10Motion LoadBvhFromText(string source, string path = "tmp.bvh")
|
||||
{
|
||||
var context = new UniHumanoid.BvhImporterContext();
|
||||
context.Parse(path, source);
|
||||
context.Load();
|
||||
return new VRM10Motion(context);
|
||||
}
|
||||
|
||||
public static VRM10Motion LoadBvhFromPath(string path)
|
||||
{
|
||||
return LoadBvhFromText(File.ReadAllText(path), path);
|
||||
}
|
||||
|
||||
static IEnumerable<Transform> Traverse(Transform t)
|
||||
{
|
||||
yield return t;
|
||||
foreach (Transform child in t)
|
||||
{
|
||||
foreach (var x in Traverse(child))
|
||||
{
|
||||
yield return x;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#region experimental vrm-animation deserializer
|
||||
//
|
||||
// vrm-animation の簡易実装
|
||||
//
|
||||
// https://github.com/vrm-c/vrm-animation
|
||||
//
|
||||
static float ForceMeterScale(Dictionary<HumanBodyBones, Transform> map)
|
||||
{
|
||||
var positionMap = map.ToDictionary(kv => kv.Key, kv => kv.Value.position);
|
||||
var hipsHeight = positionMap[HumanBodyBones.Hips].y;
|
||||
|
||||
float scaling = 1.0f;
|
||||
if (hipsHeight > 80)
|
||||
{
|
||||
// cm スケールであると見做す
|
||||
scaling = 0.01f;
|
||||
}
|
||||
return scaling;
|
||||
}
|
||||
|
||||
static bool TryGet(JsonNode obj, string key, out JsonNode found)
|
||||
{
|
||||
foreach (var kv in obj.ObjectItems())
|
||||
{
|
||||
if (kv.Key.GetString() == key)
|
||||
{
|
||||
found = kv.Value;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
found = default;
|
||||
return false;
|
||||
}
|
||||
|
||||
static (HumanBodyBones, int) ToTuple(KeyValuePair<JsonNode, JsonNode> kv)
|
||||
{
|
||||
if (TryGet(kv.Value, "node", out var value))
|
||||
{
|
||||
var name = kv.Key.GetString();
|
||||
switch (name)
|
||||
{
|
||||
case "rightThumbMetacarpal":
|
||||
return (HumanBodyBones.RightThumbProximal, value.GetInt32());
|
||||
case "leftThumbMetacarpal":
|
||||
return (HumanBodyBones.LeftThumbProximal, value.GetInt32());
|
||||
case "rightThumbProximal":
|
||||
return (HumanBodyBones.RightThumbIntermediate, value.GetInt32());
|
||||
case "leftThumbProximal":
|
||||
return (HumanBodyBones.LeftThumbIntermediate, value.GetInt32());
|
||||
default:
|
||||
return ((HumanBodyBones)Enum.Parse(typeof(HumanBodyBones), name, true), value.GetInt32());
|
||||
}
|
||||
}
|
||||
throw new Exception();
|
||||
}
|
||||
|
||||
static Dictionary<HumanBodyBones, Transform> GetHumanMap(GltfData data, IReadOnlyList<Transform> nodes)
|
||||
{
|
||||
var humanMap = new Dictionary<HumanBodyBones, Transform>();
|
||||
if (data.GLTF.extensions is UniGLTF.glTFExtensionImport extensions)
|
||||
{
|
||||
foreach (var kv in extensions.ObjectItems())
|
||||
{
|
||||
if (kv.Key.GetString() == "VRMC_vrm_animation")
|
||||
{
|
||||
var animation = kv.Value;
|
||||
if (TryGet(animation, "humanoid", out var animation_humanoid))
|
||||
{
|
||||
if (TryGet(animation_humanoid, "humanBones", out var bones))
|
||||
{
|
||||
foreach (var kkvv in bones.ObjectItems())
|
||||
{
|
||||
var (bone, index) = ToTuple(kkvv);
|
||||
// Debug.Log($"{bone} => {index}");
|
||||
humanMap.Add(bone, nodes[index]);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return humanMap;
|
||||
}
|
||||
#endregion
|
||||
|
||||
public static async Task<VRM10Motion> LoadVrmAnimationFromPathAsync(string path)
|
||||
{
|
||||
//
|
||||
// GetHumanoid Mapping
|
||||
//
|
||||
using (GltfData data = new AutoGltfFileParser(path).Parse())
|
||||
using (var loader = new UniGLTF.ImporterContext(data))
|
||||
{
|
||||
loader.InvertAxis = Axes.X;
|
||||
// loader.PositionScaling = 0.01f;
|
||||
var instance = await loader.LoadAsync(new ImmediateCaller());
|
||||
var humanMap = GetHumanMap(data, loader.Nodes);
|
||||
if (humanMap.Count == 0)
|
||||
{
|
||||
throw new ArgumentException("fail to load VRMC_vrm_animation");
|
||||
}
|
||||
|
||||
var scaling = ForceMeterScale(humanMap);
|
||||
// instance.transform.localScale = new Vector3(scaling, scaling, scaling);
|
||||
var description = AvatarDescription.Create(humanMap);
|
||||
|
||||
//
|
||||
// avatar
|
||||
//
|
||||
var avatar = description.CreateAvatar(instance.Root.transform);
|
||||
avatar.name = "Avatar";
|
||||
// AvatarDescription = description;
|
||||
var animator = instance.gameObject.AddComponent<Animator>();
|
||||
animator.avatar = avatar;
|
||||
|
||||
// create SkinnedMesh for bone visualize
|
||||
var renderer = SkeletonMeshUtility.CreateRenderer(animator);
|
||||
var material = new Material(Shader.Find("Standard"));
|
||||
renderer.sharedMaterial = material;
|
||||
var mesh = renderer.sharedMesh;
|
||||
mesh.name = "box-man";
|
||||
|
||||
var humanoid = instance.gameObject.AddComponent<Humanoid>();
|
||||
humanoid.AssignBonesFromAnimator();
|
||||
var motion = new VRM10Motion(instance);
|
||||
var poseProvider = new InitRotationPoseProvider(instance.transform, humanoid);
|
||||
motion.ControlRig = (poseProvider, poseProvider);
|
||||
return motion;
|
||||
}
|
||||
}
|
||||
|
||||
public void Retarget(Vrm10RuntimeControlRig dst)
|
||||
{
|
||||
VRM10Retarget.Retarget(ControlRig, (dst, dst));
|
||||
}
|
||||
}
|
||||
}
|
||||
11
Assets/VRM10_Samples/VRM10Viewer/VRM10Motion.cs.meta
Normal file
11
Assets/VRM10_Samples/VRM10Viewer/VRM10Motion.cs.meta
Normal file
|
|
@ -0,0 +1,11 @@
|
|||
fileFormatVersion: 2
|
||||
guid: 08f06b12436bf594b9982c6a8ec71374
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
|
|
@ -3,7 +3,6 @@ using System.IO;
|
|||
using System.Linq;
|
||||
using System.Threading;
|
||||
using UniGLTF;
|
||||
using UniHumanoid;
|
||||
using UnityEngine;
|
||||
using UnityEngine.UI;
|
||||
using VRMShaders;
|
||||
|
|
@ -34,18 +33,15 @@ namespace UniVRM10.VRM10Viewer
|
|||
[SerializeField]
|
||||
Toggle m_useAsync = default;
|
||||
|
||||
[Header("Runtime")]
|
||||
[SerializeField]
|
||||
Animator m_src = default;
|
||||
|
||||
[SerializeField]
|
||||
GameObject m_target = default;
|
||||
|
||||
[SerializeField]
|
||||
TextAsset m_motion;
|
||||
|
||||
GameObject Root = default;
|
||||
|
||||
[SerializeField]
|
||||
TextAsset m_motion;
|
||||
VRM10Motion m_src = default;
|
||||
|
||||
private CancellationTokenSource _cancellationTokenSource;
|
||||
|
||||
|
|
@ -181,8 +177,6 @@ namespace UniVRM10.VRM10Viewer
|
|||
var texts = GameObject.FindObjectsOfType<Text>();
|
||||
m_version = texts.First(x => x.name == "Version");
|
||||
|
||||
m_src = GameObject.FindObjectOfType<Animator>();
|
||||
|
||||
m_target = GameObject.FindObjectOfType<VRM10TargetMover>().gameObject;
|
||||
}
|
||||
|
||||
|
|
@ -197,7 +191,7 @@ namespace UniVRM10.VRM10Viewer
|
|||
// load initial bvh
|
||||
if (m_motion != null)
|
||||
{
|
||||
LoadMotion(m_motion.text);
|
||||
m_src = VRM10Motion.LoadBvhFromText(m_motion.text);
|
||||
}
|
||||
|
||||
string[] cmds = System.Environment.GetCommandLineArgs();
|
||||
|
|
@ -217,17 +211,6 @@ namespace UniVRM10.VRM10Viewer
|
|||
_cancellationTokenSource?.Dispose();
|
||||
}
|
||||
|
||||
private void LoadMotion(string source)
|
||||
{
|
||||
var context = new UniHumanoid.BvhImporterContext();
|
||||
context.Parse("tmp.bvh", File.ReadAllText(source));
|
||||
context.Load();
|
||||
m_src = context.Root.GetComponent<Animator>();
|
||||
m_ui.IsBvhEnabled = true;
|
||||
// hide box man
|
||||
context.Root.GetComponent<SkinnedMeshRenderer>().enabled = false;
|
||||
}
|
||||
|
||||
private void Update()
|
||||
{
|
||||
if (m_loaded != null)
|
||||
|
|
@ -254,7 +237,7 @@ namespace UniVRM10.VRM10Viewer
|
|||
{
|
||||
if (m_ui.IsBvhEnabled && m_src != null)
|
||||
{
|
||||
m_loaded.UpdateControlRigImplicit(m_src);
|
||||
m_src.Retarget(m_loaded.ControlRig);
|
||||
}
|
||||
else
|
||||
{
|
||||
|
|
@ -280,7 +263,7 @@ namespace UniVRM10.VRM10Viewer
|
|||
var ext = Path.GetExtension(path).ToLower();
|
||||
if (ext == ".bvh")
|
||||
{
|
||||
LoadMotion(path);
|
||||
m_src = VRM10Motion.LoadBvhFromPath(path);
|
||||
return;
|
||||
}
|
||||
|
||||
|
|
|
|||
Loading…
Reference in New Issue
Block a user