From 4fefbc38c3d73a6f9ee9c4524412618f8d4787d3 Mon Sep 17 00:00:00 2001 From: Masataka SUMI Date: Fri, 4 Feb 2022 18:54:58 +0900 Subject: [PATCH] Change High-level VRM-1.0 loading API. --- Assets/VRM10/Runtime/IO/Vrm10.cs | 223 +++++++++++++----- Assets/VRM10/Runtime/Scenes/Sample.cs | 2 +- Assets/VRM10/Runtime/Scenes/SampleScene.unity | 5 +- .../VRM10RuntimeLoader.cs | 9 +- .../VRM10Viewer/VRM10ViewerUI.cs | 21 +- 5 files changed, 183 insertions(+), 77 deletions(-) diff --git a/Assets/VRM10/Runtime/IO/Vrm10.cs b/Assets/VRM10/Runtime/IO/Vrm10.cs index 01dba6262..270492451 100644 --- a/Assets/VRM10/Runtime/IO/Vrm10.cs +++ b/Assets/VRM10/Runtime/IO/Vrm10.cs @@ -1,4 +1,5 @@ -using System.Threading; +using System; +using System.Threading; using System.Threading.Tasks; using UniGLTF; using UnityEngine; @@ -11,87 +12,189 @@ namespace UniVRM10 /// public static class Vrm10 { - public delegate void MetaCallback(Texture2D thumbnail, UniGLTF.Extensions.VRMC_vrm.Meta meta1, Migration.Vrm0Meta meta0); - public static async Task LoadPathAsync(string path, - bool doMigrate, - bool doNormalize, + /// + /// You can receive the thumbnail texture and the meta information. + /// `vrm10Meta` will be available if the model was vrm-1.0. + /// `vrm0Meta` will be available if the model was vrm-0.x. + /// + public delegate void VrmMetaInformationCallback(Texture2D thumbnail, UniGLTF.Extensions.VRMC_vrm.Meta vrm10Meta, Migration.Vrm0Meta vrm0Meta); + + /// + /// Load the VRM file from the path. + /// + /// vrm file path + /// if true, this loader can load the vrm-0.x model as vrm-1.0 model with migration. + /// if true, vrm-1.0 models are forced to load in T-pose. + /// if true, show meshes when loaded. + /// this loader use specified await strategy. + /// this loader use specified material generation strategy. + /// return callback that notify meta information before loading. + /// CancellationToken + /// vrm-1.0 instance + public static async Task LoadPathAsync( + string path, + bool canLoadVrm0X = true, + bool forceTPose = true, + bool showMeshes = true, IAwaitCaller awaitCaller = null, IMaterialDescriptorGenerator materialGenerator = null, - MetaCallback metaCallback = null, - CancellationToken ct = default - ) + VrmMetaInformationCallback vrmMetaInformationCallback = null, + CancellationToken ct = default) { - return await LoadBytesAsync(path, System.IO.File.ReadAllBytes(path), doMigrate, doNormalize, awaitCaller, materialGenerator, metaCallback, ct); + return await LoadAsync( + path, + System.IO.File.ReadAllBytes(path), + canLoadVrm0X, + forceTPose, + showMeshes, + awaitCaller, + materialGenerator, + vrmMetaInformationCallback, + ct); } - public static async Task LoadBytesAsync(string path, byte[] bytes, - bool doMigrate, - bool doNormalize, + /// + /// Load the VRM file from the binary. + /// + /// vrm file data + /// if true, this loader can load the vrm-0.x model as vrm-1.0 model with migration. + /// if true, vrm-1.0 models are forced to load in T-pose. + /// if true, show meshes when loaded. + /// this loader use specified await strategy. + /// this loader use specified material generation strategy. + /// return callback that notify meta information before loading. + /// CancellationToken + /// vrm-1.0 instance + public static async Task LoadBytesAsync( + byte[] bytes, + bool canLoadVrm0X = true, + bool forceTPose = true, + bool showMeshes = true, IAwaitCaller awaitCaller = null, IMaterialDescriptorGenerator materialGenerator = null, - MetaCallback metaCallback = null, - CancellationToken ct = default - ) + VrmMetaInformationCallback vrmMetaInformationCallback = null, + CancellationToken ct = default) { - using (var data = new GlbLowLevelParser(path, bytes).Parse()) - { - // 1. Try parsing as vrm-1.0 - var vrm1Data = Vrm10Data.Parse(data); - if (vrm1Data != null) - { - // successfully parsed vrm-1.0 - using (var loader = new Vrm10Importer(vrm1Data, materialGenerator: materialGenerator, doNormalize: doNormalize)) - { - if (metaCallback != null) - { - var thumbnail = await loader.LoadVrmThumbnailAsync(); - metaCallback(thumbnail, vrm1Data.VrmExtension.Meta, null); - } - var instance = await loader.LoadAsync(awaitCaller); - if (ct.IsCancellationRequested && instance != null) - { - instance.Dispose(); - } - return instance; - } - } + return await LoadAsync( + string.Empty, + bytes, + canLoadVrm0X, + forceTPose, + showMeshes, + awaitCaller, + materialGenerator, + vrmMetaInformationCallback, + ct); + } - if (!doMigrate) + private static async Task LoadAsync( + string name, + byte[] bytes, + bool canLoadVrm0X, + bool forceTPose, + bool showMeshes, + IAwaitCaller awaitCaller, + IMaterialDescriptorGenerator materialGenerator, + VrmMetaInformationCallback vrmMetaInformationCallback, + CancellationToken ct) + { + using (var data = new GlbLowLevelParser(name, bytes).Parse()) + { + // 1. Try loading as vrm-1.0 + var vrm10Data = Vrm10Data.Parse(data); + var vrm10Instance = await LoadVrm10DataAsync( + vrm10Data, + null, + forceTPose, + showMeshes, + awaitCaller, + materialGenerator, + vrmMetaInformationCallback, + ct); + if (vrm10Instance != null) return vrm10Instance; + + if (!canLoadVrm0X) { return default; } // 2. Try migration from vrm-0.x into vrm-1.0 - MigrationData migration; - using (var migrated = Vrm10Data.Migrate(data, out vrm1Data, out migration)) + MigrationData migrationData; + using (var migrated = Vrm10Data.Migrate(data, out vrm10Data, out migrationData)) { - if (vrm1Data != null) - { - // successfully migrated from vrm-0.x - using (var loader = new Vrm10Importer(vrm1Data, materialGenerator: materialGenerator, doNormalize: doNormalize)) - { - if (metaCallback != null) - { - var thumbnail = await loader.LoadVrmThumbnailAsync(); - metaCallback(thumbnail, vrm1Data.VrmExtension.Meta, null); - } - var instance = await loader.LoadAsync(awaitCaller); - if (ct.IsCancellationRequested && instance != null) - { - instance.Dispose(); - } - return instance; - } - } + var instance = await LoadVrm10DataAsync( + vrm10Data, + migrationData, + forceTPose, + showMeshes, + awaitCaller, + materialGenerator, + vrmMetaInformationCallback, + ct); + if (instance != null) return instance; } // 3. failed - if (migration != null) + if (migrationData != null) { - Debug.LogWarning(migration.Message); + Debug.LogWarning(migrationData.Message); } return default; } } + + private static async Task LoadVrm10DataAsync( + Vrm10Data vrm10Data, + MigrationData migrationData, + bool forceTPose, + bool showMeshes, + IAwaitCaller awaitCaller, + IMaterialDescriptorGenerator materialGenerator, + VrmMetaInformationCallback vrmMetaInformationCallback, + CancellationToken ct) + { + if (vrm10Data == null) + { + return default; + } + + using (var loader = new Vrm10Importer(vrm10Data, materialGenerator: materialGenerator, doNormalize: forceTPose)) + { + // 1. Load meta information if callback was available. + if (vrmMetaInformationCallback != null) + { + var thumbnail = await loader.LoadVrmThumbnailAsync(); + if (migrationData != null) + { + vrmMetaInformationCallback(thumbnail, default, migrationData.OriginalMetaBeforeMigration); + } + else + { + vrmMetaInformationCallback(thumbnail, vrm10Data.VrmExtension.Meta, default); + } + } + + // 2. Load + var gltfInstance = await loader.LoadAsync(awaitCaller); + if (ct.IsCancellationRequested) + { + gltfInstance.Dispose(); + return default; + } + + var vrm10Instance = gltfInstance.GetComponent(); + if (vrm10Instance == null) + { + gltfInstance.Dispose(); + return default; + } + + if (showMeshes) + { + gltfInstance.ShowMeshes(); + } + return vrm10Instance; + } + } } } diff --git a/Assets/VRM10/Runtime/Scenes/Sample.cs b/Assets/VRM10/Runtime/Scenes/Sample.cs index 415f2ce5f..6fc1b47b4 100644 --- a/Assets/VRM10/Runtime/Scenes/Sample.cs +++ b/Assets/VRM10/Runtime/Scenes/Sample.cs @@ -27,7 +27,7 @@ namespace UniVRM10.Sample var exportedBytes = Vrm10Exporter.Export(instance.gameObject); // Import 1.0 - var vrm10 = await Vrm10.LoadBytesAsync("tmp.vrm", exportedBytes, false, true); + var vrm10 = await Vrm10.LoadBytesAsync(exportedBytes, false, true); var pos = vrm10.transform.position; pos.x += 1.5f; vrm10.transform.position = pos; diff --git a/Assets/VRM10/Runtime/Scenes/SampleScene.unity b/Assets/VRM10/Runtime/Scenes/SampleScene.unity index ecb42cea9..af58e6cbd 100644 --- a/Assets/VRM10/Runtime/Scenes/SampleScene.unity +++ b/Assets/VRM10/Runtime/Scenes/SampleScene.unity @@ -38,7 +38,7 @@ RenderSettings: m_ReflectionIntensity: 1 m_CustomReflection: {fileID: 0} m_Sun: {fileID: 705507994} - m_IndirectSpecularColor: {r: 0.44657898, g: 0.4964133, b: 0.5748178, a: 1} + m_IndirectSpecularColor: {r: 0.18028378, g: 0.22571412, b: 0.30692285, a: 1} m_UseRadianceAmbientProbe: 0 --- !u!157 &3 LightmapSettings: @@ -325,8 +325,7 @@ MonoBehaviour: m_Script: {fileID: 11500000, guid: d2dd74f31dd71684da8aa80eaa66390e, type: 3} m_Name: m_EditorClassIdentifier: - m_vrmPath: ../UniVRM_1_0/Tests/Models/Alicia_vrm-0.51/AliciaSolid_vrm-0.51.vrm - m_rightHandToLeftHand: 1 + m_vrmPath: Tests/Models/Alicia_vrm-0.51/AliciaSolid_vrm-0.51.vrm --- !u!4 &1706915413 Transform: m_ObjectHideFlags: 0 diff --git a/Assets/VRM10_Samples/VRM10FirstPersonSample/VRM10RuntimeLoader.cs b/Assets/VRM10_Samples/VRM10FirstPersonSample/VRM10RuntimeLoader.cs index 0f507f427..b2c30e826 100644 --- a/Assets/VRM10_Samples/VRM10FirstPersonSample/VRM10RuntimeLoader.cs +++ b/Assets/VRM10_Samples/VRM10FirstPersonSample/VRM10RuntimeLoader.cs @@ -82,17 +82,14 @@ namespace UniVRM10.FirstPersonSample } m_target = humanPoseTransfer; SetupTarget(m_target); - - instance.ShowMeshes(); } - async Task LoadAsync(string path) + async Task LoadAsync(string path) { - var instance = await Vrm10.LoadPathAsync(path, true, true); + var instance = await Vrm10.LoadPathAsync(path); // VR用 FirstPerson 設定 - var controller = instance.GetComponent(); - await controller.Vrm.FirstPerson.SetupAsync(controller.gameObject); + await instance.Vrm.FirstPerson.SetupAsync(instance.gameObject); return instance; } diff --git a/Assets/VRM10_Samples/VRM10Viewer/VRM10ViewerUI.cs b/Assets/VRM10_Samples/VRM10Viewer/VRM10ViewerUI.cs index cb0a1856d..2bb86e1ba 100644 --- a/Assets/VRM10_Samples/VRM10Viewer/VRM10ViewerUI.cs +++ b/Assets/VRM10_Samples/VRM10Viewer/VRM10ViewerUI.cs @@ -415,16 +415,23 @@ namespace UniVRM10.VRM10Viewer } Debug.LogFormat("{0}", path); - var instance = await Vrm10.LoadPathAsync(path, true, m_useNormalization.isOn, - awaitCaller: new RuntimeOnlyAwaitCaller(), - materialGenerator: GetVrmMaterialDescriptorGenerator(m_useUrpMaterial.isOn), - metaCallback: m_texts.UpdateMeta); - if (instance == null) + var vrm10Instance = await Vrm10.LoadPathAsync(path, + canLoadVrm0X: true, + forceTPose: m_useNormalization.isOn, + showMeshes: false, + awaitCaller: new RuntimeOnlyAwaitCaller(), + materialGenerator: GetVrmMaterialDescriptorGenerator(m_useUrpMaterial.isOn), + vrmMetaInformationCallback: m_texts.UpdateMeta); + if (vrm10Instance != null) + { + SetModel(vrm10Instance.GetComponent()); + } + else { // fallback to gltf - instance = await GltfUtility.LoadAsync(path, awaitCaller: new RuntimeOnlyAwaitCaller()); + var instance = await GltfUtility.LoadAsync(path, awaitCaller: new RuntimeOnlyAwaitCaller()); + SetModel(instance); } - SetModel(instance); } void SetModel(RuntimeGltfInstance instance)