/// <summary>
        /// 同期でByte配列からVRMモデルを読み込む
        /// </summary>
        /// <param name="vrmByteArray"></param>
        /// <returns></returns>
        public GameObject LoadVrmModelFromByteArray(byte[] vrmByteArray)
        {
#if UNIVRM_LEGACY_IMPORTER
            InitializeVrmContextFromByteArray(vrmByteArray);

            // 同期処理で読み込みます
            currentContext.Load();

            // 読込が完了するとcontext.RootにモデルのGameObjectが入っています
            var root = currentContext.Root;

            return(root);
#elif UNIVRM_0_68_IMPORTER
            var parser = new GltfParser();
            parser.ParseGlb(vrmByteArray);

            currentContext = new VRMImporterContext(parser);
            currentContext.Load();

            return(currentContext.Root);
#elif UNIVRM_0_77_IMPORTER
            var parser = new GlbLowLevelParser(string.Empty, vrmByteArray);
            var data   = parser.Parse();

            currentContext  = new VRMImporterContext(data);
            currentInstance = currentContext.Load();

            return(currentInstance.Root);
#else
            return(null);
#endif
        }
Example #2
0
        VrmLib.Model ReadModel(string path)
        {
            var bytes = MigrationVrm.Migrate(File.ReadAllBytes(path));

            var data = new GlbLowLevelParser(path, bytes).Parse();

            var model = ModelReader.Read(data);

            return(model);
        }
Example #3
0
        static GameObject Load(byte[] bytes, string path)
        {
            var data = new GlbLowLevelParser(path, bytes).Parse();

            using (var loader = new VRMImporterContext(data))
            {
                var loaded = loader.Load();
                loaded.ShowMeshes();
                return(loaded.gameObject);
            }
        }
Example #4
0
        public void MaterialImporterTest()
        {
            var migratedBytes = MigrationVrm.Migrate(File.ReadAllBytes(AliciaPath));
            var data          = new GlbLowLevelParser(AliciaPath, migratedBytes).Parse();

            var matDesc = new Vrm10MaterialDescriptorGenerator().Get(data, 0);

            Assert.AreEqual("Alicia_body", matDesc.Name);
            Assert.AreEqual("Hidden/VRM10/vrmc_materials_mtoon", matDesc.ShaderName);
            Assert.AreEqual("Alicia_body", matDesc.TextureSlots["_MainTex"].UnityObjectName);
            Assert.AreEqual("Alicia_body", matDesc.TextureSlots["_ShadeTex"].UnityObjectName);

            AreColorEqualApproximately(new Color(1, 1, 1, 1), matDesc.Colors["_Color"]);
            ColorUtility.TryParseHtmlString("#FFDDD6", out var shadeColor);
            AreColorEqualApproximately(shadeColor, matDesc.Colors["_ShadeColor"]);

            Assert.AreEqual(1.0f - 0.1f, matDesc.FloatValues["_GiEqualization"]);

            var(key, value) = matDesc.EnumerateSubAssetKeyValue().First();
            Assert.AreEqual(new SubAssetKey(typeof(Texture2D), "Alicia_body"), key);
        }
        /// <summary>
        /// 非同期でByte配列からVRMモデルを読み込む
        /// </summary>
        /// <param name="vrmByteArray"></param>
        /// <returns></returns>
        public async Task <GameObject> LoadVrmModelFromByteArrayAsync(byte[] vrmByteArray)
        {
#if UNIVRM_LEGACY_IMPORTER
            await InitializeVrmContextFromByteArrayAsync(vrmByteArray);

            // 非同期処理(Task)で読み込みます
            await currentContext.LoadAsyncTask();

            // 読込が完了するとcontext.RootにモデルのGameObjectが入っています
            var root = currentContext.Root;

            return(root);
#elif UNIVRM_0_68_IMPORTER
            var parser = new GltfParser();
            await Task.Run(() =>
            {
                parser.ParseGlb(vrmByteArray);
            });

            currentContext = new VRMImporterContext(parser);
            await currentContext.LoadAsync();

            return(currentContext.Root);
#elif UNIVRM_0_77_IMPORTER
            var      parser = new GlbLowLevelParser(string.Empty, vrmByteArray);
            GltfData data   = null;

            await Task.Run(() =>
            {
                data = parser.Parse();
            });

            currentContext  = new VRMImporterContext(data);
            currentInstance = await currentContext.LoadAsync();

            return(currentInstance.Root);
#else
            return(null);
#endif
        }
Example #6
0
        /// <summary>
        /// VRM-1 の thumbnail テクスチャー。gltf.textures ではなく gltf.images の参照であることに注意(sampler等の設定が無い)
        /// </summary>
        public static bool TryGetMetaThumbnailTextureImportParam(GltfData data, UniGLTF.Extensions.VRMC_vrm.VRMC_vrm vrm, out (SubAssetKey, TextureDescriptor) value)
        {
            if (vrm?.Meta?.ThumbnailImage == null)
            {
                value = default;
                return(false);
            }
            var thumbnailImage = vrm.Meta.ThumbnailImage;

            if (!thumbnailImage.HasValue)
            {
                value = default;
                return(false);
            }
            var imageIndex = thumbnailImage.Value;

            if (imageIndex < 0 || imageIndex >= data.GLTF.images.Count)
            {
                value = default;
                return(false);
            }

            var gltfImage = data.GLTF.images[imageIndex];

            // data.GLTF.textures は前処理によりユニーク性がある
            // unique な名前を振り出す
            var used      = new HashSet <string>(data.GLTF.textures.Select(x => x.name));
            var imageName = gltfImage.name;

            if (string.IsNullOrEmpty(imageName))
            {
                imageName = THUMBNAIL_NAME;
            }
            var uniqueName = GlbLowLevelParser.FixNameUnique(used, imageName);

            value = GltfTextureImporter.CreateSrgbFromOnlyImage(data, imageIndex, uniqueName, gltfImage.uri);
            return(true);
        }
Example #7
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 (data)
                    using (var importer = new VRMImporterContext(new VRMData(data)))
                    {
                        return(importer.Load().gameObject);
                    }
            }
            catch (Exception ex)
            {
                Message(gltf.FullName.Substring(root.FullName.Length), ex);
                return(null);
            }
        }
Example #8
0
        /// <summary>
        /// vrm1 をパースする。vrm0 からのマイグレートもできる。
        /// </summary>
        /// <param name="path"></param>
        /// <param name="bytes"></param>
        /// <param name="doMigrate"></param>
        /// <param name="vrm1Data">成功した場合非 null</param>
        /// <param name="migration">doMigrate==true の場合、関連情報が入る</param>
        /// <returns>GltfDataを作成できたときは Return するのでDisposeすること</returns>
        public static GltfData ParseOrMigrate(string path, byte[] bytes, bool doMigrate, out Vrm10Data vrm1Data, out MigrationData migration)
        {
            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
                    vrm1Data  = new Vrm10Data(data, vrm);
                    migration = default;
                    return(data);
                }

                if (!doMigrate)
                {
                    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)
                {
                    vrm1Data  = default;
                    migration = new MigrationData("Found vrm0. But fail to migrate", oldMeta);
                    return(data);
                }

                if (VRMShaders.Symbols.VRM_DEVELOP)
                {
                    // load 時の右手左手座標変換でバッファが破壊的変更されるので、コピーを作っている
                    migratedBytes = migrated.Select(x => x).ToArray();
                }
            }
            catch (Exception ex)
            {
                // 何か起きた。Dispose は頼む
                vrm1Data  = default;
                migration = new MigrationData(ex.Message);
                return(data);
            }

            // マイグレーション前を破棄
            data.Dispose();
            // マイグレーション結果をパースする
            var migratedData = new GlbLowLevelParser(data.TargetPath, migrated).Parse();

            try
            {
                if (!UniGLTF.Extensions.VRMC_vrm.GltfDeserializer.TryGet(migratedData.GLTF.extensions, out VRMC_vrm vrm))
                {
                    // migration した結果のパースに失敗した !
                    vrm1Data  = default;
                    migration = new MigrationData("vrm0: migrate but error ?", oldMeta, migrated);
                    return(migratedData);
                }

                {
                    // 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);
            }
        }
Example #9
0
        private static async Task <Vrm10Instance> LoadAsync(
            string name,
            byte[] bytes,
            bool canLoadVrm0X,
            bool normalizeTransform,
            bool showMeshes,
            IAwaitCaller awaitCaller,
            IMaterialDescriptorGenerator materialGenerator,
            VrmMetaInformationCallback vrmMetaInformationCallback,
            CancellationToken ct)
        {
            ct.ThrowIfCancellationRequested();
            if (awaitCaller == null)
            {
                throw new ArgumentNullException();
            }

            using (var gltfData = new GlbLowLevelParser(name, bytes).Parse())
            {
                // 1. Try loading as vrm-1.0
                var instance = await TryLoadingAsVrm10Async(
                    gltfData,
                    normalizeTransform,
                    showMeshes,
                    awaitCaller,
                    materialGenerator,
                    vrmMetaInformationCallback,
                    ct);

                if (instance != null)
                {
                    if (ct.IsCancellationRequested)
                    {
                        UnityObjectDestoyer.DestroyRuntimeOrEditor(instance.gameObject);
                        ct.ThrowIfCancellationRequested();
                    }
                    return(instance);
                }

                // 2. Stop loading if not allowed migration.
                if (!canLoadVrm0X)
                {
                    throw new Exception($"Failed to load as VRM 1.0: {name}");
                }

                // 3. Try migration from vrm-0.x into vrm-1.0
                var migratedInstance = await TryMigratingFromVrm0XAsync(
                    gltfData,
                    normalizeTransform,
                    showMeshes,
                    awaitCaller,
                    materialGenerator,
                    vrmMetaInformationCallback,
                    ct);

                if (migratedInstance != null)
                {
                    if (ct.IsCancellationRequested)
                    {
                        UnityObjectDestoyer.DestroyRuntimeOrEditor(migratedInstance.gameObject);
                        ct.ThrowIfCancellationRequested();
                    }
                    return(migratedInstance);
                }

                // 4. Failed loading.
                throw new Exception($"Failed to load: {name}");
            }
        }
Example #10
0
        /// <summary>
        ///
        /// </summary>
        /// <param name="data"></param>
        /// <param name="vrm1Data"></param>
        /// <param name="migration"></param>
        /// <returns>Migrated GltfData if succeeded. Must Dispose</returns>
        public static GltfData Migrate(GltfData data, out Vrm10Data vrm1Data, out MigrationData migration)
        {
            var json = data.Json.ParseAsJson();

            if (!json.TryGet("extensions", out JsonNode extensions))
            {
                vrm1Data  = default;
                migration = new MigrationData("gltf: no extensions");
                return(null);
            }

            if (!extensions.TryGet("VRM", out JsonNode vrm0))
            {
                vrm1Data  = default;
                migration = new MigrationData("gltf: no vrm0");
                return(null);
            }

            // found vrm0
            var oldMeta = Migration.Vrm0Meta.FromJsonBytes(json);

            if (oldMeta == null)
            {
                throw new NullReferenceException("oldMeta");
            }

            // try migrate...
            byte[] migrated = null;
            try
            {
                migrated = MigrationVrm.Migrate(data);
                if (migrated == null)
                {
                    vrm1Data  = default;
                    migration = new MigrationData("Found vrm0. But fail to migrate", oldMeta);
                    return(null);
                }
            }
            catch (MigrationException ex)
            {
                // migration 失敗
                vrm1Data  = default;
                migration = new MigrationData(ex.ToString(), oldMeta);
                return(null);
            }
            catch (Exception ex)
            {
                // その他のエラー
                vrm1Data  = default;
                migration = new MigrationData(ex.ToString(), oldMeta);
                return(null);
            }

            byte[] debugCopy = null;
            if (VRMShaders.Symbols.VRM_DEVELOP)
            {
                // load 時の右手左手座標変換でバッファが破壊的変更されるので、コピーを作っている
                debugCopy = migrated.Select(x => x).ToArray();
            }

            // マイグレーション結果をパースする
            var migratedData = new GlbLowLevelParser(data.TargetPath, migrated).Parse();

            try
            {
                if (!UniGLTF.Extensions.VRMC_vrm.GltfDeserializer.TryGet(migratedData.GLTF.extensions, out VRMC_vrm vrm))
                {
                    // migration した結果のパースに失敗した !
                    vrm1Data  = default;
                    migration = new MigrationData("vrm0: migrate but error ?", oldMeta, migrated);
                    // 破棄
                    migratedData.Dispose();
                    return(null);
                }

                {
                    // success. 非null値が返るのはここだけ。
                    vrm1Data  = new Vrm10Data(migratedData, vrm);
                    migration = new MigrationData("vrm0: migrated", oldMeta, debugCopy);
                    return(migratedData);
                }
            }
            catch (Exception ex)
            {
                Debug.LogWarning(ex);
                vrm1Data  = default;
                migration = new MigrationData(ex.Message);
                // 破棄
                migratedData.Dispose();
                return(null);
            }
        }