From a82dfd4611ba8efb9b844c102c0945609049750e Mon Sep 17 00:00:00 2001 From: ousttrue Date: Mon, 20 Feb 2023 13:53:18 +0900 Subject: [PATCH] =?UTF-8?q?Vrm10RuntimeControlRig=20=E3=81=AF=E3=80=81?= =?UTF-8?q?=E6=AD=A3=E8=A6=8F=E5=8C=96=E3=81=95=E3=82=8C=E3=81=9FTPose?= =?UTF-8?q?=E3=82=92=E5=8F=97=E3=81=91=E5=8F=96=E3=82=8B=E8=B2=AC=E5=8B=99?= =?UTF-8?q?=E3=81=AB=E7=89=B9=E5=8C=96=E3=81=97=E3=81=A6=E5=8D=98=E7=B4=94?= =?UTF-8?q?=E5=8C=96=E3=81=99=E3=82=8B=E3=80=82?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 初期回転を持つポーズの受付は、Vrm10BoneInitialRotation を使う別クラスに委譲する。 (次で作ります) --- .../Components/Vrm10Instance/Vrm10Instance.cs | 12 ++--- .../Components/Vrm10Runtime/Vrm10Runtime.cs | 6 +-- .../Vrm10Runtime/Vrm10RuntimeControlRig.cs | 15 ++---- .../ControlRig/Vrm10BoneInitialRotation.cs | 39 ++++++++++++++ .../Vrm10BoneInitialRotation.cs.meta | 11 ++++ .../Runtime/ControlRig/Vrm10ControlBone.cs | 53 ++++--------------- Assets/VRM10/Runtime/IO/Vrm10.cs | 26 ++++----- Assets/VRM10/Runtime/IO/Vrm10Importer.cs | 8 +-- Assets/VRM10/Tests/ExpressionTests.cs | 4 +- Assets/VRM10/Tests/MigrationTests.cs | 2 +- 10 files changed, 92 insertions(+), 84 deletions(-) create mode 100644 Assets/VRM10/Runtime/ControlRig/Vrm10BoneInitialRotation.cs create mode 100644 Assets/VRM10/Runtime/ControlRig/Vrm10BoneInitialRotation.cs.meta diff --git a/Assets/VRM10/Runtime/Components/Vrm10Instance/Vrm10Instance.cs b/Assets/VRM10/Runtime/Components/Vrm10Instance/Vrm10Instance.cs index b7f42c40a..a48ef5733 100644 --- a/Assets/VRM10/Runtime/Components/Vrm10Instance/Vrm10Instance.cs +++ b/Assets/VRM10/Runtime/Components/Vrm10Instance/Vrm10Instance.cs @@ -67,12 +67,8 @@ namespace UniVRM10 /// /// ControlRig の生成オプション - /// - /// null: ControlRigGenerationOption.None - /// empty: ControlRigGenerationOption.Generate = Vrm0XCompatibleRig - /// other: ControlRigGenerationOption.Vrm0XCompatibleWithXR_EXT_hand_tracking など /// - private IReadOnlyDictionary m_controlRigInitialRotations; + private bool m_useControlRig; /// /// 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 controlRigInitialRotations) + internal void InitializeAtRuntime(bool useControlRig) { - m_controlRigInitialRotations = controlRigInitialRotations; + m_useControlRig = useControlRig; } void Start() diff --git a/Assets/VRM10/Runtime/Components/Vrm10Runtime/Vrm10Runtime.cs b/Assets/VRM10/Runtime/Components/Vrm10Runtime/Vrm10Runtime.cs index 6850b680b..29182017f 100644 --- a/Assets/VRM10/Runtime/Components/Vrm10Runtime/Vrm10Runtime.cs +++ b/Assets/VRM10/Runtime/Components/Vrm10Runtime/Vrm10Runtime.cs @@ -49,7 +49,7 @@ namespace UniVRM10 } } - public Vrm10Runtime(Vrm10Instance target, IReadOnlyDictionary 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(); LookAt = new Vrm10RuntimeLookAt(target.Vrm.LookAt, target.Humanoid, ControlRig); diff --git a/Assets/VRM10/Runtime/Components/Vrm10Runtime/Vrm10RuntimeControlRig.cs b/Assets/VRM10/Runtime/Components/Vrm10Runtime/Vrm10RuntimeControlRig.cs index 681cf681d..c6c13c6df 100644 --- a/Assets/VRM10/Runtime/Components/Vrm10Runtime/Vrm10RuntimeControlRig.cs +++ b/Assets/VRM10/Runtime/Components/Vrm10Runtime/Vrm10RuntimeControlRig.cs @@ -29,18 +29,12 @@ namespace UniVRM10 /// /// T-Pose である必要があります /// - /// ControlRigの各ボーンの初期回転を表します - public Vrm10RuntimeControlRig(UniHumanoid.Humanoid humanoid, Transform vrmRoot, IReadOnlyDictionary 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; } } } diff --git a/Assets/VRM10/Runtime/ControlRig/Vrm10BoneInitialRotation.cs b/Assets/VRM10/Runtime/ControlRig/Vrm10BoneInitialRotation.cs new file mode 100644 index 000000000..ffdb5b7a0 --- /dev/null +++ b/Assets/VRM10/Runtime/ControlRig/Vrm10BoneInitialRotation.cs @@ -0,0 +1,39 @@ +using UnityEngine; + +namespace UniVRM10 +{ + /// + /// Represents the rotation at the initial pose (TPose) + /// + 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; + } + + /// + /// 初期姿勢からの相対的な回転。 + /// + /// VRM-0.X 互換リグでは localRotation と同じ値を示す。 + /// + Quaternion NormalizedLocalRotation + { + get + { + return InitialGlobalRotation * Quaternion.Inverse(InitialLocalRotation) * Transform.localRotation * Quaternion.Inverse(InitialGlobalRotation); + } + } + } +} diff --git a/Assets/VRM10/Runtime/ControlRig/Vrm10BoneInitialRotation.cs.meta b/Assets/VRM10/Runtime/ControlRig/Vrm10BoneInitialRotation.cs.meta new file mode 100644 index 000000000..dd0a4eec9 --- /dev/null +++ b/Assets/VRM10/Runtime/ControlRig/Vrm10BoneInitialRotation.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: db1187bf0b13152439c8a145d9631916 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/VRM10/Runtime/ControlRig/Vrm10ControlBone.cs b/Assets/VRM10/Runtime/ControlRig/Vrm10ControlBone.cs index 3a697bf35..a10fcaba1 100644 --- a/Assets/VRM10/Runtime/ControlRig/Vrm10ControlBone.cs +++ b/Assets/VRM10/Runtime/ControlRig/Vrm10ControlBone.cs @@ -31,22 +31,11 @@ namespace UniVRM10 /// public Transform ControlBone { get; } - /// - /// コントロールボーンの初期ローカル位置。 - /// - public Vector3 InitialControlBoneLocalPosition { get; } - - /// - /// コントロールボーンの初期ローカル回転。 - /// - public Quaternion InitialControlBoneLocalRotation { get; } - - private readonly Quaternion _initialControlBoneGlobalRotation; private readonly Quaternion _initialTargetLocalRotation; private readonly Quaternion _initialTargetGlobalRotation; private readonly List _children = new List(); - private Vrm10ControlBone(Transform controlTarget, HumanBodyBones boneType, Vrm10ControlBone parent, IReadOnlyDictionary 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; } - /// - /// 初期姿勢からの相対的な回転。 - /// - /// VRM-0.X 互換リグでは localRotation と同じ値を示す。 - /// - Quaternion NormalizedLocalRotation - { - get - { - return _initialControlBoneGlobalRotation * Quaternion.Inverse(InitialControlBoneLocalRotation) * ControlBone.localRotation * Quaternion.Inverse(_initialControlBoneGlobalRotation); - } - } - /// /// 親から再帰的にNormalized の ローカル回転を初期回転を加味して Target に適用する。 /// 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 controlRigInitialRotations, out Dictionary boneMap) + public static Vrm10ControlBone Build(UniHumanoid.Humanoid humanoid, out Dictionary boneMap) { - var hips = new Vrm10ControlBone(humanoid.Hips, HumanBodyBones.Hips, null, controlRigInitialRotations); + var hips = new Vrm10ControlBone(humanoid.Hips, HumanBodyBones.Hips, null); boneMap = new Dictionary(); 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 controlRigInitialRotations, Dictionary boneMap) + private static void BuildRecursively(UniHumanoid.Humanoid humanoid, Transform current, Vrm10ControlBone parent, Dictionary 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); } } } diff --git a/Assets/VRM10/Runtime/IO/Vrm10.cs b/Assets/VRM10/Runtime/IO/Vrm10.cs index b1b433fe8..a57767cce 100644 --- a/Assets/VRM10/Runtime/IO/Vrm10.cs +++ b/Assets/VRM10/Runtime/IO/Vrm10.cs @@ -39,7 +39,7 @@ namespace UniVRM10 public static async Task 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 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 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 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 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) diff --git a/Assets/VRM10/Runtime/IO/Vrm10Importer.cs b/Assets/VRM10/Runtime/IO/Vrm10Importer.cs index 5f86c25b2..ef90adc1d 100644 --- a/Assets/VRM10/Runtime/IO/Vrm10Importer.cs +++ b/Assets/VRM10/Runtime/IO/Vrm10Importer.cs @@ -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 m_controlRigInitialRotations; + private readonly bool m_useControlRig; private VrmLib.Model m_model; private IReadOnlyDictionary m_externalMap; @@ -31,7 +31,7 @@ namespace UniVRM10 IReadOnlyDictionary externalObjectMap = null, ITextureDeserializer textureDeserializer = null, IMaterialDescriptorGenerator materialGenerator = null, - IReadOnlyDictionary 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(); - controller.InitializeAtRuntime(m_controlRigInitialRotations); + controller.InitializeAtRuntime(m_useControlRig); controller.enabled = false; // vrm diff --git a/Assets/VRM10/Tests/ExpressionTests.cs b/Assets/VRM10/Tests/ExpressionTests.cs index 99e832566..f097d503d 100644 --- a/Assets/VRM10/Tests/ExpressionTests.cs +++ b/Assets/VRM10/Tests/ExpressionTests.cs @@ -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); } } } diff --git a/Assets/VRM10/Tests/MigrationTests.cs b/Assets/VRM10/Tests/MigrationTests.cs index 75695ac67..b0688f60c 100644 --- a/Assets/VRM10/Tests/MigrationTests.cs +++ b/Assets/VRM10/Tests/MigrationTests.cs @@ -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) {