Vrm10Data.TryParseOrMigrate の API 変更

* 関連する unittest で Dispose
This commit is contained in:
ousttrue 2022-01-26 18:53:09 +09:00
parent 00a046a06c
commit 511aa89dcc
13 changed files with 234 additions and 243 deletions

View File

@ -24,6 +24,7 @@ namespace UniVRM10
RemapEditorVrm m_vrmEditor;
Vrm10Data m_result;
MigrationData m_migration;
IEnumerable<SubAssetKey> EnumerateExpressinKeys(UniGLTF.Extensions.VRMC_vrm.Expressions expressions)
{
@ -65,20 +66,23 @@ namespace UniVRM10
var importer = target as VrmScriptedImporter;
m_importer = importer;
if (!Vrm10Data.TryParseOrMigrate(m_importer.assetPath, importer.MigrateToVrm1, out m_result))
using (Vrm10Data.ParseOrMigrate(m_importer.assetPath, importer.MigrateToVrm1, out m_result, out m_migration))
{
// error
return;
if (m_result == null)
{
// error
return;
}
m_model = ModelReader.Read(m_result.Data);
var tmp = m_importer.GetExternalObjectMap();
var generator = new Vrm10MaterialDescriptorGenerator();
var materialKeys = m_result.Data.GLTF.materials.Select((x, i) => generator.Get(m_result.Data, i).SubAssetKey);
var textureKeys = new Vrm10TextureDescriptorGenerator(m_result.Data).Get().GetEnumerable().Select(x => x.SubAssetKey);
m_materialEditor = new RemapEditorMaterial(materialKeys.Concat(textureKeys), GetEditorMap, SetEditorMap);
m_vrmEditor = new RemapEditorVrm(new[] { VRM10Object.SubAssetKey }.Concat(EnumerateExpressinKeys(m_result.VrmExtension.Expressions)), GetEditorMap, SetEditorMap);
}
m_model = ModelReader.Read(m_result.Data);
var tmp = m_importer.GetExternalObjectMap();
var generator = new Vrm10MaterialDescriptorGenerator();
var materialKeys = m_result.Data.GLTF.materials.Select((x, i) => generator.Get(m_result.Data, i).SubAssetKey);
var textureKeys = new Vrm10TextureDescriptorGenerator(m_result.Data).Get().GetEnumerable().Select(x => x.SubAssetKey);
m_materialEditor = new RemapEditorMaterial(materialKeys.Concat(textureKeys), GetEditorMap, SetEditorMap);
m_vrmEditor = new RemapEditorVrm(new[] { VRM10Object.SubAssetKey }.Concat(EnumerateExpressinKeys(m_result.VrmExtension.Expressions)), GetEditorMap, SetEditorMap);
}
enum Tabs
@ -98,51 +102,44 @@ namespace UniVRM10
{
case Tabs.Model:
{
switch (m_result.FileType)
if (m_migration == null)
{
case Vrm10FileType.Vrm1:
EditorGUILayout.HelpBox(m_migration.Message, MessageType.Info);
EditorGUILayout.HelpBox(m_result.Message, MessageType.Info);
{
serializedObject.Update();
// normalize
EditorGUILayout.Space();
EditorGUILayout.HelpBox("Create normalized prefab", MessageType.Info);
EditorGUILayout.PropertyField(serializedObject.FindProperty(nameof(VrmScriptedImporter.Normalize)));
serializedObject.ApplyModifiedProperties();
}
{
serializedObject.Update();
// normalize
EditorGUILayout.Space();
EditorGUILayout.HelpBox("Create normalized prefab", MessageType.Info);
EditorGUILayout.PropertyField(serializedObject.FindProperty(nameof(VrmScriptedImporter.Normalize)));
serializedObject.ApplyModifiedProperties();
}
ApplyRevertGUI();
break;
case Vrm10FileType.Vrm0:
EditorGUILayout.HelpBox(m_result.Message, m_model != null ? MessageType.Info : MessageType.Warning);
if (VRMShaders.Symbols.VRM_DEVELOP)
{
if (GUILayout.Button("debug export"))
{
File.WriteAllBytes("tmp.vrm", m_result.MigratedBytes);
}
}
{
serializedObject.Update();
// migration
EditorGUILayout.PropertyField(serializedObject.FindProperty(nameof(VrmScriptedImporter.MigrateToVrm1)));
serializedObject.ApplyModifiedProperties();
}
ApplyRevertGUI();
break;
default:
ApplyRevertGUI();
break;
ApplyRevertGUI();
}
else
{
EditorGUILayout.HelpBox(m_migration.Message, m_model != null ? MessageType.Info : MessageType.Warning);
if (VRMShaders.Symbols.VRM_DEVELOP)
{
if (GUILayout.Button("debug export"))
{
File.WriteAllBytes("tmp.vrm", m_migration.MigratedBytes);
}
}
{
serializedObject.Update();
// migration
EditorGUILayout.PropertyField(serializedObject.FindProperty(nameof(VrmScriptedImporter.MigrateToVrm1)));
serializedObject.ApplyModifiedProperties();
}
ApplyRevertGUI();
}
break;
}
break;
case Tabs.Materials:
if (m_result.Data != null && m_result.VrmExtension != null)

View File

@ -43,43 +43,46 @@ namespace UniVRM10
Debug.Log("OnImportAsset to " + scriptedImporter.assetPath);
#endif
if (!Vrm10Data.TryParseOrMigrate(scriptedImporter.assetPath, migrateToVrm1, out Vrm10Data result))
using (var data = Vrm10Data.ParseOrMigrate(scriptedImporter.assetPath, migrateToVrm1, out Vrm10Data result, out MigrationData migration))
{
// fail to parse vrm1
return;
}
//
// Import(create unity objects)
//
var extractedObjects = scriptedImporter.GetExternalObjectMap()
.Where(kv => kv.Value != null)
.ToDictionary(kv => new SubAssetKey(kv.Value.GetType(), kv.Key.name), kv => kv.Value);
var materialGenerator = GetMaterialDescriptorGenerator(renderPipeline);
using (var loader = new Vrm10Importer(result, extractedObjects,
materialGenerator: materialGenerator,
doNormalize: doNormalize))
{
// settings TextureImporters
foreach (var textureInfo in loader.TextureDescriptorGenerator.Get().GetEnumerable())
if (result == null)
{
VRMShaders.TextureImporterConfigurator.Configure(textureInfo, loader.TextureFactory.ExternalTextures);
// fail to parse vrm1
return;
}
var loaded = loader.Load();
loaded.ShowMeshes();
//
// Import(create unity objects)
//
var extractedObjects = scriptedImporter.GetExternalObjectMap()
.Where(kv => kv.Value != null)
.ToDictionary(kv => new SubAssetKey(kv.Value.GetType(), kv.Key.name), kv => kv.Value);
loaded.TransferOwnership((key, o) =>
var materialGenerator = GetMaterialDescriptorGenerator(renderPipeline);
using (var loader = new Vrm10Importer(result, extractedObjects,
materialGenerator: materialGenerator,
doNormalize: doNormalize))
{
context.AddObjectToAsset(key.Name, o);
});
var root = loaded.Root;
GameObject.DestroyImmediate(loaded);
// settings TextureImporters
foreach (var textureInfo in loader.TextureDescriptorGenerator.Get().GetEnumerable())
{
VRMShaders.TextureImporterConfigurator.Configure(textureInfo, loader.TextureFactory.ExternalTextures);
}
context.AddObjectToAsset(root.name, root);
context.SetMainObject(root);
var loaded = loader.Load();
loaded.ShowMeshes();
loaded.TransferOwnership((key, o) =>
{
context.AddObjectToAsset(key.Name, o);
});
var root = loaded.Root;
GameObject.DestroyImmediate(loaded);
context.AddObjectToAsset(root.name, root);
context.SetMainObject(root);
}
}
}
}

View File

@ -7,23 +7,8 @@ using UniJSON;
namespace UniVRM10
{
public enum Vrm10FileType
public class MigrationData
{
Vrm1,
Vrm0,
Other,
}
public class Vrm10Data : IDisposable
{
public GltfData Data { get; }
public UniGLTF.Extensions.VRMC_vrm.VRMC_vrm VrmExtension { get; }
/// <summary>
/// TryParse した元のファイルの種類。元が vrm0 だったか分かる
/// </summary>
public readonly Vrm10FileType FileType;
/// <summary>
/// マイグレーション失敗など
/// </summary>
@ -39,128 +24,136 @@ namespace UniVRM10
/// </summary>
public readonly byte[] MigratedBytes;
Vrm10Data(GltfData data, VRMC_vrm vrm, Vrm10FileType fileType, string message,
Migration.Vrm0Meta oldMeta = null,
byte[] migratedBytes = null)
public MigrationData(string msg, Migration.Vrm0Meta meta = default, byte[] bytes = default)
{
Message = msg;
OriginalMetaBeforeMigration = meta;
MigratedBytes = bytes;
}
}
public class Vrm10Data
{
public GltfData Data { get; }
public UniGLTF.Extensions.VRMC_vrm.VRMC_vrm VrmExtension { get; }
Vrm10Data(GltfData data, VRMC_vrm vrm)
{
Data = data;
VrmExtension = vrm;
FileType = fileType;
Message = message;
OriginalMetaBeforeMigration = oldMeta;
MigratedBytes = migratedBytes;
}
public void Dispose()
public static GltfData ParseOrMigrate(string path, bool doMigrate, out Vrm10Data vrm1Data, out MigrationData migration)
{
Data.Dispose();
}
public static bool TryParseOrMigrate(string path, bool doMigrate, out Vrm10Data result)
{
return TryParseOrMigrate(path, File.ReadAllBytes(path), doMigrate, out result);
}
public static bool TryParseOrMigrate(string path, byte[] bytes, bool doMigrate, out Vrm10Data result)
{
var data = new GlbLowLevelParser(path, bytes).Parse();
return TryParseOrMigrate(data, doMigrate, out result);
return ParseOrMigrate(path, File.ReadAllBytes(path), doMigrate, out vrm1Data, out migration);
}
/// <summary>
/// VRM1 でパースし、失敗したら Migration してから VRM1 でパースする
/// Parse もしくは Migration を試みる。
/// </summary>
/// <param name="path"></param>
/// <param name="bytes"></param>
/// <param name="doMigrate"></param>
/// <returns></returns>
public static bool TryParseOrMigrate(GltfData data, bool doMigrate, out Vrm10Data result)
public static GltfData ParseOrMigrate(string path, byte[] bytes, bool doMigrate, out Vrm10Data vrm1Data, out MigrationData migration)
{
//
// Parse(parse glb, parser gltf json)
//
// 成功した場合はユーザーが Dispose する。
// 失敗した場合はこの関数が始末する。
var data = new GlbLowLevelParser(path, bytes).Parse();
byte[] migrated = default;
byte[] migratedBytes = null;
Migration.Vrm0Meta oldMeta = default;
try
{
if (UniGLTF.Extensions.VRMC_vrm.GltfDeserializer.TryGet(data.GLTF.extensions, out UniGLTF.Extensions.VRMC_vrm.VRMC_vrm vrm))
{
// success
result = new Vrm10Data(data, vrm, Vrm10FileType.Vrm1, "vrm1: loaded");
return true;
}
}
// try migrateion
byte[] migrated = default;
Migration.Vrm0Meta oldMeta = default;
try
{
var json = data.Json.ParseAsJson();
try
{
if (!json.TryGet("extensions", out JsonNode extensions))
{
result = new Vrm10Data(default, default, Vrm10FileType.Other, "gltf: no extensions");
return false;
}
if (!extensions.TryGet("VRM", out JsonNode vrm0))
{
result = new Vrm10Data(default, default, Vrm10FileType.Other, "gltf: no vrm0");
return false;
}
}
catch (Exception ex)
{
result = new Vrm10Data(default, default, Vrm10FileType.Other, $"error: {ex}");
return false;
vrm1Data = new Vrm10Data(data, vrm);
migration = default;
return data;
}
if (!doMigrate)
{
result = new Vrm10Data(default, default, Vrm10FileType.Vrm0, "vrm0: not migrated");
return false;
vrm1Data = default;
migration = new MigrationData("Not vrm1 and no migration");
return data;
}
// try migrateion
// Migration.Vrm0Meta oldMeta = default;
JsonNode json = data.Json.ParseAsJson();
if (!json.TryGet("extensions", out JsonNode extensions))
{
vrm1Data = default;
migration = new MigrationData("gltf: no extensions");
return data;
}
if (!extensions.TryGet("VRM", out JsonNode vrm0))
{
vrm1Data = default;
migration = new MigrationData("gltf: no vrm0");
return data;
}
// found vrm0
oldMeta = Migration.Vrm0Meta.FromJsonBytes(json);
if (oldMeta == null)
{
throw new NullReferenceException("oldMeta");
}
// try migrate...
migrated = MigrationVrm.Migrate(data);
if (migrated == null)
{
result = new Vrm10Data(default, default, Vrm10FileType.Vrm0, "vrm0: cannot migrate");
return false;
vrm1Data = default;
migration = new MigrationData("Found vrm0. But fail to migrate", oldMeta);
return data;
}
oldMeta = Migration.Vrm0Meta.FromJsonBytes(json);
if (VRMShaders.Symbols.VRM_DEVELOP)
{
// load 時の右手左手座標変換でバッファが破壊的変更されるので、コピーを作っている
migratedBytes = migrated.Select(x => x).ToArray();
}
}
catch (Exception ex)
{
result = new Vrm10Data(default, default, Vrm10FileType.Vrm0, $"vrm0: migration error: {ex}");
return false;
// 何か起きた。Dispose は頼む
vrm1Data = default;
migration = new MigrationData(ex.Message);
return data;
}
// マイグレーション前を破棄
data.Dispose();
// マイグレーション結果をパースする
var migratedData = new GlbLowLevelParser(data.TargetPath, migrated).Parse();
try
{
var migratedData = new GlbLowLevelParser(data.TargetPath, migrated).Parse();
if (UniGLTF.Extensions.VRMC_vrm.GltfDeserializer.TryGet(migratedData.GLTF.extensions, out VRMC_vrm vrm))
if (!UniGLTF.Extensions.VRMC_vrm.GltfDeserializer.TryGet(migratedData.GLTF.extensions, out VRMC_vrm vrm))
{
// success
if (oldMeta == null)
{
throw new NullReferenceException("oldMeta");
}
byte[] migratedBytes = null;
if (VRMShaders.Symbols.VRM_DEVELOP)
{
// 右手左手座標変換でバッファが破壊的変更されるので、コピーを作っている
migratedBytes = migrated.Select(x => x).ToArray();
}
result = new Vrm10Data(migratedData, vrm, Vrm10FileType.Vrm0,
message: "vrm0: migrated",
oldMeta: oldMeta,
migratedBytes: migratedBytes
);
return true;
// migration した結果のパースに失敗した !
vrm1Data = default;
migration = new MigrationData("vrm0: migrate but error ?", oldMeta, migrated);
return migratedData;
}
result = new Vrm10Data(default, default, Vrm10FileType.Vrm0, "vrm0: migrate but error ?");
return false;
{
// success
vrm1Data = new Vrm10Data(migratedData, vrm);
migration = new MigrationData("vrm0: migrated", oldMeta, migratedBytes);
return migratedData;
}
}
catch (Exception ex)
{
// 何か起きた。Dispose は頼む
vrm1Data = default;
migration = new MigrationData(ex.Message);
return migratedData;
}
}
}

View File

@ -4,10 +4,13 @@ namespace UniVRM10
{
public class Vrm10Exception : Exception
{
public Vrm10Exception(string msg) : base(msg)
{ }
}
public class Vrm10NoExtensionException: Vrm10Exception
public class Vrm10NoExtensionException : Vrm10Exception
{
public Vrm10NoExtensionException(string msg) : base(msg)
{ }
}
}

View File

@ -540,7 +540,7 @@ namespace UniVRM10
}
else
{
throw new Vrm10Exception();
throw new Vrm10Exception("unknown shape");
}
}

View File

@ -15,11 +15,7 @@ namespace UniVRM10.Sample
static GameObject Import(byte[] bytes, FileInfo path)
{
if (!Vrm10Data.TryParseOrMigrate(path.FullName, bytes, doMigrate: true, out Vrm10Data result))
{
return null;
}
using (var data = Vrm10Data.ParseOrMigrate(path.FullName, bytes, doMigrate: true, out Vrm10Data result, out MigrationData migration))
using (var loader = new Vrm10Importer(result))
{
var loaded = loader.Load();

View File

@ -31,12 +31,14 @@ namespace UniVRM10.Test
private (GameObject, IReadOnlyList<VRMShaders.MaterialFactory.MaterialLoadInfo>) ToUnity(byte[] bytes)
{
// Vrm => Model
if (!Vrm10Data.TryParseOrMigrate("tpm.vrm", bytes, true, out Vrm10Data result))
using (var data = Vrm10Data.ParseOrMigrate("tpm.vrm", bytes, true, out Vrm10Data result, out MigrationData migration))
{
throw new Exception();
if (result == null)
{
throw new Exception();
}
return ToUnity(result);
}
return ToUnity(result);
}
private (GameObject, IReadOnlyList<VRMShaders.MaterialFactory.MaterialLoadInfo>) ToUnity(Vrm10Data data)

View File

@ -39,9 +39,10 @@ namespace UniVRM10.Test
var path = "Tests/Models/Alicia_vrm-0.51/AliciaSolid_vrm-0.51.vrm";
Debug.Log($"load: {path}");
Assert.IsTrue(Vrm10Data.TryParseOrMigrate(path, true, out Vrm10Data result));
using (result)
using (var data = Vrm10Data.ParseOrMigrate(path, true, out Vrm10Data result, out MigrationData migration))
{
Assert.NotNull(result);
var go = BuildGameObject(result, true);
Debug.Log(go);

View File

@ -7,16 +7,19 @@ namespace UniVRM10.Test
[Test]
public void EmptyThumbnailName()
{
Assert.True(Vrm10Data.TryParseOrMigrate(TestAsset.AliciaPath, true, out Vrm10Data vrm));
var index = vrm.VrmExtension.Meta.ThumbnailImage.Value;
// empty thumbnail name
vrm.Data.GLTF.images[index].name = null;
using (var loader = new Vrm10Importer(vrm))
using (var data = Vrm10Data.ParseOrMigrate(TestAsset.AliciaPath, true, out Vrm10Data vrm, out MigrationData migration))
{
loader.LoadAsync(new VRMShaders.ImmediateCaller()).Wait();
Assert.NotNull(vrm);
var index = vrm.VrmExtension.Meta.ThumbnailImage.Value;
// empty thumbnail name
vrm.Data.GLTF.images[index].name = null;
using (var loader = new Vrm10Importer(vrm))
{
loader.LoadAsync(new VRMShaders.ImmediateCaller()).Wait();
}
}
}
}

View File

@ -198,8 +198,7 @@ namespace UniVRM10
{
try
{
Assert.True(Vrm10Data.TryParseOrMigrate(gltf.FullName, true, out Vrm10Data vrm));
using (vrm)
using (var data = Vrm10Data.ParseOrMigrate(gltf.FullName, true, out Vrm10Data vrm, out MigrationData migration))
using (var loader = new Vrm10Importer(vrm))
{
loader.LoadAsync().Wait();
@ -262,8 +261,11 @@ namespace UniVRM10
[Test]
public void MigrateMeta()
{
Assert.True(Vrm10Data.TryParseOrMigrate(AliciaPath, true, out Vrm10Data vrm));
vrm.Dispose();
using (var data = Vrm10Data.ParseOrMigrate(AliciaPath, true, out Vrm10Data vrm, out MigrationData migration))
{
Assert.NotNull(vrm);
Assert.NotNull(migration);
}
}
}
}

View File

@ -16,8 +16,7 @@ namespace UniVRM10
public static Vrm10Instance LoadAlicia()
{
Vrm10Data.TryParseOrMigrate(AliciaPath, true, out Vrm10Data vrm);
using (vrm)
using (var data = Vrm10Data.ParseOrMigrate(AliciaPath, true, out Vrm10Data vrm, out MigrationData migration))
using (var loader = new Vrm10Importer(vrm))
{
var task = loader.LoadAsync(new VRMShaders.ImmediateCaller());

View File

@ -88,20 +88,22 @@ namespace UniVRM10.FirstPersonSample
async Task<RuntimeGltfInstance> LoadAsync(string path)
{
var data = new GlbFileParser(path).Parse();
if (!Vrm10Data.TryParseOrMigrate(data, true, out Vrm10Data vrm))
using (var data = Vrm10Data.ParseOrMigrate(path, true, out Vrm10Data vrm, out MigrationData migration))
{
throw new System.Exception("vrm parse error !");
}
using (var loader = new Vrm10Importer(vrm))
{
var instance = await loader.LoadAsync();
if (vrm == null)
{
throw new System.Exception("vrm parse error !");
}
using (var loader = new Vrm10Importer(vrm))
{
var instance = await loader.LoadAsync();
// VR用 FirstPerson 設定
var controller = instance.GetComponent<Vrm10Instance>();
await controller.Vrm.FirstPerson.SetupAsync(controller.gameObject);
// VR用 FirstPerson 設定
var controller = instance.GetComponent<Vrm10Instance>();
await controller.Vrm.FirstPerson.SetupAsync(controller.gameObject);
return instance;
return instance;
}
}
}

View File

@ -425,43 +425,32 @@ namespace UniVRM10.VRM10Viewer
}
Debug.LogFormat("{0}", path);
GltfData data;
try
var (vrm, migration) = await System.Threading.Tasks.Task.Run(() =>
{
data = new AutoGltfFileParser(path).Parse();
}
catch (Exception ex)
{
Debug.LogWarning(ex);
return;
}
var vrm = await System.Threading.Tasks.Task.Run(() =>
{
if (Vrm10Data.TryParseOrMigrate(data, doMigrate: true, out Vrm10Data _vrm))
using (var data = Vrm10Data.ParseOrMigrate(path, doMigrate: true, out Vrm10Data _vrm, out MigrationData _migration))
{
return _vrm;
}
else
{
return null;
if (_vrm != null)
{
return (_vrm, _migration);
}
}
return default;
});
if (vrm != null)
{
// vrm
using (var loader = new Vrm10Importer(vrm,
using (var loader = new Vrm10Importer(vrm,
materialGenerator: GetVrmMaterialDescriptorGenerator(m_useUrpMaterial.isOn),
doNormalize: m_useNormalization.isOn))
{
// migrate しても thumbnail は同じ
var thumbnail = await loader.LoadVrmThumbnailAsync();
if (vrm.OriginalMetaBeforeMigration != null)
if (migration != null)
{
// migrated from vrm-0.x. use OldMeta
m_texts.UpdateMeta(vrm.OriginalMetaBeforeMigration, thumbnail);
m_texts.UpdateMeta(migration.OriginalMetaBeforeMigration, thumbnail);
}
else
{
@ -476,6 +465,7 @@ namespace UniVRM10.VRM10Viewer
else
{
// gltf
using (var data = new AutoGltfFileParser(path).Parse())
using (var loader = new UniGLTF.ImporterContext(data, materialGenerator: GetMaterialDescriptorGenerator(m_useUrpMaterial.isOn)))
{
var instance = await loader.LoadAsync(new RuntimeOnlyAwaitCaller());