mirror of
https://github.com/vrm-c/UniVRM.git
synced 2026-08-28 13:54:45 -05:00
Merge pull request #1992 from ousttrue/feature/vrm10viewer_use_controlrig
[sample] VRM10Retarget の実装
This commit is contained in:
@@ -6,178 +6,6 @@ using System.Linq;
|
||||
|
||||
namespace UniHumanoid
|
||||
{
|
||||
public class BvhException : Exception
|
||||
{
|
||||
public BvhException(string msg) : base(msg) { }
|
||||
}
|
||||
|
||||
public enum Channel
|
||||
{
|
||||
Xposition,
|
||||
Yposition,
|
||||
Zposition,
|
||||
Xrotation,
|
||||
Yrotation,
|
||||
Zrotation,
|
||||
}
|
||||
public static class ChannelExtensions
|
||||
{
|
||||
public static string ToProperty(this Channel ch)
|
||||
{
|
||||
switch (ch)
|
||||
{
|
||||
case Channel.Xposition: return "localPosition.x";
|
||||
case Channel.Yposition: return "localPosition.y";
|
||||
case Channel.Zposition: return "localPosition.z";
|
||||
case Channel.Xrotation: return "localEulerAnglesBaked.x";
|
||||
case Channel.Yrotation: return "localEulerAnglesBaked.y";
|
||||
case Channel.Zrotation: return "localEulerAnglesBaked.z";
|
||||
}
|
||||
|
||||
throw new BvhException("no property for " + ch);
|
||||
}
|
||||
|
||||
public static bool IsLocation(this Channel ch)
|
||||
{
|
||||
switch (ch)
|
||||
{
|
||||
case Channel.Xposition:
|
||||
case Channel.Yposition:
|
||||
case Channel.Zposition: return true;
|
||||
case Channel.Xrotation:
|
||||
case Channel.Yrotation:
|
||||
case Channel.Zrotation: return false;
|
||||
}
|
||||
|
||||
throw new BvhException("no property for " + ch);
|
||||
}
|
||||
}
|
||||
|
||||
public struct Single3
|
||||
{
|
||||
public Single x;
|
||||
public Single y;
|
||||
public Single z;
|
||||
|
||||
public Single3(Single _x, Single _y, Single _z)
|
||||
{
|
||||
x = _x;
|
||||
y = _y;
|
||||
z = _z;
|
||||
}
|
||||
}
|
||||
|
||||
public class BvhNode
|
||||
{
|
||||
public String Name
|
||||
{
|
||||
get;
|
||||
private set;
|
||||
}
|
||||
|
||||
public Single3 Offset
|
||||
{
|
||||
get;
|
||||
private set;
|
||||
}
|
||||
|
||||
public Channel[] Channels
|
||||
{
|
||||
get;
|
||||
private set;
|
||||
}
|
||||
|
||||
public List<BvhNode> Children
|
||||
{
|
||||
get;
|
||||
private set;
|
||||
}
|
||||
|
||||
public BvhNode(string name)
|
||||
{
|
||||
Name = name;
|
||||
Children = new List<BvhNode>();
|
||||
}
|
||||
|
||||
public virtual void Parse(StringReader r)
|
||||
{
|
||||
Offset = ParseOffset(r.ReadLine());
|
||||
|
||||
Channels = ParseChannel(r.ReadLine());
|
||||
}
|
||||
|
||||
static Single3 ParseOffset(string line)
|
||||
{
|
||||
var split = line.Trim().Split();
|
||||
if (split[0] != "OFFSET")
|
||||
{
|
||||
throw new BvhException("OFFSET is not found");
|
||||
}
|
||||
|
||||
var offset = split.Skip(1).Where(x => !string.IsNullOrEmpty(x)).Select(x => float.Parse(x, System.Globalization.CultureInfo.InvariantCulture)).ToArray();
|
||||
return new Single3(offset[0], offset[1], offset[2]);
|
||||
}
|
||||
|
||||
static Channel[] ParseChannel(string line)
|
||||
{
|
||||
var split = line.Trim().Split();
|
||||
if (split[0] != "CHANNELS")
|
||||
{
|
||||
throw new BvhException("CHANNELS is not found");
|
||||
}
|
||||
var count = int.Parse(split[1]);
|
||||
if (count + 2 != split.Length)
|
||||
{
|
||||
throw new BvhException("channel count is not match with split count");
|
||||
}
|
||||
return split.Skip(2).Select(x => (Channel)Enum.Parse(typeof(Channel), x)).ToArray();
|
||||
}
|
||||
|
||||
public IEnumerable<BvhNode> Traverse()
|
||||
{
|
||||
yield return this;
|
||||
|
||||
foreach (var child in Children)
|
||||
{
|
||||
foreach (var descendant in child.Traverse())
|
||||
{
|
||||
yield return descendant;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public class EndSite : BvhNode
|
||||
{
|
||||
public EndSite() : base("")
|
||||
{
|
||||
}
|
||||
|
||||
public override void Parse(StringReader r)
|
||||
{
|
||||
r.ReadLine(); // offset
|
||||
}
|
||||
}
|
||||
|
||||
public class ChannelCurve
|
||||
{
|
||||
public float[] Keys
|
||||
{
|
||||
get;
|
||||
private set;
|
||||
}
|
||||
|
||||
public ChannelCurve(int frameCount)
|
||||
{
|
||||
Keys = new float[frameCount];
|
||||
}
|
||||
|
||||
public void SetKey(int frame, float value)
|
||||
{
|
||||
Keys[frame] = value;
|
||||
}
|
||||
}
|
||||
|
||||
public class Bvh
|
||||
{
|
||||
public BvhNode Root
|
||||
@@ -192,7 +20,7 @@ namespace UniHumanoid
|
||||
private set;
|
||||
}
|
||||
|
||||
public ChannelCurve[] Channels
|
||||
public BvhChannelCurve[] Channels
|
||||
{
|
||||
get;
|
||||
private set;
|
||||
@@ -211,7 +39,7 @@ namespace UniHumanoid
|
||||
public bool IsLocation;
|
||||
}
|
||||
|
||||
public bool TryGetPathWithPropertyFromChannel(ChannelCurve channel, out PathWithProperty pathWithProp)
|
||||
public bool TryGetPathWithPropertyFromChannel(BvhChannelCurve channel, out PathWithProperty pathWithProp)
|
||||
{
|
||||
var index = Channels.ToList().IndexOf(channel);
|
||||
if (index == -1)
|
||||
@@ -270,7 +98,7 @@ namespace UniHumanoid
|
||||
return null;
|
||||
}
|
||||
|
||||
public ChannelCurve GetChannel(BvhNode target, Channel channel)
|
||||
public BvhChannelCurve GetChannel(BvhNode target, BvhChannel channel)
|
||||
{
|
||||
var index = 0;
|
||||
foreach (var node in Root.Traverse())
|
||||
@@ -306,7 +134,7 @@ namespace UniHumanoid
|
||||
.Select(x => x.Channels.Length)
|
||||
.Sum();
|
||||
Channels = Enumerable.Range(0, channelCount)
|
||||
.Select(x => new ChannelCurve(frames))
|
||||
.Select(x => new BvhChannelCurve(frames))
|
||||
.ToArray()
|
||||
;
|
||||
}
|
||||
@@ -410,7 +238,7 @@ namespace UniHumanoid
|
||||
{
|
||||
throw new BvhException("End in level 0");
|
||||
}
|
||||
node = new EndSite();
|
||||
node = new BvhEndSite();
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -433,7 +261,7 @@ namespace UniHumanoid
|
||||
break;
|
||||
}
|
||||
|
||||
if (!(child is EndSite))
|
||||
if (!(child is BvhEndSite))
|
||||
{
|
||||
node.Children.Add(child);
|
||||
}
|
||||
|
||||
45
Assets/UniGLTF/Runtime/UniHumanoid/Format/BvhChannel.cs
Normal file
45
Assets/UniGLTF/Runtime/UniHumanoid/Format/BvhChannel.cs
Normal file
@@ -0,0 +1,45 @@
|
||||
namespace UniHumanoid
|
||||
{
|
||||
public enum BvhChannel
|
||||
{
|
||||
Xposition,
|
||||
Yposition,
|
||||
Zposition,
|
||||
Xrotation,
|
||||
Yrotation,
|
||||
Zrotation,
|
||||
}
|
||||
|
||||
public static class BvhChannelExtensions
|
||||
{
|
||||
public static string ToProperty(this BvhChannel ch)
|
||||
{
|
||||
switch (ch)
|
||||
{
|
||||
case BvhChannel.Xposition: return "localPosition.x";
|
||||
case BvhChannel.Yposition: return "localPosition.y";
|
||||
case BvhChannel.Zposition: return "localPosition.z";
|
||||
case BvhChannel.Xrotation: return "localEulerAnglesBaked.x";
|
||||
case BvhChannel.Yrotation: return "localEulerAnglesBaked.y";
|
||||
case BvhChannel.Zrotation: return "localEulerAnglesBaked.z";
|
||||
}
|
||||
|
||||
throw new BvhException("no property for " + ch);
|
||||
}
|
||||
|
||||
public static bool IsLocation(this BvhChannel ch)
|
||||
{
|
||||
switch (ch)
|
||||
{
|
||||
case BvhChannel.Xposition:
|
||||
case BvhChannel.Yposition:
|
||||
case BvhChannel.Zposition: return true;
|
||||
case BvhChannel.Xrotation:
|
||||
case BvhChannel.Yrotation:
|
||||
case BvhChannel.Zrotation: return false;
|
||||
}
|
||||
|
||||
throw new BvhException("no property for " + ch);
|
||||
}
|
||||
}
|
||||
}
|
||||
11
Assets/UniGLTF/Runtime/UniHumanoid/Format/BvhChannel.cs.meta
Normal file
11
Assets/UniGLTF/Runtime/UniHumanoid/Format/BvhChannel.cs.meta
Normal file
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 885c621c7dd0faf4e8e3de2e0187d2ac
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
21
Assets/UniGLTF/Runtime/UniHumanoid/Format/BvhChannelCurve.cs
Normal file
21
Assets/UniGLTF/Runtime/UniHumanoid/Format/BvhChannelCurve.cs
Normal file
@@ -0,0 +1,21 @@
|
||||
namespace UniHumanoid
|
||||
{
|
||||
public class BvhChannelCurve
|
||||
{
|
||||
public float[] Keys
|
||||
{
|
||||
get;
|
||||
private set;
|
||||
}
|
||||
|
||||
public BvhChannelCurve(int frameCount)
|
||||
{
|
||||
Keys = new float[frameCount];
|
||||
}
|
||||
|
||||
public void SetKey(int frame, float value)
|
||||
{
|
||||
Keys[frame] = value;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 588638a01ee0b7c47bd731aeed170cea
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
16
Assets/UniGLTF/Runtime/UniHumanoid/Format/BvhEndSite.cs
Normal file
16
Assets/UniGLTF/Runtime/UniHumanoid/Format/BvhEndSite.cs
Normal file
@@ -0,0 +1,16 @@
|
||||
using System.IO;
|
||||
|
||||
namespace UniHumanoid
|
||||
{
|
||||
public class BvhEndSite : BvhNode
|
||||
{
|
||||
public BvhEndSite() : base("")
|
||||
{
|
||||
}
|
||||
|
||||
public override void Parse(StringReader r)
|
||||
{
|
||||
r.ReadLine(); // offset
|
||||
}
|
||||
}
|
||||
}
|
||||
11
Assets/UniGLTF/Runtime/UniHumanoid/Format/BvhEndSite.cs.meta
Normal file
11
Assets/UniGLTF/Runtime/UniHumanoid/Format/BvhEndSite.cs.meta
Normal file
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: bc2103bbe9c95224e9458e1fb058140f
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,9 @@
|
||||
using System;
|
||||
|
||||
namespace UniHumanoid
|
||||
{
|
||||
public class BvhException : Exception
|
||||
{
|
||||
public BvhException(string msg) : base(msg) { }
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 86267a6edfc8fc749948c586e622846f
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
100
Assets/UniGLTF/Runtime/UniHumanoid/Format/BvhNode.cs
Normal file
100
Assets/UniGLTF/Runtime/UniHumanoid/Format/BvhNode.cs
Normal file
@@ -0,0 +1,100 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using UnityEngine;
|
||||
|
||||
namespace UniHumanoid
|
||||
{
|
||||
public class BvhNode
|
||||
{
|
||||
public String Name
|
||||
{
|
||||
get;
|
||||
private set;
|
||||
}
|
||||
|
||||
public Vector3 Offset
|
||||
{
|
||||
get;
|
||||
private set;
|
||||
}
|
||||
|
||||
public BvhChannel[] Channels
|
||||
{
|
||||
get;
|
||||
private set;
|
||||
}
|
||||
|
||||
public List<BvhNode> Children
|
||||
{
|
||||
get;
|
||||
private set;
|
||||
}
|
||||
|
||||
public BvhNode(string name)
|
||||
{
|
||||
Name = name;
|
||||
Children = new List<BvhNode>();
|
||||
}
|
||||
|
||||
public int GetChannelIndex(BvhChannel 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());
|
||||
|
||||
Channels = ParseChannel(r.ReadLine());
|
||||
}
|
||||
|
||||
private static Vector3 ParseOffset(string line)
|
||||
{
|
||||
string[] split = line.Trim().Split();
|
||||
if (split[0] != "OFFSET")
|
||||
{
|
||||
throw new BvhException("OFFSET is not found");
|
||||
}
|
||||
|
||||
var offset = split.Skip(1).Where(x => !string.IsNullOrEmpty(x)).Select(x => float.Parse(x, System.Globalization.CultureInfo.InvariantCulture)).ToArray();
|
||||
return new Vector3(offset[0], offset[1], offset[2]);
|
||||
}
|
||||
|
||||
private static BvhChannel[] ParseChannel(string line)
|
||||
{
|
||||
var split = line.Trim().Split();
|
||||
if (split[0] != "CHANNELS")
|
||||
{
|
||||
throw new BvhException("CHANNELS is not found");
|
||||
}
|
||||
var count = int.Parse(split[1]);
|
||||
if (count + 2 != split.Length)
|
||||
{
|
||||
throw new BvhException("channel count is not match with split count");
|
||||
}
|
||||
return split.Skip(2).Select(x => (BvhChannel)Enum.Parse(typeof(BvhChannel), x)).ToArray();
|
||||
}
|
||||
|
||||
public IEnumerable<BvhNode> Traverse()
|
||||
{
|
||||
yield return this;
|
||||
|
||||
foreach (var child in Children)
|
||||
{
|
||||
foreach (var descendant in child.Traverse())
|
||||
{
|
||||
yield return descendant;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
11
Assets/UniGLTF/Runtime/UniHumanoid/Format/BvhNode.cs.meta
Normal file
11
Assets/UniGLTF/Runtime/UniHumanoid/Format/BvhNode.cs.meta
Normal file
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 7f4ac3efd1faca94381a344a5be51cc2
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -16,9 +16,9 @@ namespace UniHumanoid
|
||||
Node = node;
|
||||
}
|
||||
|
||||
public ChannelCurve PositionX;
|
||||
public ChannelCurve PositionY;
|
||||
public ChannelCurve PositionZ;
|
||||
public BvhChannelCurve PositionX;
|
||||
public BvhChannelCurve PositionY;
|
||||
public BvhChannelCurve PositionZ;
|
||||
public Vector3 GetPosition(int i)
|
||||
{
|
||||
return new Vector3(
|
||||
@@ -27,9 +27,9 @@ namespace UniHumanoid
|
||||
PositionZ.Keys[i]);
|
||||
}
|
||||
|
||||
public ChannelCurve RotationX;
|
||||
public ChannelCurve RotationY;
|
||||
public ChannelCurve RotationZ;
|
||||
public BvhChannelCurve RotationX;
|
||||
public BvhChannelCurve RotationY;
|
||||
public BvhChannelCurve RotationZ;
|
||||
public Quaternion GetRotation(int i)
|
||||
{
|
||||
if (EulerToRotation == null)
|
||||
@@ -43,7 +43,7 @@ namespace UniHumanoid
|
||||
);
|
||||
}
|
||||
|
||||
static void AddCurve(Bvh bvh, AnimationClip clip, ChannelCurve ch, float scaling)
|
||||
static void AddCurve(Bvh bvh, AnimationClip clip, BvhChannelCurve ch, float scaling)
|
||||
{
|
||||
if (ch == null) return;
|
||||
var pathWithProp = default(Bvh.PathWithProperty);
|
||||
@@ -106,12 +106,12 @@ namespace UniHumanoid
|
||||
var curve = bvh.Channels[j];
|
||||
switch (node.Channels[i])
|
||||
{
|
||||
case Channel.Xposition: set.PositionX = curve; break;
|
||||
case Channel.Yposition: set.PositionY = curve; break;
|
||||
case Channel.Zposition: set.PositionZ = curve; break;
|
||||
case Channel.Xrotation: set.RotationX = curve; break;
|
||||
case Channel.Yrotation: set.RotationY = curve; break;
|
||||
case Channel.Zrotation: set.RotationZ = curve; break;
|
||||
case BvhChannel.Xposition: set.PositionX = curve; break;
|
||||
case BvhChannel.Yposition: set.PositionY = curve; break;
|
||||
case BvhChannel.Zposition: set.PositionZ = curve; break;
|
||||
case BvhChannel.Xrotation: set.RotationX = curve; break;
|
||||
case BvhChannel.Yrotation: set.RotationY = curve; break;
|
||||
case BvhChannel.Zrotation: set.RotationZ = curve; break;
|
||||
default: throw new Exception();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -75,11 +75,15 @@ namespace UniHumanoid
|
||||
//
|
||||
// scaling. reposition
|
||||
//
|
||||
var yCh = Bvh.Root.GetChannelIndex(BvhChannel.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())
|
||||
|
||||
@@ -9,7 +9,7 @@ namespace UniHumanoid
|
||||
{
|
||||
public static Func<float, float, float, Quaternion> GetEulerToRotation(this BvhNode bvh)
|
||||
{
|
||||
var order = bvh.Channels.Where(x => x == Channel.Xrotation || x == Channel.Yrotation || x == Channel.Zrotation).ToArray();
|
||||
var order = bvh.Channels.Where(x => x == BvhChannel.Xrotation || x == BvhChannel.Yrotation || x == BvhChannel.Zrotation).ToArray();
|
||||
|
||||
return (x, y, z) =>
|
||||
{
|
||||
@@ -22,9 +22,9 @@ namespace UniHumanoid
|
||||
{
|
||||
switch (ch)
|
||||
{
|
||||
case Channel.Xrotation: r = r * xRot; break;
|
||||
case Channel.Yrotation: r = r * yRot; break;
|
||||
case Channel.Zrotation: r = r * zRot; break;
|
||||
case BvhChannel.Xrotation: r = r * xRot; break;
|
||||
case BvhChannel.Yrotation: r = r * yRot; break;
|
||||
case BvhChannel.Zrotation: r = r * zRot; break;
|
||||
default: throw new BvhException("no rotation");
|
||||
}
|
||||
}
|
||||
@@ -32,12 +32,12 @@ namespace UniHumanoid
|
||||
};
|
||||
}
|
||||
|
||||
public static Vector3 ToVector3(this Single3 s3)
|
||||
public static Vector3 ToVector3(this Vector3 s3)
|
||||
{
|
||||
return new Vector3(s3.x, s3.y, s3.z);
|
||||
}
|
||||
|
||||
public static Vector3 ToXReversedVector3(this Single3 s3)
|
||||
public static Vector3 ToXReversedVector3(this Vector3 s3)
|
||||
{
|
||||
return new Vector3(-s3.x, s3.y, s3.z);
|
||||
}
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -23,8 +23,6 @@ namespace UniVRM10
|
||||
public IReadOnlyDictionary<HumanBodyBones, Vrm10ControlBone> Bones => _bones;
|
||||
public Animator ControlRigAnimator { get; }
|
||||
|
||||
public float InitialHipsHeight => HipTPoseWorldPosition.y;
|
||||
|
||||
/// <summary>
|
||||
/// humanoid に対して ControlRig を生成します
|
||||
/// </summary>
|
||||
@@ -35,11 +33,9 @@ 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);
|
||||
|
||||
var transformBonePairs = _bones.Select(kv => (kv.Value.ControlBone, kv.Key));
|
||||
_controlRigAvatar = HumanoidLoader.LoadHumanoidAvatar(vrmRoot, transformBonePairs);
|
||||
_controlRigAvatar.name = "Runtime Control Rig";
|
||||
@@ -72,19 +68,11 @@ namespace UniVRM10
|
||||
}
|
||||
}
|
||||
|
||||
public void EnforceTPose()
|
||||
#region INormalizedPoseApplicable
|
||||
public void SetRawHipsPosition(Vector3 position)
|
||||
{
|
||||
SetHipsPosition(_hipBone.ControlBone.position);
|
||||
foreach (var bone in _bones.Values)
|
||||
{
|
||||
bone.ControlBone.localRotation = Quaternion.identity;
|
||||
}
|
||||
}
|
||||
|
||||
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 +82,7 @@ namespace UniVRM10
|
||||
t.ControlBone.localRotation = normalizedLocalRotation;
|
||||
}
|
||||
}
|
||||
#endregion
|
||||
|
||||
IEnumerable<(HumanBodyBones Head, HumanBodyBones Parent)> Traverse(Vrm10ControlBone bone, Vrm10ControlBone parent = null)
|
||||
{
|
||||
@@ -108,7 +97,8 @@ namespace UniVRM10
|
||||
}
|
||||
}
|
||||
|
||||
public IEnumerable<(HumanBodyBones Head, HumanBodyBones Parent)> EnumerateBones()
|
||||
#region ITPoseProvider
|
||||
public IEnumerable<(HumanBodyBones Bone, HumanBodyBones Parent)> EnumerateBoneParentPairs()
|
||||
{
|
||||
foreach (var headParent in Traverse(_hipBone))
|
||||
{
|
||||
@@ -116,11 +106,15 @@ namespace UniVRM10
|
||||
}
|
||||
}
|
||||
|
||||
public Vector3 HipTPoseWorldPosition { get; }
|
||||
|
||||
public Quaternion GetBoneTPoseWorldRotation(HumanBodyBones bone)
|
||||
public Quaternion? GetBoneWorldRotation(HumanBodyBones bone)
|
||||
{
|
||||
return Quaternion.identity;
|
||||
}
|
||||
|
||||
public Vector3? GetBoneWorldPosition(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 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()
|
||||
{
|
||||
throw new System.NotImplementedException();
|
||||
}
|
||||
|
||||
public Quaternion? GetBoneWorldRotation(HumanBodyBones bone)
|
||||
{
|
||||
throw new System.NotImplementedException();
|
||||
}
|
||||
|
||||
public Vector3? GetBoneWorldPosition(HumanBodyBones bone)
|
||||
{
|
||||
return m_posMap[bone];
|
||||
}
|
||||
#endregion
|
||||
}
|
||||
}
|
||||
@@ -5,7 +5,7 @@ namespace UniVRM10
|
||||
{
|
||||
public interface INormalizedPoseApplicable
|
||||
{
|
||||
void SetHipsPosition(Vector3 position);
|
||||
void SetRawHipsPosition(Vector3 position);
|
||||
|
||||
void SetNormalizedLocalRotation(HumanBodyBones bone, Quaternion normalizedLocalRotation);
|
||||
}
|
||||
|
||||
@@ -7,7 +7,7 @@ namespace UniVRM10
|
||||
/// <summary>
|
||||
/// Get hips position in model root space
|
||||
/// </summary>
|
||||
Vector3 GetHipsPosition();
|
||||
Vector3 GetRawHipsPosition();
|
||||
|
||||
/// <summary>
|
||||
/// Get normalized local rotation
|
||||
|
||||
@@ -6,22 +6,15 @@ namespace UniVRM10
|
||||
public interface ITPoseProvider
|
||||
{
|
||||
/// <summary>
|
||||
/// * world は ModelRoot を意図していることに注意
|
||||
/// </summary>
|
||||
Vector3 HipTPoseWorldPosition { get; }
|
||||
|
||||
/// <summary>
|
||||
/// * world は ModelRoot を意図していることに注意
|
||||
/// * bone 無いときはどう振る舞うべきか
|
||||
/// </summary>
|
||||
/// <param name="bone"></param>
|
||||
/// <returns></returns>
|
||||
Quaternion GetBoneTPoseWorldRotation(HumanBodyBones bone);
|
||||
|
||||
/// <summary>
|
||||
/// ボーンを親ボーンとセットで列挙する</returns>
|
||||
/// このTPoseに含まれるボーンと親ボーンの組み合わせを列挙する。
|
||||
///
|
||||
/// * Humanoidの木構造を深さ優先の順番で列挙する
|
||||
///
|
||||
/// </summary>
|
||||
/// <returns>hips の場合は parent は HumanBodyBones.LastBone で null を表す</returns>
|
||||
IEnumerable<(HumanBodyBones Head, HumanBodyBones Parent)> EnumerateBones();
|
||||
IEnumerable<(HumanBodyBones Bone, HumanBodyBones Parent)> EnumerateBoneParentPairs();
|
||||
|
||||
Quaternion? GetBoneWorldRotation(HumanBodyBones bone);
|
||||
Vector3? GetBoneWorldPosition(HumanBodyBones bone);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -44,7 +44,7 @@ namespace UniVRM10
|
||||
}
|
||||
}
|
||||
|
||||
public Vector3 GetHipsPosition()
|
||||
public Vector3 GetRawHipsPosition()
|
||||
{
|
||||
if (m_hips.parent == m_root)
|
||||
{
|
||||
@@ -56,12 +56,17 @@ namespace UniVRM10
|
||||
}
|
||||
}
|
||||
|
||||
public Quaternion GetBoneTPoseWorldRotation(HumanBodyBones bone)
|
||||
public IEnumerable<(HumanBodyBones Bone, HumanBodyBones Parent)> EnumerateBoneParentPairs()
|
||||
{
|
||||
throw new System.NotImplementedException();
|
||||
}
|
||||
|
||||
public IEnumerable<(HumanBodyBones Head, HumanBodyBones Parent)> EnumerateBones()
|
||||
public Quaternion? GetBoneWorldRotation(HumanBodyBones bone)
|
||||
{
|
||||
throw new System.NotImplementedException();
|
||||
}
|
||||
|
||||
public Vector3? GetBoneWorldPosition(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();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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;
|
||||
@@ -87,115 +88,5 @@ namespace UniVRM10.VRM10Viewer
|
||||
// destroy GameObject
|
||||
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;
|
||||
controlRig.EnforceTPose();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
72
Assets/VRM10_Samples/VRM10Viewer/VRM10Motion.cs
Normal file
72
Assets/VRM10_Samples/VRM10Viewer/VRM10Motion.cs
Normal file
@@ -0,0 +1,72 @@
|
||||
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 AnimatorPoseProvider(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;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
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:
|
||||
@@ -1,15 +1,31 @@
|
||||
namespace UniVRM10
|
||||
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.EnumerateBones())
|
||||
foreach (var (head, parent) in sink.TPose.EnumerateBoneParentPairs())
|
||||
{
|
||||
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.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);
|
||||
}
|
||||
|
||||
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.GetBoneWorldPosition(HumanBodyBones.Hips).Value);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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,11 +237,11 @@ namespace UniVRM10.VRM10Viewer
|
||||
{
|
||||
if (m_ui.IsBvhEnabled && m_src != null)
|
||||
{
|
||||
m_loaded.UpdateControlRigImplicit(m_src);
|
||||
VRM10Retarget.Retarget(m_src.ControlRig, (m_loaded.ControlRig, m_loaded.ControlRig));
|
||||
}
|
||||
else
|
||||
{
|
||||
m_loaded.TPoseControlRig();
|
||||
VRM10Retarget.EnforceTPose((m_loaded.ControlRig, m_loaded.ControlRig));
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -280,7 +263,7 @@ namespace UniVRM10.VRM10Viewer
|
||||
var ext = Path.GetExtension(path).ToLower();
|
||||
if (ext == ".bvh")
|
||||
{
|
||||
LoadMotion(path);
|
||||
m_src = VRM10Motion.LoadBvhFromPath(path);
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user