diff --git a/Assets/VRM10/Runtime/Components/VRM10Object/VRM10ObjectFirstPerson.cs b/Assets/VRM10/Runtime/Components/VRM10Object/VRM10ObjectFirstPerson.cs index cae4eb1e0..0dce267e7 100644 --- a/Assets/VRM10/Runtime/Components/VRM10Object/VRM10ObjectFirstPerson.cs +++ b/Assets/VRM10/Runtime/Components/VRM10Object/VRM10ObjectFirstPerson.cs @@ -61,7 +61,7 @@ namespace UniVRM10 bool m_done; async Task SetupSelfRendererAsync(GameObject go, UniGLTF.RuntimeGltfInstance runtime, - Transform FirstPersonBone, RendererFirstPersonFlags x, + Transform firstPersonBone, RendererFirstPersonFlags x, (int FirstPersonOnly, int ThirdPersonOnly) layer, IAwaitCaller awaitCaller = null) { switch (x.FirstPersonFlag) @@ -70,7 +70,7 @@ namespace UniVRM10 { if (x.GetRenderer(go.transform) is SkinnedMeshRenderer smr) { - var eraseBones = GetBonesThatHasAncestor(smr, FirstPersonBone); + var eraseBones = GetBonesThatHasAncestor(smr, firstPersonBone); if (eraseBones.Any()) { // オリジナルのモデルを3人称用にする @@ -92,7 +92,7 @@ namespace UniVRM10 } else if (x.GetRenderer(go.transform) is MeshRenderer mr) { - if (mr.transform.Ancestors().Any(y => y == FirstPersonBone)) + if (mr.transform.Ancestors().Any(y => y == firstPersonBone)) { // 頭の子孫なので1人称では非表示に mr.gameObject.layer = layer.ThirdPersonOnly; @@ -154,7 +154,9 @@ namespace UniVRM10 m_done = true; var runtime = go.GetComponent(); - var firstPersonBone = go.GetComponent().GetBoneTransform(HumanBodyBones.Head); + var vrmInstance = go.GetComponent(); + // NOTE: This bone must be referenced by renderers instead of the control rig bone. + var firstPersonBone = vrmInstance.Humanoid.Head; var used = new HashSet(); foreach (var x in Renderers) diff --git a/Assets/VRM10/Runtime/Components/Vrm10Instance/Vrm10Instance.cs b/Assets/VRM10/Runtime/Components/Vrm10Instance/Vrm10Instance.cs index 16199a6ec..f2a0b1028 100644 --- a/Assets/VRM10/Runtime/Components/Vrm10Instance/Vrm10Instance.cs +++ b/Assets/VRM10/Runtime/Components/Vrm10Instance/Vrm10Instance.cs @@ -5,9 +5,9 @@ namespace UniVRM10 { /// /// VRM全体を制御するRoot - /// + /// /// Importer(scripted importer) -> Prefab(editor/asset) -> Instance(scene/MonoBehavior) -> Runtime(play時) - /// + /// /// * DefaultExecutionOrder(11000) means calculate springbone after FinalIK( VRIK ) /// [AddComponentMenu("VRM10/VRMInstance")] @@ -52,8 +52,12 @@ namespace UniVRM10 private UniHumanoid.Humanoid m_humanoid; private Vrm10Runtime m_runtime; - private bool m_generateControlRig = false; + private ControlRigGenerationOption m_controlRigGenerationOption = ControlRigGenerationOption.None; + /// + /// VRM ファイルに記録された Humanoid ボーンに対応します。 + /// これは、コントロールリグのボーンとは異なります。 + /// public UniHumanoid.Humanoid Humanoid { get @@ -75,15 +79,15 @@ namespace UniVRM10 { if (m_runtime == null) { - m_runtime = new Vrm10Runtime(this, m_generateControlRig); + m_runtime = new Vrm10Runtime(this, m_controlRigGenerationOption); } return m_runtime; } } - internal void InitializeAtRuntime(bool generateControlRig) + internal void InitializeAtRuntime(ControlRigGenerationOption controlRigGenerationOption) { - m_generateControlRig = generateControlRig; + m_controlRigGenerationOption = controlRigGenerationOption; } void Start() diff --git a/Assets/VRM10/Runtime/Components/Vrm10Runtime/ControlRig/ControlRigGenerationOption.cs b/Assets/VRM10/Runtime/Components/Vrm10Runtime/ControlRig/ControlRigGenerationOption.cs new file mode 100644 index 000000000..6ebb0e6e4 --- /dev/null +++ b/Assets/VRM10/Runtime/Components/Vrm10Runtime/ControlRig/ControlRigGenerationOption.cs @@ -0,0 +1,16 @@ +namespace UniVRM10 +{ + public enum ControlRigGenerationOption + { + /// + /// コントロールリグを生成しません。 + /// + None, + + /// + /// 推奨されるオプションです。 + /// コントロールリグのボーン Transform を生成し、Root の Animator はコントロールリグのボーンを制御するようになります。 + /// + Generate, + } +} \ No newline at end of file diff --git a/Assets/VRM10/Runtime/Components/Vrm10Runtime/ControlRig/ControlRigGenerationOption.cs.meta b/Assets/VRM10/Runtime/Components/Vrm10Runtime/ControlRig/ControlRigGenerationOption.cs.meta new file mode 100644 index 000000000..f6e9a90c1 --- /dev/null +++ b/Assets/VRM10/Runtime/Components/Vrm10Runtime/ControlRig/ControlRigGenerationOption.cs.meta @@ -0,0 +1,3 @@ +fileFormatVersion: 2 +guid: 9723f89e671a460188d12cbcceccaa4e +timeCreated: 1663314138 \ No newline at end of file diff --git a/Assets/VRM10/Runtime/Components/Vrm10Runtime/ControlRig/Vrm10ControlBone.cs b/Assets/VRM10/Runtime/Components/Vrm10Runtime/ControlRig/Vrm10ControlBone.cs index c43f742f1..36828b9fb 100644 --- a/Assets/VRM10/Runtime/Components/Vrm10Runtime/ControlRig/Vrm10ControlBone.cs +++ b/Assets/VRM10/Runtime/Components/Vrm10Runtime/ControlRig/Vrm10ControlBone.cs @@ -58,7 +58,8 @@ namespace UniVRM10 BoneType = boneType; ControlTarget = controlTarget; - ControlBone = new GameObject(boneType.ToString()).transform; + // NOTE: bone name must be unique in the vrm instance. + ControlBone = new GameObject($"{nameof(Vrm10ControlBone)}:{boneType.ToString()}").transform; ControlBone.position = controlTarget.position; InitialControlBoneLocalPosition = ControlBone.localPosition; InitialControlBoneLocalRotation = ControlBone.localRotation; diff --git a/Assets/VRM10/Runtime/Components/Vrm10Runtime/Vrm10Runtime.cs b/Assets/VRM10/Runtime/Components/Vrm10Runtime/Vrm10Runtime.cs index e4c59acec..314a539ab 100644 --- a/Assets/VRM10/Runtime/Components/Vrm10Runtime/Vrm10Runtime.cs +++ b/Assets/VRM10/Runtime/Components/Vrm10Runtime/Vrm10Runtime.cs @@ -38,7 +38,7 @@ namespace UniVRM10 public Vrm10RuntimeExpression Expression { get; } public Vrm10RuntimeLookAt LookAt { get; } - public Vrm10Runtime(Vrm10Instance target, bool generateControlRig) + public Vrm10Runtime(Vrm10Instance target, ControlRigGenerationOption controlRigGenerationOption) { m_target = target; @@ -47,9 +47,9 @@ namespace UniVRM10 throw new Exception(); } - if (generateControlRig) + if (controlRigGenerationOption != ControlRigGenerationOption.None) { - ControlRig = new Vrm10RuntimeControlRig(target.Humanoid, m_target.transform); + ControlRig = new Vrm10RuntimeControlRig(target.Humanoid, m_target.transform, controlRigGenerationOption); } Constraints = target.GetComponentsInChildren(); LookAt = new Vrm10RuntimeLookAt(target.Vrm.LookAt, target.Humanoid, m_head, target.LookAtTargetType, target.Gaze); diff --git a/Assets/VRM10/Runtime/Components/Vrm10Runtime/Vrm10RuntimeControlRig.cs b/Assets/VRM10/Runtime/Components/Vrm10Runtime/Vrm10RuntimeControlRig.cs index fb4acf273..cb4f6f05d 100644 --- a/Assets/VRM10/Runtime/Components/Vrm10Runtime/Vrm10RuntimeControlRig.cs +++ b/Assets/VRM10/Runtime/Components/Vrm10Runtime/Vrm10RuntimeControlRig.cs @@ -28,8 +28,10 @@ namespace UniVRM10 /// コンストラクタ。 /// humanoid は VRM T-Pose でなければならない。 /// - public Vrm10RuntimeControlRig(UniHumanoid.Humanoid humanoid, Transform vrmRoot) + public Vrm10RuntimeControlRig(UniHumanoid.Humanoid humanoid, Transform vrmRoot, ControlRigGenerationOption option) { + if (option == ControlRigGenerationOption.None) return; + _controlRigRoot = new GameObject("Runtime Control Rig").transform; _controlRigRoot.SetParent(vrmRoot); @@ -39,9 +41,10 @@ namespace UniVRM10 InitialHipsHeight = _hipBone.ControlTarget.position.y; var transformBonePairs = _bones.Select(kv => (kv.Value.ControlBone, kv.Key)); - _controlRigAvatar = HumanoidLoader.LoadHumanoidAvatar(_controlRigRoot, transformBonePairs); + _controlRigAvatar = HumanoidLoader.LoadHumanoidAvatar(vrmRoot, transformBonePairs); _controlRigAvatar.name = "Runtime Control Rig"; - ControlRigAnimator = _controlRigRoot.gameObject.AddComponent(); + + ControlRigAnimator = vrmRoot.GetComponent(); ControlRigAnimator.avatar = _controlRigAvatar; } diff --git a/Assets/VRM10/Runtime/IO/Vrm10.cs b/Assets/VRM10/Runtime/IO/Vrm10.cs index 55e51eecc..bf9c74ee4 100644 --- a/Assets/VRM10/Runtime/IO/Vrm10.cs +++ b/Assets/VRM10/Runtime/IO/Vrm10.cs @@ -27,7 +27,7 @@ namespace UniVRM10 /// /// vrm file path /// if true, this loader can load the vrm-0.x model as vrm-1.0 model with migration. - /// if true, generating the control rig provides bone manipulation like vrm-0.x + /// the flag of generating the control rig provides bone manipulation unified between models. /// if true, show meshes when loaded. /// this loader use specified await strategy. /// this loader use specified material generation strategy. @@ -37,7 +37,7 @@ namespace UniVRM10 public static async Task LoadPathAsync( string path, bool canLoadVrm0X = true, - bool generateControlRig = true, + ControlRigGenerationOption controlRigGenerationOption = ControlRigGenerationOption.Generate, bool showMeshes = true, IAwaitCaller awaitCaller = null, IMaterialDescriptorGenerator materialGenerator = null, @@ -55,7 +55,7 @@ namespace UniVRM10 path, System.IO.File.ReadAllBytes(path), canLoadVrm0X, - generateControlRig, + controlRigGenerationOption, showMeshes, awaitCaller, materialGenerator, @@ -71,7 +71,7 @@ namespace UniVRM10 /// /// vrm file data /// if true, this loader can load the vrm-0.x model as vrm-1.0 model with migration. - /// if true, generating the control rig provides bone manipulation like vrm-0.x + /// the flag of generating the control rig provides bone manipulation unified between models. /// if true, show meshes when loaded. /// this loader use specified await strategy. /// this loader use specified material generation strategy. @@ -81,7 +81,7 @@ namespace UniVRM10 public static async Task LoadBytesAsync( byte[] bytes, bool canLoadVrm0X = true, - bool generateControlRig = true, + ControlRigGenerationOption controlRigGenerationOption = ControlRigGenerationOption.Generate, bool showMeshes = true, IAwaitCaller awaitCaller = null, IMaterialDescriptorGenerator materialGenerator = null, @@ -99,7 +99,7 @@ namespace UniVRM10 string.Empty, bytes, canLoadVrm0X, - generateControlRig, + controlRigGenerationOption, showMeshes, awaitCaller, materialGenerator, @@ -111,7 +111,7 @@ namespace UniVRM10 string name, byte[] bytes, bool canLoadVrm0X, - bool generateControlRig, + ControlRigGenerationOption controlRigGenerationOption, bool showMeshes, IAwaitCaller awaitCaller, IMaterialDescriptorGenerator materialGenerator, @@ -129,7 +129,7 @@ namespace UniVRM10 // 1. Try loading as vrm-1.0 var instance = await TryLoadingAsVrm10Async( gltfData, - generateControlRig, + controlRigGenerationOption, showMeshes, awaitCaller, materialGenerator, @@ -154,7 +154,7 @@ namespace UniVRM10 // 3. Try migration from vrm-0.x into vrm-1.0 var migratedInstance = await TryMigratingFromVrm0XAsync( gltfData, - generateControlRig, + controlRigGenerationOption, showMeshes, awaitCaller, materialGenerator, @@ -177,7 +177,7 @@ namespace UniVRM10 private static async Task TryLoadingAsVrm10Async( GltfData gltfData, - bool generateControlRig, + ControlRigGenerationOption controlRigGenerationOption, bool showMeshes, IAwaitCaller awaitCaller, IMaterialDescriptorGenerator materialGenerator, @@ -202,7 +202,7 @@ namespace UniVRM10 return await LoadVrm10DataAsync( vrm10Data, null, - generateControlRig, + controlRigGenerationOption, showMeshes, awaitCaller, materialGenerator, @@ -212,7 +212,7 @@ namespace UniVRM10 private static async Task TryMigratingFromVrm0XAsync( GltfData gltfData, - bool generateControlRig, + ControlRigGenerationOption controlRigGenerationOption, bool showMeshes, IAwaitCaller awaitCaller, IMaterialDescriptorGenerator materialGenerator, @@ -239,7 +239,7 @@ namespace UniVRM10 var migratedVrm10Instance = await LoadVrm10DataAsync( migratedVrm10Data, migrationData, - generateControlRig, + controlRigGenerationOption, showMeshes, awaitCaller, materialGenerator, @@ -256,7 +256,7 @@ namespace UniVRM10 private static async Task LoadVrm10DataAsync( Vrm10Data vrm10Data, MigrationData migrationData, - bool generateControlRig, + ControlRigGenerationOption controlRigGenerationOption, bool showMeshes, IAwaitCaller awaitCaller, IMaterialDescriptorGenerator materialGenerator, @@ -274,7 +274,7 @@ namespace UniVRM10 throw new ArgumentNullException(nameof(vrm10Data)); } - using (var loader = new Vrm10Importer(vrm10Data, generateControlRig: generateControlRig, materialGenerator: materialGenerator)) + using (var loader = new Vrm10Importer(vrm10Data, controlRigGenerationOption: controlRigGenerationOption, materialGenerator: materialGenerator)) { // 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 6618c419d..31b6ae002 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 bool m_generateControlRig; + private readonly ControlRigGenerationOption m_controlRigGenerationOption; private VrmLib.Model m_model; private IReadOnlyDictionary m_externalMap; @@ -31,7 +31,7 @@ namespace UniVRM10 IReadOnlyDictionary externalObjectMap = null, ITextureDeserializer textureDeserializer = null, IMaterialDescriptorGenerator materialGenerator = null, - bool generateControlRig = false) + ControlRigGenerationOption controlRigGenerationOption = ControlRigGenerationOption.None) : base(vrm.Data, externalObjectMap, textureDeserializer) { if (vrm == null) @@ -39,7 +39,7 @@ namespace UniVRM10 throw new ArgumentNullException("vrm"); } m_vrm = vrm; - m_generateControlRig = generateControlRig; + m_controlRigGenerationOption = controlRigGenerationOption; TextureDescriptorGenerator = new Vrm10TextureDescriptorGenerator(Data); MaterialDescriptorGenerator = materialGenerator ?? new Vrm10MaterialDescriptorGenerator(); @@ -246,7 +246,7 @@ namespace UniVRM10 // VrmController var controller = Root.AddComponent(); - controller.InitializeAtRuntime(m_generateControlRig); + controller.InitializeAtRuntime(m_controlRigGenerationOption); controller.enabled = false; // vrm diff --git a/Assets/VRM10/Runtime/Scenes/Sample.cs b/Assets/VRM10/Runtime/Scenes/Sample.cs index 6fc1b47b4..f3468a243 100644 --- a/Assets/VRM10/Runtime/Scenes/Sample.cs +++ b/Assets/VRM10/Runtime/Scenes/Sample.cs @@ -22,12 +22,12 @@ namespace UniVRM10.Sample async void Run() { var src = new FileInfo(m_vrmPath); - var instance = await Vrm10.LoadPathAsync(m_vrmPath, true, true); + var instance = await Vrm10.LoadPathAsync(m_vrmPath, true); var exportedBytes = Vrm10Exporter.Export(instance.gameObject); // Import 1.0 - var vrm10 = await Vrm10.LoadBytesAsync(exportedBytes, false, true); + var vrm10 = await Vrm10.LoadBytesAsync(exportedBytes, false); var pos = vrm10.transform.position; pos.x += 1.5f; vrm10.transform.position = pos; diff --git a/Assets/VRM10/Tests/ExpressionTests.cs b/Assets/VRM10/Tests/ExpressionTests.cs index dfd370363..8b8be849b 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, false); + var r = new Vrm10Runtime(controller, ControlRigGenerationOption.None); } [Test] @@ -56,7 +56,7 @@ namespace UniVRM10.Test controller.Vrm.Expression.Aa.MaterialUVBindings = src.ToArray(); // ok if no exception - var r = new Vrm10Runtime(controller, false); + var r = new Vrm10Runtime(controller, ControlRigGenerationOption.None); } } } diff --git a/Assets/VRM10/Tests/MigrationTests.cs b/Assets/VRM10/Tests/MigrationTests.cs index 7e26b7099..1a6f773fd 100644 --- a/Assets/VRM10/Tests/MigrationTests.cs +++ b/Assets/VRM10/Tests/MigrationTests.cs @@ -198,7 +198,7 @@ namespace UniVRM10 { try { - Vrm10.LoadPathAsync(gltf.FullName, true, false).Wait(); + Vrm10.LoadPathAsync(gltf.FullName, true, ControlRigGenerationOption.None).Wait(); } catch (UnNormalizedException) { diff --git a/Assets/VRM10/Tests/TestAsset.cs b/Assets/VRM10/Tests/TestAsset.cs index 2ee9fe5bf..6077c2c44 100644 --- a/Assets/VRM10/Tests/TestAsset.cs +++ b/Assets/VRM10/Tests/TestAsset.cs @@ -16,7 +16,7 @@ namespace UniVRM10 public static Vrm10Instance LoadAlicia() { - var task = Vrm10.LoadPathAsync(AliciaPath, true, true); + var task = Vrm10.LoadPathAsync(AliciaPath, canLoadVrm0X: true); task.Wait(); var instance = task.Result;