mirror of
https://github.com/vrm-c/UniVRM.git
synced 2026-05-14 22:50:08 -05:00
Merge pull request #1775 from Santarh/controlRig2
Refactoring about ControlRig
This commit is contained in:
commit
157c48ca06
|
|
@ -5,99 +5,94 @@ using UnityEngine;
|
|||
namespace UniVRM10
|
||||
{
|
||||
/// <summary>
|
||||
/// The control bone of the control rig.
|
||||
///
|
||||
/// このクラスのヒエラルキーが 正規化された TPose を表している。
|
||||
/// 同時に、元のヒエラルキーの初期回転を保持する。
|
||||
/// Apply 関数で、再帰的に正規化済みのローカル回転から初期回転を加味したローカル回転を作って適用する。
|
||||
/// </summary>
|
||||
public class Vrm10ControlBone
|
||||
public sealed class Vrm10ControlBone
|
||||
{
|
||||
public readonly HumanBodyBones Bone;
|
||||
/// <summary>
|
||||
/// このボーンに紐づく種類。
|
||||
/// </summary>
|
||||
public HumanBodyBones BoneType { get; }
|
||||
|
||||
/// <summary>
|
||||
/// 元のヒエラルキーの対応ボーン
|
||||
/// コントロール対象のボーン Transform。
|
||||
/// </summary>
|
||||
public readonly Transform Target;
|
||||
public Transform ControlTarget { get; }
|
||||
|
||||
/// <summary>
|
||||
/// 回転と拡大縮小を除去した(正規化された)ボーン。
|
||||
/// このボーンに対して localRotation を代入する。
|
||||
/// コントロールのためのボーン Transform。
|
||||
///
|
||||
/// VRM の T-Pose 姿勢をしているときに、回転とスケールが初期値になっている(正規化)。
|
||||
/// このボーンに対して localRotation を代入し、コントロールを行う。
|
||||
/// </summary>
|
||||
public readonly Transform Normalized;
|
||||
public Transform ControlBone { get; }
|
||||
|
||||
/// <summary>
|
||||
/// 元のボーンの初期回転。
|
||||
/// </summary>
|
||||
public readonly Quaternion InitialLocalRotation;
|
||||
private readonly Quaternion _initialTargetLocalRotation;
|
||||
private readonly Quaternion _initialTargetGlobalRotation;
|
||||
private readonly List<Vrm10ControlBone> _children = new List<Vrm10ControlBone>();
|
||||
|
||||
public readonly Quaternion ToLocal;
|
||||
|
||||
public List<Vrm10ControlBone> Children = new List<Vrm10ControlBone>();
|
||||
|
||||
public Vrm10ControlBone(Transform current, Quaternion parentInverse, HumanBodyBones bone)
|
||||
internal Vrm10ControlBone(Transform controlTarget, HumanBodyBones boneType)
|
||||
{
|
||||
if (bone == HumanBodyBones.LastBone)
|
||||
if (boneType == HumanBodyBones.LastBone)
|
||||
{
|
||||
throw new ArgumentNullException();
|
||||
}
|
||||
if (current == null)
|
||||
if (controlTarget == null)
|
||||
{
|
||||
throw new ArgumentNullException();
|
||||
}
|
||||
Bone = bone;
|
||||
Target = current;
|
||||
Normalized = new GameObject(bone.ToString()).transform;
|
||||
Normalized.position = current.position;
|
||||
// InitialLocalRotation = parentInverse * current.rotation;
|
||||
InitialLocalRotation = current.localRotation;
|
||||
// InitialLocalRotation = current.rotation;
|
||||
ToLocal = current.rotation;
|
||||
|
||||
BoneType = boneType;
|
||||
ControlTarget = controlTarget;
|
||||
ControlBone = new GameObject(boneType.ToString()).transform;
|
||||
ControlBone.position = controlTarget.position;
|
||||
_initialTargetLocalRotation = controlTarget.localRotation;
|
||||
_initialTargetGlobalRotation = controlTarget.rotation;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 親から再帰的にNormalized の ローカル回転を初期回転を加味して Target に適用する。
|
||||
/// </summary>
|
||||
internal void ProcessRecursively()
|
||||
{
|
||||
ControlTarget.localRotation = _initialTargetLocalRotation * Quaternion.Inverse(_initialTargetGlobalRotation) * ControlBone.localRotation * _initialTargetGlobalRotation;
|
||||
foreach (var child in _children)
|
||||
{
|
||||
child.ProcessRecursively();
|
||||
}
|
||||
}
|
||||
|
||||
public static Vrm10ControlBone Build(UniHumanoid.Humanoid humanoid, Dictionary<HumanBodyBones, Vrm10ControlBone> boneMap)
|
||||
{
|
||||
var hips = new Vrm10ControlBone(humanoid.Hips, Quaternion.identity, HumanBodyBones.Hips);
|
||||
var hips = new Vrm10ControlBone(humanoid.Hips, HumanBodyBones.Hips);
|
||||
boneMap.Add(HumanBodyBones.Hips, hips);
|
||||
|
||||
foreach (Transform child in humanoid.Hips)
|
||||
{
|
||||
Traverse(humanoid, child, hips, boneMap);
|
||||
BuildRecursively(humanoid, child, hips, boneMap);
|
||||
}
|
||||
|
||||
return hips;
|
||||
}
|
||||
|
||||
private static void Traverse(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)
|
||||
{
|
||||
if (humanoid.TryGetBoneForTransform(current, out var bone))
|
||||
{
|
||||
|
||||
// ヒューマンボーンだけを対象にするので、
|
||||
// parent が current の直接の親でない場合がある。
|
||||
// ワールド回転 parent^-1 * current からローカル回転を算出する。
|
||||
var parentInverse = Quaternion.Inverse(parent.Target.rotation);
|
||||
|
||||
var newBone = new Vrm10ControlBone(current, parentInverse, bone);
|
||||
newBone.Normalized.SetParent(parent.Normalized, true);
|
||||
parent.Children.Add(newBone);
|
||||
var newBone = new Vrm10ControlBone(current, bone);
|
||||
newBone.ControlBone.SetParent(parent.ControlBone, true);
|
||||
parent._children.Add(newBone);
|
||||
parent = newBone;
|
||||
boneMap.Add(bone, newBone);
|
||||
}
|
||||
|
||||
foreach (Transform child in current)
|
||||
{
|
||||
Traverse(humanoid, child, parent, boneMap);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 親から再帰的にNormalized の ローカル回転を初期回転を加味して Target に適用する。
|
||||
/// </summary>
|
||||
public void ApplyRecursive(Quaternion worldParentRotation)
|
||||
{
|
||||
Target.localRotation = InitialLocalRotation * Quaternion.Inverse(ToLocal) * Normalized.localRotation * ToLocal;
|
||||
foreach (var child in Children)
|
||||
{
|
||||
child.ApplyRecursive(Normalized.rotation);
|
||||
BuildRecursively(humanoid, child, parent, boneMap);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -9,7 +9,14 @@ using UniVRM10.FastSpringBones.System;
|
|||
namespace UniVRM10
|
||||
{
|
||||
/// <summary>
|
||||
/// Play時 と Editorからの参照情報置き場
|
||||
/// VRM モデルインスタンスを、状態をもって、元の状態から操作・変更するためのクラス。
|
||||
/// また、仕様に従ってその操作を行う。
|
||||
///
|
||||
/// 操作対象としては以下が挙げられる。
|
||||
/// - ControlRig
|
||||
/// - Constraint
|
||||
/// - LookAt
|
||||
/// - Expression
|
||||
/// </summary>
|
||||
public class Vrm10Runtime : IDisposable
|
||||
{
|
||||
|
|
|
|||
|
|
@ -10,31 +10,31 @@ namespace UniVRM10
|
|||
/// Create a control rig for the VRM 1.0 model instance.
|
||||
/// This provides the normalized operation of bones, like VRM 0.x.
|
||||
/// </summary>
|
||||
public class Vrm10RuntimeControlRig
|
||||
public sealed class Vrm10RuntimeControlRig
|
||||
{
|
||||
private readonly Vrm10ControlBone _rootBone;
|
||||
private readonly Dictionary<HumanBodyBones, Vrm10ControlBone> _bones = new Dictionary<HumanBodyBones, Vrm10ControlBone>();
|
||||
|
||||
public readonly float InitialHipsHeight;
|
||||
public float InitialHipsHeight { get; }
|
||||
|
||||
public Vrm10RuntimeControlRig(UniHumanoid.Humanoid humanoid)
|
||||
{
|
||||
_rootBone = Vrm10ControlBone.Build(humanoid, _bones);
|
||||
InitialHipsHeight = _rootBone.Target.position.y;
|
||||
InitialHipsHeight = _rootBone.ControlTarget.position.y;
|
||||
Debug.Log($"InitialHipsHeight: {InitialHipsHeight}");
|
||||
}
|
||||
|
||||
public void Process()
|
||||
{
|
||||
_rootBone.Target.position = _rootBone.Normalized.position;
|
||||
_rootBone.ApplyRecursive(Quaternion.identity);
|
||||
_rootBone.ControlTarget.position = _rootBone.ControlBone.position;
|
||||
_rootBone.ProcessRecursively();
|
||||
}
|
||||
|
||||
public Transform GetBoneTransform(HumanBodyBones bone)
|
||||
{
|
||||
if (_bones.TryGetValue(bone, out var value))
|
||||
{
|
||||
return value.Normalized;
|
||||
return value.ControlBone;
|
||||
}
|
||||
else
|
||||
{
|
||||
|
|
|
|||
Loading…
Reference in New Issue
Block a user