diff --git a/Assets/UniGLTF/Runtime/UniJSON/ListTreeNode/ListTreeNodeObjectExtensions.cs b/Assets/UniGLTF/Runtime/UniJSON/ListTreeNode/ListTreeNodeObjectExtensions.cs index 6a3d3e34b..5f884988c 100644 --- a/Assets/UniGLTF/Runtime/UniJSON/ListTreeNode/ListTreeNodeObjectExtensions.cs +++ b/Assets/UniGLTF/Runtime/UniJSON/ListTreeNode/ListTreeNodeObjectExtensions.cs @@ -66,6 +66,27 @@ namespace UniJSON return self.ContainsKey(ukey); } + public static bool TryGet(this JsonNode self, Utf8String key, out JsonNode found) + { + foreach (var kv in self.ObjectItems()) + { + if (kv.Key.GetUtf8String() == key) + { + found = kv.Value; + return true; + } + } + + found = default; + return false; + } + + public static bool TryGet(this JsonNode self, String key, out JsonNode found) + { + var ukey = Utf8String.From(key); + return self.TryGet(ukey, out found); + } + public static Utf8String KeyOf(this JsonNode self, JsonNode node) { foreach (var kv in self.ObjectItems()) diff --git a/Assets/VRM10/Editor/ScriptedImporter/VrmScriptedImporter.cs b/Assets/VRM10/Editor/ScriptedImporter/VrmScriptedImporter.cs index 69d994c0e..3a2d71eb3 100644 --- a/Assets/VRM10/Editor/ScriptedImporter/VrmScriptedImporter.cs +++ b/Assets/VRM10/Editor/ScriptedImporter/VrmScriptedImporter.cs @@ -2,6 +2,7 @@ using UnityEditor.AssetImporters; #else using UnityEditor.Experimental.AssetImporters; +using UnityEngine; #endif @@ -10,9 +11,12 @@ namespace UniVRM10 [ScriptedImporter(1, "vrm")] public class VrmScriptedImporter : ScriptedImporter { + [SerializeField] + bool m_migrateToVrm1 = default; + public override void OnImportAsset(AssetImportContext ctx) { - VrmScriptedImporterImpl.Import(this, ctx); + VrmScriptedImporterImpl.Import(this, ctx, m_migrateToVrm1); } } } diff --git a/Assets/VRM10/Editor/ScriptedImporter/VrmScriptedImporterImpl.cs b/Assets/VRM10/Editor/ScriptedImporter/VrmScriptedImporterImpl.cs index 540da45a5..6a10803e6 100644 --- a/Assets/VRM10/Editor/ScriptedImporter/VrmScriptedImporterImpl.cs +++ b/Assets/VRM10/Editor/ScriptedImporter/VrmScriptedImporterImpl.cs @@ -1,6 +1,7 @@ using System.Linq; using UnityEngine; using UniGLTF; +using System.IO; #if UNITY_2020_2_OR_NEWER using UnityEditor.AssetImporters; #else @@ -17,17 +18,42 @@ namespace UniVRM10 // const string MetaDirName = "MetaObjects"; // const string ExpressionDirName = "Expressions"; - public static void Import(ScriptedImporter scriptedImporter, AssetImportContext context) + static GltfParser Parse(string path, bool migrateToVrm1) + { + // + // Parse(parse glb, parser gltf json) + // + var parser = new GltfParser(); + parser.ParsePath(path); + if (UniGLTF.Extensions.VRMC_vrm.GltfDeserializer.TryGet(parser.GLTF.extensions, out UniGLTF.Extensions.VRMC_vrm.VRMC_vrm vrm)) + { + return parser; + } + + if (migrateToVrm1) + { + // try migrateion + var migrated = MigrationVrm.Migrate(File.ReadAllBytes(path)); + parser = new GltfParser(); + parser.Parse(path, migrated); + return parser; + } + + return null; + } + + public static void Import(ScriptedImporter scriptedImporter, AssetImportContext context, bool migrateToVrm1) { #if VRM_DEVELOP Debug.Log("OnImportAsset to " + scriptedImporter.assetPath); #endif - // - // Parse(parse glb, parser gltf json) - // - var parser = new GltfParser(); - parser.ParsePath(scriptedImporter.assetPath); + var parser = Parse(scriptedImporter.assetPath, migrateToVrm1); + if (parser == null) + { + // fail to parse vrm1 + return; + } // // Import(create unity objects) @@ -36,11 +62,11 @@ namespace UniVRM10 using (var loader = new RuntimeUnityBuilder(parser, externalObjectMap)) { - // // settings TextureImporters - // foreach (var textureInfo in GltfTextureEnumerator.Enumerate(parser)) - // { - // TextureImporterConfigurator.Configure(textureInfo, loader.TextureFactory.ExternalMap); - // } + // settings TextureImporters + foreach (var textureInfo in Vrm10MToonMaterialImporter.EnumerateAllTexturesDistinct(parser)) + { + TextureImporterConfigurator.Configure(textureInfo, loader.TextureFactory.ExternalMap); + } loader.Load(); loader.ShowMeshes(); diff --git a/Assets/VRM10/Runtime/IO/Vrm10MToonMaterialImporter.cs b/Assets/VRM10/Runtime/IO/Vrm10MToonMaterialImporter.cs index d8a32713e..32c8ff975 100644 --- a/Assets/VRM10/Runtime/IO/Vrm10MToonMaterialImporter.cs +++ b/Assets/VRM10/Runtime/IO/Vrm10MToonMaterialImporter.cs @@ -40,6 +40,22 @@ namespace UniVRM10 } } + if (m.normalTexture != null && m.normalTexture.index != -1) + { + // normal map + param.Actions.Add(material => material.EnableKeyword("_NORMALMAP")); + var textureParam = GltfPBRMaterial.NormalTexture(parser, m); + param.TextureSlots.Add("_BumpMap", textureParam); + // param.FloatValues.Add("_BumpScale", m.normalTexture.scale); + } + + if (m.emissiveTexture != null && m.emissiveTexture.index != -1) + { + var (offset, scale) = GltfMaterialImporter.GetTextureOffsetAndScale(m.emissiveTexture); + var textureParam = GltfTextureImporter.CreateSRGB(parser, m.emissiveTexture.index, offset, scale); + param.TextureSlots.Add("_EmissionMap", textureParam); + } + // TODO: return true; diff --git a/Assets/VRM10/Runtime/Migration/MigrationVrmExpression.cs b/Assets/VRM10/Runtime/Migration/MigrationVrmExpression.cs index c9605c77b..62ffee153 100644 --- a/Assets/VRM10/Runtime/Migration/MigrationVrmExpression.cs +++ b/Assets/VRM10/Runtime/Migration/MigrationVrmExpression.cs @@ -113,6 +113,7 @@ namespace UniVRM10 var targetValue = x["targetValue"].ArrayItems().Select(y => y.GetSingle()).ToArray(); if (propertyName.EndsWith("_ST")) { + var scaling = new float[] { targetValue[0], targetValue[1] }; expression.TextureTransformBinds.Add(new UniGLTF.Extensions.VRMC_vrm.TextureTransformBind { Material = materialIndex, @@ -156,14 +157,27 @@ namespace UniVRM10 foreach (var blendShapeClip in json["blendShapeGroups"].ArrayItems()) { var name = blendShapeClip["name"].GetString(); + var isBinary = false; + if (blendShapeClip.TryGet("isBinary", out JsonNode isBinaryNode)) + { + isBinary = isBinaryNode.GetBoolean(); + } var expression = new UniGLTF.Extensions.VRMC_vrm.Expression { Name = name, Preset = ToPreset(blendShapeClip["presetName"]), - IsBinary = blendShapeClip["isBinary"].GetBoolean(), + IsBinary = isBinary, + MorphTargetBinds = new List(), + MaterialColorBinds = new List(), + TextureTransformBinds = new List(), }; expression.MorphTargetBinds = ToMorphTargetBinds(gltf, blendShapeClip["binds"]).ToList(); - ToMaterialColorBinds(gltf, blendShapeClip["materialValues"], expression); + + if (blendShapeClip.TryGet("materialValues", out JsonNode materialValues)) + { + ToMaterialColorBinds(gltf, materialValues, expression); + } + yield return expression; } } diff --git a/Assets/VRM10/Runtime/Migration/RotateY180.cs b/Assets/VRM10/Runtime/Migration/RotateY180.cs index 749ddbb43..f4878cb63 100644 --- a/Assets/VRM10/Runtime/Migration/RotateY180.cs +++ b/Assets/VRM10/Runtime/Migration/RotateY180.cs @@ -4,6 +4,11 @@ using UniGLTF; namespace UniVRM10 { + public class UnNormalizedException : Exception + { + + } + /// /// x, y, z => -x, y, -z /// @@ -32,7 +37,7 @@ namespace UniVRM10 } else { - throw new NotImplementedException("not normalized !"); + throw new UnNormalizedException(); } } if (node.scale != null && node.scale.Length == 3) diff --git a/Assets/VRM10/Tests/MigrationTests.cs b/Assets/VRM10/Tests/MigrationTests.cs index e6265804b..2f5bded6f 100644 --- a/Assets/VRM10/Tests/MigrationTests.cs +++ b/Assets/VRM10/Tests/MigrationTests.cs @@ -5,6 +5,7 @@ using UniJSON; using System; using UniGLTF; using System.Runtime.InteropServices; +using System.Collections.Generic; namespace UniVRM10 { @@ -154,5 +155,63 @@ namespace UniVRM10 } Assert.AreEqual(1.0f, BitConverter.ToSingle(bytes, 4)); } + + static IEnumerable EnumerateGltfFiles(DirectoryInfo dir) + { + if (dir.Name == ".git") + { + yield break; + } + + foreach (var child in dir.EnumerateDirectories()) + { + foreach (var x in EnumerateGltfFiles(child)) + { + yield return x; + } + } + + foreach (var child in dir.EnumerateFiles()) + { + switch (child.Extension.ToLower()) + { + case ".vrm": + yield return child; + break; + } + } + } + + [Test] + public void Migrate_VrmTestModels() + { + var env = System.Environment.GetEnvironmentVariable("VRM_TEST_MODELS"); + if (string.IsNullOrEmpty(env)) + { + return; + } + var root = new DirectoryInfo(env); + if (!root.Exists) + { + return; + } + + foreach (var gltf in EnumerateGltfFiles(root)) + { + var bytes = File.ReadAllBytes(gltf.FullName); + try + { + var migrated = MigrationVrm.Migrate(bytes); + var parser = new GltfParser(); + parser.Parse(gltf.FullName, migrated); + UniGLTF.Extensions.VRMC_vrm.GltfDeserializer.TryGet(parser.GLTF.extensions, out UniGLTF.Extensions.VRMC_vrm.VRMC_vrm vrm); + Assert.NotNull(vrm); + } + catch (UnNormalizedException) + { + Debug.LogWarning($"[Not Normalized] {gltf}"); + } + } + } } }