Пример #1
0
        public override void OnEnable()
        {
            base.OnEnable();

            var importer = target as VrmScriptedImporter;

            m_importer = importer;
            using (var data = new GlbFileParser(m_importer.assetPath).Parse())
            {
                m_result = Vrm10Data.Parse(data);
                if (m_result != null)
                {
                    OnData();
                }
                else
                {
                    using (var migrated = Vrm10Data.Migrate(data, out m_result, out m_migration))
                    {
                        if (m_result != null)
                        {
                            OnData();
                        }
                    }
                }
            }
        }
Пример #2
0
        public void VRMLookAtTest()
        {
            var data = new GlbFileParser(AliciaPath).Parse();

            byte[] bytes = default;
            using (data)
                using (var loader = new VRMImporterContext(new VRMData(data)))
                    using (var loaded = loader.Load())
                    {
                        loaded.ShowMeshes();

                        var go = loaded.gameObject;
                        var fp = go.GetComponent <VRMFirstPerson>();
                        GameObject.DestroyImmediate(go.GetComponent <VRMLookAtBoneApplyer>());
                        var lookAt = go.AddComponent <VRMLookAtBlendShapeApplyer>();
                        bytes = VRMEditorExporter.Export(go, null, new VRMExportSettings
                        {
                            PoseFreeze = true,
                        });
                    }

            using (var data2 = new GlbLowLevelParser(AliciaPath, bytes).Parse())
                using (var loader2 = new VRMImporterContext(new VRMData(data2)))
                {
                    Assert.AreEqual(LookAtType.BlendShape, loader2.VRM.firstPerson.lookAtType);
                }
        }
Пример #3
0
        public void SerializerCompare()
        {
            // Aliciaを古いデシリアライザでロードする
            var path = AliciaPath;
            var data = new GlbFileParser(path).Parse();

            using (var context = new VRMImporterContext(new VRMData(data)))
            {
                var oldJson = context.GLTF.ToJson().ParseAsJson().ToString("  ");

                // 生成シリアライザでJSON化する
                var f = new JsonFormatter();
                GltfSerializer.Serialize(f, context.GLTF);
                var parsed  = f.ToString().ParseAsJson();
                var newJson = parsed.ToString("  ");

                // File.WriteAllText("old.json", oldJson);
                // File.WriteAllText("new.json", newJson);

                // 比較
                Assert.AreEqual(oldJson.ParseAsJson().ToString(), newJson.ParseAsJson().ToString());

                // 生成デシリアライザでロードする
                var ff  = new JsonFormatter();
                var des = GltfDeserializer.Deserialize(parsed);
                ff.Clear();
                GltfSerializer.Serialize(ff, des);
                var desJson = ff.ToString().ParseAsJson().ToString("  ");
                Assert.AreEqual(oldJson.ParseAsJson().ToString(), desJson.ParseAsJson().ToString());
            }
        }
Пример #4
0
        static GameObject Load(FileInfo gltf, DirectoryInfo root, byte[] bytes = null)
        {
            GltfData data = null;

            try
            {
                if (bytes != null)
                {
                    data = new GlbLowLevelParser(gltf.FullName, bytes).Parse();
                }
                else
                {
                    data = new GlbFileParser(gltf.FullName).Parse();
                }
            }
            catch (Exception ex)
            {
                Debug.LogError($"ParseError: {gltf}");
                Debug.LogException(ex);
                return(null);
            }

            try
            {
                using (var importer = new VRMImporterContext(data))
                {
                    return(importer.Load().gameObject);
                }
            }
            catch (Exception ex)
            {
                Message(gltf.FullName.Substring(root.FullName.Length), ex);
                return(null);
            }
        }
Пример #5
0
        async void OnLoadClicked()
        {
#if UNITY_STANDALONE_WIN
            var path = FileDialogForWindows.FileDialog("open VRM", ".vrm");
#elif UNITY_EDITOR
            var path = UnityEditor.EditorUtility.OpenFilePanel("Open VRM", "", "vrm");
#else
            var path = Application.dataPath + "/default.vrm";
#endif
            if (string.IsNullOrEmpty(path))
            {
                return;
            }

            // GLB形式でJSONを取得しParseします
            var data = new GlbFileParser(path).Parse();
            // VRM extension を parse します
            var vrm = new VRMData(data);
            using (var context = new VRMImporterContext(vrm))
            {
                // metaを取得(todo: thumbnailテクスチャのロード)
                var meta = await context.ReadMetaAsync();

                Debug.LogFormat("meta: title:{0}", meta.Title);

                // ParseしたJSONをシーンオブジェクトに変換していく
                var loaded = await context.LoadAsync();

                loaded.ShowMeshes();
                loaded.EnableUpdateWhenOffscreen();

                OnLoaded(loaded.gameObject);
            }
        }
Пример #6
0
        /// <summary>
        /// メタが不要な場合のローダー
        /// </summary>
        async void LoadVRMClicked_without_meta()
        {
#if UNITY_STANDALONE_WIN
            var path = FileDialogForWindows.FileDialog("open VRM", ".vrm");
#elif UNITY_EDITOR
            var path = UnityEditor.EditorUtility.OpenFilePanel("Open VRM", "", "vrm");
#else
            var path = Application.dataPath + "/default.vrm";
#endif
            if (string.IsNullOrEmpty(path))
            {
                return;
            }

            // GLB形式でJSONを取得しParseします
            var data = new GlbFileParser(path).Parse();
            // VRM extension を parse します
            var vrm     = new VRMData(data);
            var context = new VRMImporterContext(vrm);
            var loaded  = default(RuntimeGltfInstance);
            if (m_loadAsync)
            {
                loaded = await context.LoadAsync();
            }
            else
            {
                loaded = context.Load();
            }
            OnLoaded(loaded);
        }
Пример #7
0
        public void VRMLookAtCurveMapTest()
        {
            var data = new GlbFileParser(AliciaPath).Parse();

            byte[]      bytes           = default;
            CurveMapper horizontalInner = default;

            using (data)
                using (var loader = new VRMImporterContext(new VRMData(data)))
                    using (var loaded = loader.Load())
                    {
                        loaded.ShowMeshes();

                        var go     = loaded.gameObject;
                        var fp     = go.GetComponent <VRMFirstPerson>();
                        var lookAt = go.GetComponent <VRMLookAtBoneApplyer>();
                        horizontalInner = lookAt.HorizontalInner;
                        bytes           = VRMEditorExporter.Export(go, null, new VRMExportSettings
                        {
                            PoseFreeze = false,
                        });
                    }

            using (var data2 = new GlbLowLevelParser(AliciaPath, bytes).Parse())
                using (var loader = new VRMImporterContext(new VRMData(data2)))
                    using (var loaded = loader.Load())
                    {
                        loaded.ShowMeshes();

                        var lookAt = loaded.GetComponent <VRMLookAtBoneApplyer>();
                        Assert.AreEqual(horizontalInner.CurveXRangeDegree, lookAt.HorizontalInner.CurveXRangeDegree);
                        Assert.AreEqual(horizontalInner.CurveYRangeDegree, lookAt.HorizontalInner.CurveYRangeDegree);
                    }
        }
Пример #8
0
 /// <summary>
 /// load into scene
 /// </summary>
 /// <param name="path">vrm path</param>
 static void ImportRuntime(string path)
 {
     using (var data = new GlbFileParser(path).Parse())
         using (var context = new VRMImporterContext(new VRMData(data)))
         {
             var loaded = context.Load();
             loaded.EnableUpdateWhenOffscreen();
             loaded.ShowMeshes();
             Selection.activeGameObject = loaded.gameObject;
         }
 }
Пример #9
0
        public void MaterialImporterTest()
        {
            var path          = AliciaPath;
            var data          = new GlbFileParser(path).Parse();
            var vrmImporter   = new VRMImporterContext(data, null);
            var materialParam = new VRMMaterialDescriptorGenerator(vrmImporter.VRM).Get(data, 0);

            Assert.AreEqual("VRM/MToon", materialParam.ShaderName);
            Assert.AreEqual("Alicia_body", materialParam.TextureSlots["_MainTex"].UnityObjectName);

            var(key, value) = materialParam.EnumerateSubAssetKeyValue().First();
            Assert.AreEqual(new SubAssetKey(typeof(Texture), "Alicia_body"), key);
        }
Пример #10
0
        public void MToonMaterialParamTest()
        {
            if (!VRMTestAssets.TryGetPath("Models/VRoid/VictoriaRubin/VictoriaRubin.vrm", out string path))
            {
                return;
            }

            var data = new GlbFileParser(path).Parse();

            var importer = new VRMImporterContext(data, null);

            Assert.AreEqual(73, data.GLTF.materials.Count);
            Assert.True(VRMMToonMaterialImporter.TryCreateParam(data, importer.VRM, 0, out MaterialDescriptor matDesc));
        }
Пример #11
0
        static void ImportRuntime(string path)
        {
            // load into scene
            var data = new GlbFileParser(path).Parse();
            // VRM extension を parse します
            var vrm = new VRMData(data);

            using (var context = new VRMImporterContext(vrm))
            {
                var loaded = context.Load();
                loaded.EnableUpdateWhenOffscreen();
                loaded.ShowMeshes();
                Selection.activeGameObject = loaded.gameObject;
            }
        }
Пример #12
0
        public void MeshCopyTest()
        {
            var path = AliciaPath;
            var data = new GlbFileParser(path).Parse();

            using (var context = new VRMImporterContext(new VRMData(data)))
                using (var loaded = context.Load())
                {
                    loaded.ShowMeshes();
                    loaded.EnableUpdateWhenOffscreen();
                    foreach (var mesh in context.Meshes)
                    {
                        var src = mesh.Mesh;
                        var dst = src.Copy(true);
                        MeshTests.MeshEquals(src, dst);
                    }
                }
        }
Пример #13
0
        public static void ImportVrmAndCreatePrefab(string vrmPath, UnityPath prefabPath)
        {
            if (!prefabPath.IsUnderAssetsFolder)
            {
                Debug.LogWarningFormat("out of asset path: {0}", prefabPath);
                return;
            }

            /// <summary>
            /// これは EditorApplication.delayCall により呼び出される。
            ///
            /// * delayCall には UnityEngine.Object 持ち越すことができない
            /// * vrmPath のみを持ち越す
            ///
            /// </summary>
            /// <value></value>
            Action <IEnumerable <UnityPath> > onCompleted = texturePaths =>
            {
                var map = texturePaths
                          .Select(x => x.LoadAsset <Texture>())
                          .ToDictionary(x => new SubAssetKey(x), x => x as UnityEngine.Object);

                // 確実に Dispose するために敢えて再パースしている
                using (var data = new GlbFileParser(vrmPath).Parse())
                    using (var context = new VRMImporterContext(new VRMData(data), externalObjectMap: map))
                    {
                        var editor = new VRMEditorImporterContext(context, prefabPath);
                        foreach (var textureInfo in context.TextureDescriptorGenerator.Get().GetEnumerable())
                        {
                            VRMShaders.TextureImporterConfigurator.Configure(textureInfo, context.TextureFactory.ExternalTextures);
                        }
                        var loaded = context.Load();
                        editor.SaveAsAsset(loaded);
                    }
            };

            using (var data = new GlbFileParser(vrmPath).Parse())
                using (var context = new VRMImporterContext(new VRMData(data)))
                {
                    var editor = new VRMEditorImporterContext(context, prefabPath);
                    // extract texture images
                    editor.ConvertAndExtractImages(onCompleted);
                }
        }
Пример #14
0
        async Task <RuntimeGltfInstance> LoadAsync(string path)
        {
            var data = new GlbFileParser(path).Parse();

            if (!Vrm10Data.TryParseOrMigrate(data, true, out Vrm10Data vrm))
            {
                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);

                return(instance);
            }
        }
Пример #15
0
        public void EmptyThumbnailName()
        {
            using (var data = new GlbFileParser(TestAsset.AliciaPath).Parse())
                using (var migrated = Vrm10Data.Migrate(data, out var vrm1Data, out var migration))
                {
                    // Vrm10Data.ParseOrMigrate(TestAsset.AliciaPath, true, out Vrm10Data vrm, out MigrationData migration))
                    Assert.NotNull(vrm1Data);

                    var index = vrm1Data.VrmExtension.Meta.ThumbnailImage.Value;

                    // empty thumbnail name
                    vrm1Data.Data.GLTF.images[index].name = null;

                    using (var loader = new Vrm10Importer(vrm1Data))
                    {
                        loader.LoadAsync(new VRMShaders.ImmediateCaller()).Wait();
                    }
                }
        }
Пример #16
0
        public void Sample()
        {
            var path = "Tests/Models/Alicia_vrm-0.51/AliciaSolid_vrm-0.51.vrm";

            Debug.Log($"load: {path}");

            using (var data = new GlbFileParser(path).Parse())
                using (var migrated = Vrm10Data.Migrate(data, out Vrm10Data result, out MigrationData migration))
                {
                    Assert.NotNull(result);

                    var go = BuildGameObject(result, true);
                    Debug.Log(go);

                    // export
                    var vrmBytes = Vrm10Exporter.Export(go, new EditorTextureSerializer());

                    Debug.Log($"export {vrmBytes.Length} bytes");
                }
        }
Пример #17
0
        static void ImportAsset(string path, UnityPath prefabPath)
        {
            if (!prefabPath.IsUnderAssetsFolder)
            {
                Debug.LogWarningFormat("out of asset path: {0}", prefabPath);
                return;
            }

            // import as asset
            var data = new GlbFileParser(path).Parse();
            var vrm  = new VRMData(data);

            Action <IEnumerable <UnityPath> > onCompleted = texturePaths =>
            {
                //
                // after textures imported
                //
                var map = texturePaths
                          .Select(x => x.LoadAsset <Texture2D>())
                          .Where(x => x != null)
                          .ToDictionary(x => new SubAssetKey(x), x => x as Object);

                using (var context = new VRMImporterContext(vrm, externalObjectMap: map))
                {
                    var editor = new VRMEditorImporterContext(context, prefabPath);
                    foreach (var textureInfo in editor.TextureDescriptorGenerator.Get().GetEnumerable())
                    {
                        VRMShaders.TextureImporterConfigurator.Configure(textureInfo, context.TextureFactory.ExternalTextures);
                    }
                    var loaded = context.Load();
                    editor.SaveAsAsset(loaded);
                }
            };

            using (var context = new VRMImporterContext(vrm))
            {
                var editor = new VRMEditorImporterContext(context, prefabPath);
                editor.ConvertAndExtractImages(onCompleted);
            }
        }
Пример #18
0
        async void LoadVRMClicked()
        {
#if UNITY_STANDALONE_WIN
            var path = FileDialogForWindows.FileDialog("open VRM", ".vrm");
#elif UNITY_EDITOR
            var path = UnityEditor.EditorUtility.OpenFilePanel("Open VRM", "", "vrm");
#else
            var path = Application.dataPath + "/default.vrm";
#endif
            if (string.IsNullOrEmpty(path))
            {
                return;
            }

            // GLB形式でJSONを取得しParseします
            var data = new GlbFileParser(path).Parse();
            // var data = new GlbBinaryParser(anyBinary).Parse();

            using (var context = new VRMImporterContext(data))
            {
                // metaを取得(todo: thumbnailテクスチャのロード)
                var meta = await context.ReadMetaAsync();

                Debug.LogFormat("meta: title:{0}", meta.Title);

                // ParseしたJSONをシーンオブジェクトに変換していく
                var loaded = default(RuntimeGltfInstance);
                if (m_loadAsync)
                {
                    loaded = await context.LoadAsync();
                }
                else
                {
                    loaded = context.Load();
                }

                OnLoaded(loaded);
            }
        }
Пример #19
0
        /// <summary>
        ///
        /// </summary>
        /// <param name="scriptedImporter"></param>
        /// <param name="context"></param>
        /// <param name="doMigrate">vrm0 だった場合に vrm1 化する</param>
        /// <param name="renderPipeline"></param>
        /// <param name="doNormalize">normalize する</param>
        public static void Import(ScriptedImporter scriptedImporter, AssetImportContext context, bool doMigrate, RenderPipelineTypes renderPipeline, bool doNormalize)
        {
#if VRM_DEVELOP
            Debug.Log("OnImportAsset to " + scriptedImporter.assetPath);
#endif

            // 1st parse as vrm1
            using (var data = new GlbFileParser(scriptedImporter.assetPath).Parse())
            {
                var vrm1Data = Vrm10Data.Parse(data);
                if (vrm1Data != null)
                {
                    // successfully parsed vrm-1.0
                    Process(vrm1Data, scriptedImporter, context, renderPipeline, doNormalize);
                }

                if (!doMigrate)
                {
                    return;
                }

                // try migration...
                MigrationData migration;
                using (var migrated = Vrm10Data.Migrate(data, out vrm1Data, out migration))
                {
                    if (vrm1Data != null)
                    {
                        Process(vrm1Data, scriptedImporter, context, renderPipeline, doNormalize);
                    }
                }

                // fail to migrate...
                if (migration != null)
                {
                    Debug.LogWarning(migration.Message);
                }
                return;
            }
        }
        static void ImportVrm(UnityPath vrmPath)
        {
            if (!vrmPath.IsUnderAssetsFolder)
            {
                throw new Exception();
            }

            var data = new GlbFileParser(vrmPath.FullPath).Parse();
            var vrm  = new VRMData(data);

            var prefabPath = vrmPath.Parent.Child(vrmPath.FileNameWithoutExtension + ".prefab");

            Action <IEnumerable <UnityPath> > onCompleted = texturePaths =>
            {
                var map = texturePaths
                          .Select(x => x.LoadAsset <Texture>())
                          .ToDictionary(x => new SubAssetKey(x), x => x as UnityEngine.Object);

                using (var context = new VRMImporterContext(vrm, externalObjectMap: map))
                {
                    var editor = new VRMEditorImporterContext(context, prefabPath);
                    foreach (var textureInfo in context.TextureDescriptorGenerator.Get().GetEnumerable())
                    {
                        VRMShaders.TextureImporterConfigurator.Configure(textureInfo, context.TextureFactory.ExternalTextures);
                    }
                    var loaded = context.Load();
                    editor.SaveAsAsset(loaded);
                }
            };

            // extract texture images
            using (var context = new VRMImporterContext(vrm))
            {
                var editor = new VRMEditorImporterContext(context, prefabPath);
                editor.ConvertAndExtractImages(onCompleted);
            }
        }
Пример #21
0
        async void LoadModelAsync(string path)
        {
            if (!File.Exists(path))
            {
                return;
            }

            Debug.LogFormat("{0}", path);
            var ext = Path.GetExtension(path).ToLower();

            switch (ext)
            {
            case ".vrm":
            {
                var data = new GlbFileParser(path).Parse();

                using (var context = new VRMImporterContext(data))
                {
                    await m_texts.UpdateMetaAsync(context);

                    var loaded = await context.LoadAsync();

                    loaded.EnableUpdateWhenOffscreen();
                    loaded.ShowMeshes();
                    SetModel(loaded.gameObject);
                }
                break;
            }

            case ".glb":
            {
                var data = new GlbFileParser(path).Parse();

                var context = new UniGLTF.ImporterContext(data);
                var loaded  = context.Load();
                loaded.EnableUpdateWhenOffscreen();
                loaded.ShowMeshes();
                SetModel(loaded.gameObject);
                break;
            }

            case ".gltf":
            {
                var data = new GltfFileWithResourceFilesParser(path).Parse();

                var context = new UniGLTF.ImporterContext(data);
                var loaded  = context.Load();
                loaded.EnableUpdateWhenOffscreen();
                loaded.ShowMeshes();
                SetModel(loaded.gameObject);
                break;
            }

            case ".zip":
            {
                var data = new ZipArchivedGltfFileParser(path).Parse();

                var context = new UniGLTF.ImporterContext(data);
                var loaded  = context.Load();
                loaded.EnableUpdateWhenOffscreen();
                loaded.ShowMeshes();
                SetModel(loaded.gameObject);
                break;
            }

            default:
                Debug.LogWarningFormat("unknown file type: {0}", path);
                break;
            }
        }
Пример #22
0
    /// <summary>
    /// Unload the old model and load the new model from VRM file.
    /// </summary>
    /// <param name="path"></param>
    private void LoadModel(string path)
    {
        if (!File.Exists(path))
        {
            Debug.Log("Model " + path + " is not exits.");
            return;
        }

        GameObject newModelObject = null;

        try
        {
            // Load from a VRM file.
            var parser = new GlbFileParser(path);
            var data   = parser.Parse();

            context = new VRMImporterContext(data);
            //Debug.Log("Loading model : " + path);

            RuntimeGltfInstance instance = context.Load();
            instance.EnableUpdateWhenOffscreen();

            newModelObject = instance.Root;
            meta           = context.ReadMeta(true);

            instance.ShowMeshes();
        }
        catch (Exception ex)
        {
            if (uiController)
            {
                uiController.ShowWarning("Model load failed.");
            }
            Debug.LogError("Failed loading " + path);
            Debug.LogError(ex);
            return;
        }

        if (newModelObject)
        {
            if (model)
            {
                GameObject.Destroy(model.gameObject);
            }

            model = newModelObject.AddComponent <HumanPoseTransfer>();

            CreateColliders(model.gameObject);

            var characterController = model.gameObject.AddComponent <VrmCharacterBehaviour>();

            SetMotion(motion, model, meta);

            if (uiController)
            {
                uiController.Show(meta);

                if (characterController)
                {
                    uiController.enableRandomMotion  = characterController.randomMotion;
                    uiController.enableRandomEmotion = characterController.randomEmotion;
                }
            }
        }
    }
Пример #23
0
        void LoadModel(string path)
        {
            if (!File.Exists(path))
            {
                return;
            }

            Debug.LogFormat("{0}", path);
            var ext = Path.GetExtension(path).ToLower();

            switch (ext)
            {
            case ".vrm":
            {
                if (!Vrm10Parser.TryParseOrMigrate(path, doMigrate: true, out Vrm10Parser.Result result))
                {
                    Debug.LogError(result.Message);
                    return;
                }
                using (var loader = new Vrm10Importer(result.Data, result.Vrm))
                {
                    var loaded = loader.Load();
                    loaded.ShowMeshes();
                    loaded.EnableUpdateWhenOffscreen();
                    SetModel(loaded.gameObject);
                }
                break;
            }

            case ".glb":
            {
                var data = new GlbFileParser(path).Parse();

                using (var loader = new UniGLTF.ImporterContext(data))
                {
                    var loaded = loader.Load();
                    loaded.ShowMeshes();
                    loaded.EnableUpdateWhenOffscreen();
                    SetModel(loaded.gameObject);
                }
                break;
            }

            case ".gltf":
            {
                var data = new GltfFileWithResourceFilesParser(path).Parse();

                using (var loader = new UniGLTF.ImporterContext(data))
                {
                    var loaded = loader.Load();
                    loaded.ShowMeshes();
                    loaded.EnableUpdateWhenOffscreen();
                    SetModel(loaded.gameObject);
                }
                break;
            }

            case ".zip":
            {
                var data = new ZipArchivedGltfFileParser(path).Parse();

                using (var loader = new UniGLTF.ImporterContext(data))
                {
                    var loaded = loader.Load();
                    loaded.ShowMeshes();
                    loaded.EnableUpdateWhenOffscreen();
                    SetModel(loaded.gameObject);
                }
                break;
            }

            default:
                Debug.LogWarningFormat("unknown file type: {0}", path);
                break;
            }
        }
Пример #24
0
        public void ImportExportTest()
        {
            var path = AliciaPath;
            var data = new GlbFileParser(path).Parse();

            using (var context = new VRMImporterContext(new VRMData(data)))
                using (var loaded = context.Load())
                {
                    loaded.ShowMeshes();
                    loaded.EnableUpdateWhenOffscreen();

                    // mesh
                    {
                        foreach (var renderer in loaded.GetComponentsInChildren <Renderer>())
                        {
                            Mesh mesh = default;
                            if (renderer is MeshRenderer)
                            {
                                var f = renderer.GetComponent <MeshFilter>();
                                mesh = f.sharedMesh;
                            }
                            else if (renderer is SkinnedMeshRenderer smr)
                            {
                                mesh = smr.sharedMesh;
                            }

                            var gltfMesh = data.GLTF.meshes.Find(x => x.name == mesh.name);
                            Assert.AreEqual(gltfMesh.name, mesh.name);

                            // materials
                            foreach (var material in renderer.sharedMaterials)
                            {
                                var gltfMaterial = data.GLTF.materials.Find(x => x.name == material.name);
                                Assert.AreEqual(gltfMaterial.name, material.name);

                                var materialIndex = data.GLTF.materials.IndexOf(gltfMaterial);
                                var vrmMaterial   = context.VRM.materialProperties[materialIndex];
                                // Debug.Log($"shaderName: '{vrmMaterial.shader}'");
                                if (vrmMaterial.shader == "VRM/MToon")
                                {
                                    // MToon
                                    // Debug.Log($"{material.name} is MToon");
                                    foreach (var kv in vrmMaterial.textureProperties)
                                    {
                                        var texture = material.GetTexture(kv.Key);
                                        // Debug.Log($"{kv.Key}: {texture}");
                                        Assert.NotNull(texture);
                                    }
                                }
                                else if (glTF_KHR_materials_unlit.IsEnable(gltfMaterial))
                                {
                                    // Unlit
                                    // Debug.Log($"{material.name} is unlit");
                                    throw new NotImplementedException();
                                }
                                else
                                {
                                    // PBR
                                    // Debug.Log($"{material.name} is PBR");
                                    throw new NotImplementedException();
                                }
                            }
                        }
                    }

                    // meta
                    {
                        var meta = loaded.GetComponent <VRMMeta>();
                    }

                    // humanoid
                    {
                        var animator = loaded.GetComponent <Animator>();
                    }


                    // blendshape
                    {
                        var blendshapeProxy = loaded.GetComponent <VRMBlendShapeProxy>();
                        for (int i = 0; i < context.VRM.blendShapeMaster.blendShapeGroups.Count; ++i)
                        {
                            var gltfBlendShapeClip  = context.VRM.blendShapeMaster.blendShapeGroups[i];
                            var unityBlendShapeClip = blendshapeProxy.BlendShapeAvatar.Clips[i];
                            Assert.AreEqual(Enum.Parse(typeof(BlendShapePreset), gltfBlendShapeClip.presetName, true), unityBlendShapeClip.Preset);
                        }
                    }

                    var importedJson = JsonParser.Parse(context.Json);
                    importedJson.SetValue("/extensions/VRM/exporterVersion", VRMVersion.VRM_VERSION, (f, x) => f.Value(x));
                    importedJson.SetValue("/asset/generator", UniGLTF.UniGLTFVersion.UNIGLTF_VERSION, (f, x) => f.Value(x));
                    importedJson.SetValue("/scene", 0, (f, x) => f.Value(x));
                    importedJson.SetValue("/materials/*/doubleSided", false, (f, x) => f.Value(x));
                    //importJson.SetValue("/materials/*/pbrMetallicRoughness/roughnessFactor", 0);
                    //importJson.SetValue("/materials/*/pbrMetallicRoughness/baseColorFactor", new float[] { 1, 1, 1, 1 });
                    importedJson.SetValue("/accessors/*/normalized", false, (f, x) => f.Value(x));
                    importedJson.RemoveValue(Utf8String.From("/nodes/*/extras"));

                    /*
                     * importJson.SetValue("/bufferViews/12/byteStride", 4);
                     * importJson.SetValue("/bufferViews/13/byteStride", 4);
                     * importJson.SetValue("/bufferViews/14/byteStride", 4);
                     * importJson.SetValue("/bufferViews/15/byteStride", 4);
                     * importJson.SetValue("/bufferViews/22/byteStride", 4);
                     * importJson.SetValue("/bufferViews/29/byteStride", 4);
                     * importJson.SetValue("/bufferViews/45/byteStride", 4);
                     * importJson.SetValue("/bufferViews/46/byteStride", 4);
                     * importJson.SetValue("/bufferViews/47/byteStride", 4);
                     * importJson.SetValue("/bufferViews/201/byteStride", 4);
                     * importJson.SetValue("/bufferViews/202/byteStride", 4);
                     * importJson.SetValue("/bufferViews/203/byteStride", 4);
                     * importJson.SetValue("/bufferViews/204/byteStride", 4);
                     * importJson.SetValue("/bufferViews/211/byteStride", 4);
                     * importJson.SetValue("/bufferViews/212/byteStride", 4);
                     * importJson.SetValue("/bufferViews/213/byteStride", 4);
                     * importJson.SetValue("/bufferViews/214/byteStride", 4);
                     * importJson.SetValue("/bufferViews/215/byteStride", 4);
                     * importJson.SetValue("/bufferViews/243/byteStride", 4);
                     * importJson.SetValue("/bufferViews/247/byteStride", 64);
                     * importJson.SetValue("/bufferViews/248/byteStride", 64);
                     * importJson.SetValue("/bufferViews/249/byteStride", 64);
                     * importJson.SetValue("/bufferViews/250/byteStride", 64);
                     * importJson.SetValue("/bufferViews/251/byteStride", 64);
                     * importJson.SetValue("/bufferViews/252/byteStride", 64);
                     * importJson.SetValue("/bufferViews/253/byteStride", 64);
                     */
                    importedJson.RemoveValue(Utf8String.From("/bufferViews/*/byteStride"));

                    var vrm = VRMExporter.Export(new GltfExportSettings(), loaded.gameObject, new EditorTextureSerializer());

                    // TODO: Check contents in JSON
                    /*var exportJson = */
                    JsonParser.Parse(vrm.GLTF.ToJson());

                    // TODO: Check contents in JSON
                    /*var newExportedJson = */
                    // JsonParser.Parse(JsonSchema.FromType<glTF>().Serialize(vrm));

                    /*
                     * foreach (var kv in importJson.Diff(exportJson))
                     * {
                     *  Debug.Log(kv);
                     * }
                     *
                     * Assert.AreEqual(importJson, exportJson);
                     */
                }
        }