mirror of
https://github.com/vrm-c/UniVRM.git
synced 2026-08-20 01:25:45 -05:00
Vrm10RuntimeControlRig は、正規化されたTPoseを受け取る責務に特化して単純化する。
初期回転を持つポーズの受付は、Vrm10BoneInitialRotation を使う別クラスに委譲する。 (次で作ります)
This commit is contained in:
@@ -67,12 +67,8 @@ namespace UniVRM10
|
||||
|
||||
/// <summary>
|
||||
/// ControlRig の生成オプション
|
||||
///
|
||||
/// null: ControlRigGenerationOption.None
|
||||
/// empty: ControlRigGenerationOption.Generate = Vrm0XCompatibleRig
|
||||
/// other: ControlRigGenerationOption.Vrm0XCompatibleWithXR_EXT_hand_tracking など
|
||||
/// </summary>
|
||||
private IReadOnlyDictionary<HumanBodyBones, Quaternion> m_controlRigInitialRotations;
|
||||
private bool m_useControlRig;
|
||||
|
||||
/// <summary>
|
||||
/// VRM ファイルに記録された Humanoid ボーンに対応します。
|
||||
@@ -99,15 +95,15 @@ namespace UniVRM10
|
||||
{
|
||||
if (m_runtime == null)
|
||||
{
|
||||
m_runtime = new Vrm10Runtime(this, m_controlRigInitialRotations);
|
||||
m_runtime = new Vrm10Runtime(this, m_useControlRig);
|
||||
}
|
||||
return m_runtime;
|
||||
}
|
||||
}
|
||||
|
||||
internal void InitializeAtRuntime(IReadOnlyDictionary<HumanBodyBones, Quaternion> controlRigInitialRotations)
|
||||
internal void InitializeAtRuntime(bool useControlRig)
|
||||
{
|
||||
m_controlRigInitialRotations = controlRigInitialRotations;
|
||||
m_useControlRig = useControlRig;
|
||||
}
|
||||
|
||||
void Start()
|
||||
|
||||
@@ -49,7 +49,7 @@ namespace UniVRM10
|
||||
}
|
||||
}
|
||||
|
||||
public Vrm10Runtime(Vrm10Instance target, IReadOnlyDictionary<HumanBodyBones, Quaternion> controlRigInitialRotations)
|
||||
public Vrm10Runtime(Vrm10Instance target, bool useControlRig)
|
||||
{
|
||||
m_target = target;
|
||||
|
||||
@@ -58,9 +58,9 @@ namespace UniVRM10
|
||||
throw new Exception();
|
||||
}
|
||||
|
||||
if (controlRigInitialRotations != null)
|
||||
if (useControlRig)
|
||||
{
|
||||
ControlRig = new Vrm10RuntimeControlRig(target.Humanoid, m_target.transform, controlRigInitialRotations);
|
||||
ControlRig = new Vrm10RuntimeControlRig(target.Humanoid, m_target.transform);
|
||||
}
|
||||
Constraints = target.GetComponentsInChildren<IVrm10Constraint>();
|
||||
LookAt = new Vrm10RuntimeLookAt(target.Vrm.LookAt, target.Humanoid, ControlRig);
|
||||
|
||||
@@ -29,18 +29,12 @@ namespace UniVRM10
|
||||
/// </summary>
|
||||
/// <param name="humanoid">T-Pose である必要があります</param>
|
||||
/// <param name="vrmRoot"></param>
|
||||
/// <param name="controlRigInitialRotations">ControlRigの各ボーンの初期回転を表します</param>
|
||||
public Vrm10RuntimeControlRig(UniHumanoid.Humanoid humanoid, Transform vrmRoot, IReadOnlyDictionary<HumanBodyBones, Quaternion> controlRigInitialRotations)
|
||||
public Vrm10RuntimeControlRig(UniHumanoid.Humanoid humanoid, Transform vrmRoot)
|
||||
{
|
||||
if (controlRigInitialRotations == null)
|
||||
{
|
||||
throw new ArgumentNullException();
|
||||
}
|
||||
|
||||
_controlRigRoot = new GameObject("Runtime Control Rig").transform;
|
||||
_controlRigRoot.SetParent(vrmRoot);
|
||||
|
||||
_hipBone = Vrm10ControlBone.Build(humanoid, controlRigInitialRotations, out _bones);
|
||||
_hipBone = Vrm10ControlBone.Build(humanoid, out _bones);
|
||||
_hipBone.ControlBone.SetParent(_controlRigRoot);
|
||||
|
||||
InitialHipsHeight = _hipBone.ControlTarget.position.y;
|
||||
@@ -79,10 +73,11 @@ namespace UniVRM10
|
||||
|
||||
public void EnforceTPose()
|
||||
{
|
||||
// TODO: restore hips position
|
||||
|
||||
foreach (var bone in _bones.Values)
|
||||
{
|
||||
bone.ControlBone.localPosition = bone.InitialControlBoneLocalPosition;
|
||||
bone.ControlBone.localRotation = bone.InitialControlBoneLocalRotation;
|
||||
bone.ControlBone.localRotation = Quaternion.identity;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
39
Assets/VRM10/Runtime/ControlRig/Vrm10BoneInitialRotation.cs
Normal file
39
Assets/VRM10/Runtime/ControlRig/Vrm10BoneInitialRotation.cs
Normal file
@@ -0,0 +1,39 @@
|
||||
using UnityEngine;
|
||||
|
||||
namespace UniVRM10
|
||||
{
|
||||
/// <summary>
|
||||
/// Represents the rotation at the initial pose (TPose)
|
||||
/// </summary>
|
||||
public readonly struct Vrm10BoneInitialRotation
|
||||
{
|
||||
public readonly Transform Transform;
|
||||
|
||||
public readonly Vector3 InitialLocalPosition;
|
||||
|
||||
public readonly Quaternion InitialLocalRotation;
|
||||
|
||||
public readonly Quaternion InitialGlobalRotation;
|
||||
|
||||
public Vrm10BoneInitialRotation(Transform transform)
|
||||
{
|
||||
Transform = transform;
|
||||
InitialLocalPosition = transform.localPosition;
|
||||
InitialLocalRotation = transform.localRotation;
|
||||
InitialGlobalRotation = transform.rotation;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 初期姿勢からの相対的な回転。
|
||||
///
|
||||
/// VRM-0.X 互換リグでは localRotation と同じ値を示す。
|
||||
/// </summary>
|
||||
Quaternion NormalizedLocalRotation
|
||||
{
|
||||
get
|
||||
{
|
||||
return InitialGlobalRotation * Quaternion.Inverse(InitialLocalRotation) * Transform.localRotation * Quaternion.Inverse(InitialGlobalRotation);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: db1187bf0b13152439c8a145d9631916
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -31,22 +31,11 @@ namespace UniVRM10
|
||||
/// </summary>
|
||||
public Transform ControlBone { get; }
|
||||
|
||||
/// <summary>
|
||||
/// コントロールボーンの初期ローカル位置。
|
||||
/// </summary>
|
||||
public Vector3 InitialControlBoneLocalPosition { get; }
|
||||
|
||||
/// <summary>
|
||||
/// コントロールボーンの初期ローカル回転。
|
||||
/// </summary>
|
||||
public Quaternion InitialControlBoneLocalRotation { get; }
|
||||
|
||||
private readonly Quaternion _initialControlBoneGlobalRotation;
|
||||
private readonly Quaternion _initialTargetLocalRotation;
|
||||
private readonly Quaternion _initialTargetGlobalRotation;
|
||||
private readonly List<Vrm10ControlBone> _children = new List<Vrm10ControlBone>();
|
||||
|
||||
private Vrm10ControlBone(Transform controlTarget, HumanBodyBones boneType, Vrm10ControlBone parent, IReadOnlyDictionary<HumanBodyBones, Quaternion> controlRigInitialRotations)
|
||||
private Vrm10ControlBone(Transform controlTarget, HumanBodyBones boneType, Vrm10ControlBone parent)
|
||||
{
|
||||
if (boneType == HumanBodyBones.LastBone)
|
||||
{
|
||||
@@ -59,81 +48,59 @@ namespace UniVRM10
|
||||
|
||||
BoneType = boneType;
|
||||
ControlTarget = controlTarget;
|
||||
|
||||
// 回転とスケールが除去されたTPoseを構築
|
||||
// NOTE: bone name must be unique in the vrm instance.
|
||||
ControlBone = new GameObject($"{nameof(Vrm10ControlBone)}:{boneType.ToString()}").transform;
|
||||
if (controlRigInitialRotations != null)
|
||||
{
|
||||
if (controlRigInitialRotations.TryGetValue(boneType, out var rotation))
|
||||
{
|
||||
ControlBone.rotation = rotation;
|
||||
}
|
||||
}
|
||||
ControlBone.position = controlTarget.position;
|
||||
|
||||
if (parent != null)
|
||||
{
|
||||
ControlBone.SetParent(parent.ControlBone, true);
|
||||
parent._children.Add(this);
|
||||
}
|
||||
|
||||
InitialControlBoneLocalPosition = ControlBone.localPosition;
|
||||
InitialControlBoneLocalRotation = ControlBone.localRotation;
|
||||
_initialControlBoneGlobalRotation = ControlBone.rotation;
|
||||
_initialTargetLocalRotation = controlTarget.localRotation;
|
||||
_initialTargetGlobalRotation = controlTarget.rotation;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 初期姿勢からの相対的な回転。
|
||||
///
|
||||
/// VRM-0.X 互換リグでは localRotation と同じ値を示す。
|
||||
/// </summary>
|
||||
Quaternion NormalizedLocalRotation
|
||||
{
|
||||
get
|
||||
{
|
||||
return _initialControlBoneGlobalRotation * Quaternion.Inverse(InitialControlBoneLocalRotation) * ControlBone.localRotation * Quaternion.Inverse(_initialControlBoneGlobalRotation);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 親から再帰的にNormalized の ローカル回転を初期回転を加味して Target に適用する。
|
||||
/// </summary>
|
||||
internal void ProcessRecursively()
|
||||
{
|
||||
ControlTarget.localRotation = _initialTargetLocalRotation * (Quaternion.Inverse(_initialTargetGlobalRotation) * NormalizedLocalRotation * _initialTargetGlobalRotation);
|
||||
ControlTarget.localRotation = _initialTargetLocalRotation * (Quaternion.Inverse(_initialTargetGlobalRotation) * ControlBone.localRotation * _initialTargetGlobalRotation);
|
||||
foreach (var child in _children)
|
||||
{
|
||||
child.ProcessRecursively();
|
||||
}
|
||||
}
|
||||
|
||||
public static Vrm10ControlBone Build(UniHumanoid.Humanoid humanoid, IReadOnlyDictionary<HumanBodyBones, Quaternion> controlRigInitialRotations, out Dictionary<HumanBodyBones, Vrm10ControlBone> boneMap)
|
||||
public static Vrm10ControlBone Build(UniHumanoid.Humanoid humanoid, out Dictionary<HumanBodyBones, Vrm10ControlBone> boneMap)
|
||||
{
|
||||
var hips = new Vrm10ControlBone(humanoid.Hips, HumanBodyBones.Hips, null, controlRigInitialRotations);
|
||||
var hips = new Vrm10ControlBone(humanoid.Hips, HumanBodyBones.Hips, null);
|
||||
boneMap = new Dictionary<HumanBodyBones, Vrm10ControlBone>();
|
||||
boneMap.Add(HumanBodyBones.Hips, hips);
|
||||
|
||||
foreach (Transform child in humanoid.Hips)
|
||||
{
|
||||
BuildRecursively(humanoid, child, hips, controlRigInitialRotations, boneMap);
|
||||
BuildRecursively(humanoid, child, hips, boneMap);
|
||||
}
|
||||
|
||||
return hips;
|
||||
}
|
||||
|
||||
private static void BuildRecursively(UniHumanoid.Humanoid humanoid, Transform current, Vrm10ControlBone parent, IReadOnlyDictionary<HumanBodyBones, Quaternion> controlRigInitialRotations, 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))
|
||||
{
|
||||
var newBone = new Vrm10ControlBone(current, bone, parent, controlRigInitialRotations);
|
||||
var newBone = new Vrm10ControlBone(current, bone, parent);
|
||||
parent = newBone;
|
||||
boneMap.Add(bone, newBone);
|
||||
}
|
||||
|
||||
foreach (Transform child in current)
|
||||
{
|
||||
BuildRecursively(humanoid, child, parent, controlRigInitialRotations, boneMap);
|
||||
BuildRecursively(humanoid, child, parent, boneMap);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -39,7 +39,7 @@ namespace UniVRM10
|
||||
public static async Task<Vrm10Instance> LoadPathAsync(
|
||||
string path,
|
||||
bool canLoadVrm0X = true,
|
||||
ControlRigGenerationOption controlRigGenerationOption = ControlRigGenerationOption.Generate,
|
||||
bool useControlRig = true,
|
||||
bool showMeshes = true,
|
||||
IAwaitCaller awaitCaller = null,
|
||||
ITextureDeserializer textureDeserializer = null,
|
||||
@@ -58,7 +58,7 @@ namespace UniVRM10
|
||||
path,
|
||||
System.IO.File.ReadAllBytes(path),
|
||||
canLoadVrm0X,
|
||||
controlRigGenerationOption,
|
||||
useControlRig,
|
||||
showMeshes,
|
||||
awaitCaller,
|
||||
textureDeserializer,
|
||||
@@ -86,7 +86,7 @@ namespace UniVRM10
|
||||
public static async Task<Vrm10Instance> LoadBytesAsync(
|
||||
byte[] bytes,
|
||||
bool canLoadVrm0X = true,
|
||||
ControlRigGenerationOption controlRigGenerationOption = ControlRigGenerationOption.Generate,
|
||||
bool useControlRig = true,
|
||||
bool showMeshes = true,
|
||||
IAwaitCaller awaitCaller = null,
|
||||
ITextureDeserializer textureDeserializer = null,
|
||||
@@ -105,7 +105,7 @@ namespace UniVRM10
|
||||
string.Empty,
|
||||
bytes,
|
||||
canLoadVrm0X,
|
||||
controlRigGenerationOption,
|
||||
useControlRig,
|
||||
showMeshes,
|
||||
awaitCaller,
|
||||
textureDeserializer,
|
||||
@@ -118,7 +118,7 @@ namespace UniVRM10
|
||||
string name,
|
||||
byte[] bytes,
|
||||
bool canLoadVrm0X,
|
||||
ControlRigGenerationOption controlRigGenerationOption,
|
||||
bool useControlRig,
|
||||
bool showMeshes,
|
||||
IAwaitCaller awaitCaller,
|
||||
ITextureDeserializer textureDeserializer,
|
||||
@@ -137,7 +137,7 @@ namespace UniVRM10
|
||||
// 1. Try loading as vrm-1.0
|
||||
var instance = await TryLoadingAsVrm10Async(
|
||||
gltfData,
|
||||
controlRigGenerationOption,
|
||||
useControlRig,
|
||||
showMeshes,
|
||||
awaitCaller,
|
||||
textureDeserializer,
|
||||
@@ -163,7 +163,7 @@ namespace UniVRM10
|
||||
// 3. Try migration from vrm-0.x into vrm-1.0
|
||||
var migratedInstance = await TryMigratingFromVrm0XAsync(
|
||||
gltfData,
|
||||
controlRigGenerationOption,
|
||||
useControlRig,
|
||||
showMeshes,
|
||||
awaitCaller,
|
||||
textureDeserializer,
|
||||
@@ -187,7 +187,7 @@ namespace UniVRM10
|
||||
|
||||
private static async Task<Vrm10Instance> TryLoadingAsVrm10Async(
|
||||
GltfData gltfData,
|
||||
ControlRigGenerationOption controlRigGenerationOption,
|
||||
bool useControlRig,
|
||||
bool showMeshes,
|
||||
IAwaitCaller awaitCaller,
|
||||
ITextureDeserializer textureDeserializer,
|
||||
@@ -213,7 +213,7 @@ namespace UniVRM10
|
||||
return await LoadVrm10DataAsync(
|
||||
vrm10Data,
|
||||
null,
|
||||
controlRigGenerationOption,
|
||||
useControlRig,
|
||||
showMeshes,
|
||||
awaitCaller,
|
||||
textureDeserializer,
|
||||
@@ -224,7 +224,7 @@ namespace UniVRM10
|
||||
|
||||
private static async Task<Vrm10Instance> TryMigratingFromVrm0XAsync(
|
||||
GltfData gltfData,
|
||||
ControlRigGenerationOption controlRigGenerationOption,
|
||||
bool useControlRig,
|
||||
bool showMeshes,
|
||||
IAwaitCaller awaitCaller,
|
||||
ITextureDeserializer textureDeserializer,
|
||||
@@ -252,7 +252,7 @@ namespace UniVRM10
|
||||
var migratedVrm10Instance = await LoadVrm10DataAsync(
|
||||
migratedVrm10Data,
|
||||
migrationData,
|
||||
controlRigGenerationOption,
|
||||
useControlRig,
|
||||
showMeshes,
|
||||
awaitCaller,
|
||||
textureDeserializer,
|
||||
@@ -270,7 +270,7 @@ namespace UniVRM10
|
||||
private static async Task<Vrm10Instance> LoadVrm10DataAsync(
|
||||
Vrm10Data vrm10Data,
|
||||
MigrationData migrationData,
|
||||
ControlRigGenerationOption controlRigGenerationOption,
|
||||
bool useControlRig,
|
||||
bool showMeshes,
|
||||
IAwaitCaller awaitCaller,
|
||||
ITextureDeserializer textureDeserializer,
|
||||
@@ -293,7 +293,7 @@ namespace UniVRM10
|
||||
vrm10Data,
|
||||
textureDeserializer: textureDeserializer,
|
||||
materialGenerator: materialGenerator,
|
||||
controlRigInitialRotations: controlRigGenerationOption.ToInitialRotations()))
|
||||
useControlRig: useControlRig))
|
||||
{
|
||||
// 1. Load meta information if callback was available.
|
||||
if (vrmMetaInformationCallback != null)
|
||||
|
||||
@@ -18,7 +18,7 @@ namespace UniVRM10
|
||||
private readonly Vrm10Data m_vrm;
|
||||
/// VrmLib.Model の オブジェクトと UnityEngine.Object のマッピングを記録する
|
||||
private readonly ModelMap m_map = new ModelMap();
|
||||
private readonly IReadOnlyDictionary<HumanBodyBones, Quaternion> m_controlRigInitialRotations;
|
||||
private readonly bool m_useControlRig;
|
||||
|
||||
private VrmLib.Model m_model;
|
||||
private IReadOnlyDictionary<SubAssetKey, UnityEngine.Object> m_externalMap;
|
||||
@@ -31,7 +31,7 @@ namespace UniVRM10
|
||||
IReadOnlyDictionary<SubAssetKey, UnityEngine.Object> externalObjectMap = null,
|
||||
ITextureDeserializer textureDeserializer = null,
|
||||
IMaterialDescriptorGenerator materialGenerator = null,
|
||||
IReadOnlyDictionary<HumanBodyBones, Quaternion> controlRigInitialRotations = null
|
||||
bool useControlRig = false
|
||||
)
|
||||
: base(vrm.Data, externalObjectMap, textureDeserializer)
|
||||
{
|
||||
@@ -40,7 +40,7 @@ namespace UniVRM10
|
||||
throw new ArgumentNullException("vrm");
|
||||
}
|
||||
m_vrm = vrm;
|
||||
m_controlRigInitialRotations = controlRigInitialRotations;
|
||||
m_useControlRig = useControlRig;
|
||||
|
||||
TextureDescriptorGenerator = new Vrm10TextureDescriptorGenerator(Data);
|
||||
MaterialDescriptorGenerator = materialGenerator ?? new BuiltInVrm10MaterialDescriptorGenerator();
|
||||
@@ -247,7 +247,7 @@ namespace UniVRM10
|
||||
|
||||
// VrmController
|
||||
var controller = Root.AddComponent<Vrm10Instance>();
|
||||
controller.InitializeAtRuntime(m_controlRigInitialRotations);
|
||||
controller.InitializeAtRuntime(m_useControlRig);
|
||||
controller.enabled = false;
|
||||
|
||||
// vrm
|
||||
|
||||
@@ -32,7 +32,7 @@ namespace UniVRM10.Test
|
||||
controller.Vrm.Expression.Aa.MaterialColorBindings = src.ToArray();
|
||||
|
||||
// ok if no exception
|
||||
var r = new Vrm10Runtime(controller, null);
|
||||
var r = new Vrm10Runtime(controller, useControlRig: false);
|
||||
}
|
||||
|
||||
[Test]
|
||||
@@ -56,7 +56,7 @@ namespace UniVRM10.Test
|
||||
controller.Vrm.Expression.Aa.MaterialUVBindings = src.ToArray();
|
||||
|
||||
// ok if no exception
|
||||
var r = new Vrm10Runtime(controller, null);
|
||||
var r = new Vrm10Runtime(controller, useControlRig: false);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -199,7 +199,7 @@ namespace UniVRM10
|
||||
{
|
||||
try
|
||||
{
|
||||
Vrm10.LoadPathAsync(gltf.FullName, true, ControlRigGenerationOption.None).Wait();
|
||||
Vrm10.LoadPathAsync(gltf.FullName, true, useControlRig: false).Wait();
|
||||
}
|
||||
catch (UnNormalizedException)
|
||||
{
|
||||
|
||||
Reference in New Issue
Block a user