public static bool TryGetTextureFromMaterialProperty(GltfData data, glTF_VRM_Material vrmMaterial, string textureKey, out (SubAssetKey, TextureDescriptor) texture) { // 任意の shader の import を許容する if (/*vrmMaterial.shader == MToon.Utils.ShaderName &&*/ vrmMaterial.textureProperties.TryGetValue(textureKey, out var textureIdx)) { var(offset, scale) = (new Vector2(0, 0), new Vector2(1, 1)); if (TryGetTextureOffsetAndScale(vrmMaterial, textureKey, out var os)) { offset = os.offset; scale = os.scale; } switch (textureKey) { case MToon.Utils.PropBumpMap: texture = GltfTextureImporter.CreateNormal(data, textureIdx, offset, scale); break; default: texture = GltfTextureImporter.CreateSrgb(data, textureIdx, offset, scale); break; } return(true); } texture = default; return(false); }
public MaterialDescriptor Get(GltfData data, int i) { // mtoon URP "MToon" shader is not ready. import fallback to unlit // unlit "UniUnlit" work in URP if (GltfUnlitMaterialImporter.TryCreateParam(data, i, out var matDesc)) { return(matDesc); } // pbr "Standard" to "Universal Render Pipeline/Lit" if (GltfPbrUrpMaterialImporter.TryCreateParam(data, i, out matDesc)) { return(matDesc); } // fallback #if VRM_DEVELOP Debug.LogWarning($"material: {i} out of range. fallback"); #endif return(new MaterialDescriptor( GltfMaterialDescriptorGenerator.GetMaterialName(i, null), GltfPbrMaterialImporter.ShaderName, null, new Dictionary <string, TextureDescriptor>(), new Dictionary <string, float>(), new Dictionary <string, Color>(), new Dictionary <string, Vector4>(), new Action <Material>[] {})); }
public static SkinningInfo Create(GltfData data, glTFMesh mesh, glTFPrimitives primitives) { var hasMorphTarget = HasMorphTarget(mesh); var positions = data.GLTF.accessors[primitives.attributes.POSITION]; var skinning = new SkinningInfo { Joints = primitives.GetJoints(data, positions.count), Weights = primitives.GetWeights(data, positions.count), }; if (skinning.Joints != null) { // use SkinnedMeshRenderer return(skinning); } else if (!hasMorphTarget) { // use MeshRenderer return(skinning); } else { // use SkinnedMeshRenderer without boneWeight. // https://github.com/vrm-c/UniVRM/issues/1675 return(new SkinningInfo { ShouldSetRendererNodeAsBone = true, Joints = _ => (0, 0, 0, 0), Weights = _ => (1, 0, 0, 0), // assign weight 1 });
public MaterialDescriptor Get(GltfData data, int i) { // mtoon if (Vrm10MToonMaterialImporter.TryCreateParam(data, i, out MaterialDescriptor matDesc)) { return(matDesc); } // unlit if (GltfUnlitMaterialImporter.TryCreateParam(data, i, out matDesc)) { return(matDesc); } // pbr if (GltfPbrMaterialImporter.TryCreateParam(data, i, out matDesc)) { return(matDesc); } // fallback #if VRM_DEVELOP Debug.LogWarning($"material: {i} out of range. fallback"); #endif return(new MaterialDescriptor( GltfMaterialDescriptorGenerator.GetMaterialName(i, null), GltfPbrMaterialImporter.ShaderName, null, new Dictionary <string, TextureDescriptor>(), new Dictionary <string, float>(), new Dictionary <string, Color>(), new Dictionary <string, Vector4>(), new Action <Material>[] {})); }
/// <summary> /// VMRC_materials_mtoon の場合にマテリアル生成情報を作成する /// </summary> public static bool TryCreateParam(GltfData data, int i, out MaterialDescriptor matDesc) { var m = data.GLTF.materials[i]; if (!UniGLTF.Extensions.VRMC_materials_mtoon.GltfDeserializer.TryGet(m.extensions, out UniGLTF.Extensions.VRMC_materials_mtoon.VRMC_materials_mtoon mtoon)) { // Fallback to glTF, when MToon extension does not exist. matDesc = default; return(false); } // use material.name, because material name may renamed in GltfParser. matDesc = new MaterialDescriptor( m.name, MToon10Meta.UnityShaderName, null, Vrm10MToonTextureImporter.EnumerateAllTextures(data, m, mtoon).ToDictionary(tuple => tuple.key, tuple => tuple.Item2.Item2), TryGetAllFloats(m, mtoon).ToDictionary(tuple => tuple.key, tuple => tuple.value), TryGetAllColors(m, mtoon).ToDictionary(tuple => tuple.key, tuple => tuple.value), TryGetAllFloatArrays(m, mtoon).ToDictionary(tuple => tuple.key, tuple => tuple.value), new Action <Material>[] { material => { // Set hidden properties, keywords from float properties. new MToonValidator(material).Validate(); } }); return(true); }
/// <summary> /// /// * VRM10Object /// * VRM10Expression[] /// /// が Extract 対象となる /// /// </summary> public static void Extract(ScriptedImporter importer, GltfData data) { if (string.IsNullOrEmpty(importer.assetPath)) { return; } var path = GetAndCreateFolder(importer.assetPath, ".vrm1.Assets"); // expression を extract し置き換え map を作る var map = new Dictionary <VRM10Expression, VRM10Expression>(); foreach (var asset in AssetDatabase.LoadAllAssetsAtPath(importer.assetPath)) { if (asset is VRM10Expression expression) { var clone = ExtractSubAsset(asset, $"{path}/{asset.name}.asset", false); map.Add(expression, clone as VRM10Expression); } } // vrmObject の expression を置き換える var vrmObject = AssetDatabase.LoadAllAssetsAtPath(importer.assetPath).First(x => x is VRM10Object) as VRM10Object; vrmObject.Expression.Replace(map); // extract ExtractSubAsset(vrmObject, $"{path}/{vrmObject.name}.asset", false); AssetDatabase.ImportAsset(importer.assetPath, ImportAssetOptions.ForceUpdate); }
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); } }
static void ReverseVector3Array(GltfData data, int accessorIndex, HashSet <int> used) { if (accessorIndex == -1) { return; } if (!used.Add(accessorIndex)) { return; } var accessor = data.GLTF.accessors[accessorIndex]; var bufferViewIndex = -1; if (accessor.bufferView != -1) { bufferViewIndex = accessor.bufferView; } else if (accessor.sparse?.values != null && accessor.sparse.values.bufferView != -1) { bufferViewIndex = accessor.sparse.values.bufferView; } if (bufferViewIndex != -1) { var buffer = data.GetBytesFromBufferView(bufferViewIndex); var span = buffer.Reinterpret <UnityEngine.Vector3>(1); for (int i = 0; i < span.Length; ++i) { span[i] = span[i].RotateY180(); } } }
/// <summary> /// 非同期でByte配列からVRMImporterContextの初期化をします /// </summary> /// <param name="vrmByteArray"></param> public async Task InitializeVrmContextFromByteArrayAsync(byte[] vrmByteArray) { #if UNIVRM_LEGACY_IMPORTER // VRMImporterContextがVRMを読み込む機能を提供します currentContext = new VRMImporterContext(); // GLB形式でJSONを取得しParseします await Task.Run(() => currentContext.ParseGlb(vrmByteArray)); #elif UNIVRM_0_68_IMPORTER var parser = new GltfParser(); await Task.Run(() => parser.ParseGlb(vrmByteArray)); currentContext = new VRMImporterContext(parser); #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 = null; #else #endif }
public void TextureEnumerationInUnknownShader() { using (var data = GltfData.CreateFromGltfDataForTest( new glTF { images = new List <glTFImage> { new glTFImage { mimeType = "image/png", } }, textures = new List <glTFTexture> { new glTFTexture { name = "texture0", source = 0, } }, materials = new List <glTFMaterial> { new glTFMaterial { pbrMetallicRoughness = new glTFPbrMetallicRoughness { baseColorTexture = new glTFMaterialBaseColorTextureInfo { index = 0, } } }, } }, default )) { var vrm = new glTF_VRM_extensions { materialProperties = new List <glTF_VRM_Material> { new glTF_VRM_Material { shader = "UnknownShader", textureProperties = new Dictionary <string, int> { { "_MainTex", 0 }, } }, } }; // 2系統ある? Assert.IsTrue(VRMMToonMaterialImporter.TryCreateParam(data, vrm, 0, out VRMShaders.MaterialDescriptor matDesc)); Assert.AreEqual(1, matDesc.TextureSlots.Count); var items = new VrmTextureDescriptorGenerator(data, vrm).Get().GetEnumerable().ToArray(); Assert.AreEqual(1, items.Length); } }
public Result(GltfData data, VRMC_vrm vrm, Vrm10FileType fileType, string message) { Data = data; Vrm = vrm; FileType = fileType; Message = message; }
private static async Task <Vrm10Instance> TryLoadingAsVrm10Async( GltfData gltfData, bool normalizeTransform, bool showMeshes, IAwaitCaller awaitCaller, IMaterialDescriptorGenerator materialGenerator, VrmMetaInformationCallback vrmMetaInformationCallback, CancellationToken ct) { ct.ThrowIfCancellationRequested(); if (awaitCaller == null) { throw new ArgumentNullException(); } var vrm10Data = await awaitCaller.Run(() => Vrm10Data.Parse(gltfData)); ct.ThrowIfCancellationRequested(); if (vrm10Data == null) { // NOTE: Failed to parse as VRM 1.0. return(null); } return(await LoadVrm10DataAsync( vrm10Data, null, normalizeTransform, showMeshes, awaitCaller, materialGenerator, vrmMetaInformationCallback, ct)); }
/// <summary> /// VRM-1.0 拡張を取得する。 /// </summary> /// <param name="data"></param> /// <returns>失敗したら null が返る</returns> public static Vrm10Data Parse(GltfData data) { if (!UniGLTF.Extensions.VRMC_vrm.GltfDeserializer.TryGet(data.GLTF.extensions, out var vrm)) { return(null); } return(new Vrm10Data(data, vrm)); }
public VRMData(GltfData data) { Data = data; if (!glTF_VRM_extensions.TryDeserialize(data.GLTF.extensions, out VRM.glTF_VRM_extensions vrm)) { throw new NotVrm0Exception(); } VrmExtension = vrm; }
private static bool TryGetThumbnailTexture(GltfData data, glTF_VRM_extensions vrm, out (SubAssetKey, TextureDescriptor) texture) { if (vrm.meta.texture > -1) { texture = GltfTextureImporter.CreateSRGB(data, vrm.meta.texture, Vector2.zero, Vector2.one); return(true); } texture = default; return(false); }
public static byte[] Migrate(GltfData data) { // VRM0 -> Unity var model = ModelReader.Read(data, VrmLib.Coordinates.Vrm0); // Unity -> VRM1 VrmLib.ModelExtensionsForCoordinates.ConvertCoordinate(model, VrmLib.Coordinates.Vrm1); var(gltf, bin) = new MeshUpdater(data).Update(model); gltf.extensions = null; return(MigrateVrm(gltf, bin, data.Json.ParseAsJson()["extensions"]["VRM"])); }
GameObject BuildGameObject(GltfData data, VRMC_vrm vrm, bool showMesh) { using (var loader = new Vrm10Importer(data, vrm)) { var loaded = loader.Load(); if (showMesh) { loaded.ShowMeshes(); } loaded.EnableUpdateWhenOffscreen(); return(loaded.gameObject); } }
private static bool TryGetNormalTexture(GltfData data, glTFMaterial src, out (SubAssetKey, TextureDescriptor) pair) { try { pair = GltfPbrTextureImporter.NormalTexture(data, src); return(true); } catch (NullReferenceException) { pair = default; return(false); } catch (ArgumentOutOfRangeException) { pair = default; return(false); } }
public VRMImporterContext( GltfData data, IReadOnlyDictionary <SubAssetKey, Object> externalObjectMap = null, ITextureDeserializer textureDeserializer = null) : base(data, externalObjectMap, textureDeserializer) { // parse VRM part if (glTF_VRM_extensions.TryDeserialize(GLTF.extensions, out glTF_VRM_extensions vrm)) { VRM = vrm; TextureDescriptorGenerator = new VrmTextureDescriptorGenerator(Data, VRM); MaterialDescriptorGenerator = new VRMMaterialDescriptorGenerator(VRM); } else { throw new NotVrm0Exception(); } }
/// <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 imageIndex = vrm.Meta.ThumbnailImage.Value; var gltfImage = data.GLTF.images[imageIndex]; var name = TextureImportName.GetUnityObjectName(TextureImportTypes.sRGB, gltfImage.name, gltfImage.uri); GetTextureBytesAsync getThumbnailImageBytesAsync = () => { var bytes = data.GLTF.GetImageBytes(data.Storage, imageIndex); return(Task.FromResult(GltfTextureImporter.ToArray(bytes))); }; var texDesc = new TextureDescriptor(name, gltfImage.GetExt(), gltfImage.uri, Vector2.zero, Vector2.one, default, TextureImportTypes.sRGB, default, default,
private static async Task <Vrm10Instance> TryMigratingFromVrm0XAsync( GltfData gltfData, bool normalizeTransform, bool showMeshes, IAwaitCaller awaitCaller, IMaterialDescriptorGenerator materialGenerator, VrmMetaInformationCallback vrmMetaInformationCallback, CancellationToken ct) { ct.ThrowIfCancellationRequested(); if (awaitCaller == null) { throw new ArgumentNullException(); } Vrm10Data migratedVrm10Data = default; MigrationData migrationData = default; using (var migratedGltfData = await awaitCaller.Run(() => Vrm10Data.Migrate(gltfData, out migratedVrm10Data, out migrationData))) { ct.ThrowIfCancellationRequested(); if (migratedVrm10Data == null) { throw new Exception(migrationData?.Message ?? "Failed to migrate."); } var migratedVrm10Instance = await LoadVrm10DataAsync( migratedVrm10Data, migrationData, normalizeTransform, showMeshes, awaitCaller, materialGenerator, vrmMetaInformationCallback, ct); if (migratedVrm10Instance == null) { throw new Exception(migrationData?.Message ?? "Failed to load migrated."); } return(migratedVrm10Instance); } }
private static bool TryGetLinearTexture(GltfData data, Vrm10TextureInfo info, out (SubAssetKey, TextureDescriptor) pair) { try { var(offset, scale) = GetTextureOffsetAndScale(info); pair = GltfTextureImporter.CreateLinear(data, info.index, offset, scale); return(true); } catch (NullReferenceException) { pair = default; return(false); } catch (ArgumentOutOfRangeException) { pair = default; return(false); } }
/// <summary> /// VMRC_materials_mtoon の場合にマテリアル生成情報を作成する /// </summary> public static bool TryCreateParam(GltfData data, int i, out MaterialDescriptor matDesc) { var m = data.GLTF.materials[i]; if (!UniGLTF.Extensions.VRMC_materials_mtoon.GltfDeserializer.TryGet(m.extensions, out UniGLTF.Extensions.VRMC_materials_mtoon.VRMC_materials_mtoon mtoon)) { // Fallback to glTF, when MToon extension does not exist. matDesc = default; return(false); } // use material.name, because material name may renamed in GltfParser. matDesc = new MaterialDescriptor(m.name, MToon10Meta.UnityShaderName); foreach (var(key, (subAssetKey, value)) in Vrm10MToonTextureImporter.EnumerateAllTextures(data, m, mtoon)) { matDesc.TextureSlots.Add(key, value); } foreach (var(key, value) in TryGetAllColors(m, mtoon)) { matDesc.Colors.Add(key, value); } foreach (var(key, value) in TryGetAllFloats(m, mtoon)) { matDesc.FloatValues.Add(key, value); } foreach (var(key, value) in TryGetAllFloatArrays(m, mtoon)) { matDesc.Vectors.Add(key, value); } matDesc.Actions.Add(material => { // Set hidden properties, keywords from float properties. new MToonValidator(material).Validate(); }); return(true); }
public MaterialDescriptor Get(GltfData data, int i) { // mtoon if (!Vrm10MToonMaterialImporter.TryCreateParam(data, i, out MaterialDescriptor matDesc)) { // unlit if (!GltfUnlitMaterialImporter.TryCreateParam(data, i, out matDesc)) { // pbr if (!GltfPbrMaterialImporter.TryCreateParam(data, i, out matDesc)) { // fallback #if VRM_DEVELOP Debug.LogWarning($"material: {i} out of range. fallback"); #endif return(new MaterialDescriptor(GltfMaterialDescriptorGenerator.GetMaterialName(i, null), GltfPbrMaterialImporter.ShaderName)); } } } return(matDesc); }
/// <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 }
public void OnGUI(ScriptedImporter importer, GltfData data, UniGLTF.Extensions.VRMC_vrm.VRMC_vrm vrm) { if (CanExtract(importer)) { if (GUILayout.Button("Extract Meta And Expressions ...")) { Extract(importer, data); } EditorGUILayout.HelpBox("Extract subasset to external object and overwrite remap", MessageType.Info); } else { if (GUILayout.Button("Clear extraction")) { ClearExternalObjects(importer, typeof(VRM10Object), typeof(VRM10Expression)); } EditorGUILayout.HelpBox("Clear remap. All remap use subAsset", MessageType.Info); } DrawRemapGUI <VRM10Object>(importer.GetExternalObjectMap()); DrawRemapGUI <VRM10Expression>(importer.GetExternalObjectMap()); }
/// <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); }
public MaterialDescriptor Get(GltfData data, int i) { // legacy "VRM/UnlitTransparentZWrite" if (VRMUnlitTransparentZWriteMaterialImporter.TryCreateParam(data, m_vrm, i, out var matDesc)) { return(matDesc); } // mtoon if (VRMMToonMaterialImporter.TryCreateParam(data, m_vrm, i, out matDesc)) { return(matDesc); } // unlit if (GltfUnlitMaterialImporter.TryCreateParam(data, i, out matDesc)) { return(matDesc); } // pbr if (GltfPbrMaterialImporter.TryCreateParam(data, i, out matDesc)) { return(matDesc); } // fallback Debug.LogWarning($"fallback"); return(new MaterialDescriptor( GltfMaterialDescriptorGenerator.GetMaterialName(i, null), GltfPbrMaterialImporter.ShaderName, null, new Dictionary <string, TextureDescriptor>(), new Dictionary <string, float>(), new Dictionary <string, Color>(), new Dictionary <string, Vector4>(), new Action <Material>[] {})); }
/// <summary> /// シーンをY軸で180度回転する /// </summary> /// <param name="gltf"></param> public static void Rotate(GltfData data) { foreach (var node in data.GLTF.nodes) { Rotate(node); } // mesh の回転のみでよい var used = new HashSet <int>(); foreach (var mesh in data.GLTF.meshes) { foreach (var prim in mesh.primitives) { ReverseVector3Array(data, prim.attributes.POSITION, used); ReverseVector3Array(data, prim.attributes.NORMAL, used); foreach (var target in prim.targets) { ReverseVector3Array(data, target.POSITION, used); ReverseVector3Array(data, target.NORMAL, used); } } } foreach (var skin in data.GLTF.skins) { if (used.Add(skin.inverseBindMatrices)) { var accessor = data.GLTF.accessors[skin.inverseBindMatrices]; var buffer = data.GetBytesFromBufferView(accessor.bufferView); var span = buffer.Reinterpret <UnityEngine.Matrix4x4>(1); for (int i = 0; i < span.Length; ++i) { span[i] = span[i].RotateY180(); } } } }
private (GameObject, IReadOnlyList <VRMShaders.MaterialFactory.MaterialLoadInfo>) ToUnity(GltfData data, VRMC_vrm vrm) { // Model => Unity using (var loader = new Vrm10Importer(data, vrm)) { var loaded = loader.Load(); return(loaded.gameObject, loader.MaterialFactory.Materials); } }