diff --git a/Assets/UniGLTF/Editor/UniGLTF/ExportDialog/MeshExportValidator.cs b/Assets/UniGLTF/Editor/UniGLTF/ExportDialog/MeshExportValidator.cs index ee0c53b02..91061f642 100644 --- a/Assets/UniGLTF/Editor/UniGLTF/ExportDialog/MeshExportValidator.cs +++ b/Assets/UniGLTF/Editor/UniGLTF/ExportDialog/MeshExportValidator.cs @@ -48,9 +48,20 @@ namespace UniGLTF public enum Messages { + [LangMsg(Languages.en, "Materials with fewer sub-meshes")] + [LangMsg(Languages.ja, "サブメッシュ数より少ないマテリアル")] MATERIALS_LESS_THAN_SUBMESH_COUNT, + + [LangMsg(Languages.en, "Materials with more sub-meshes")] + [LangMsg(Languages.ja, "サブメッシュ数より多いマテリアル")] MATERIALS_GREATER_THAN_SUBMESH_COUNT, + + [LangMsg(Languages.en, "Renderer has null in material")] + [LangMsg(Languages.ja, "レンダラーの material に null があります")] MATERIALS_CONTAINS_NULL, + + [LangMsg(Languages.en, "A Shader that cannot be exported")] + [LangMsg(Languages.ja, "エクスポート非対応のシェーダーです")] UNKNOWN_SHADER, [LangMsg(Languages.en, "Meshes containing BlendShapes with multiple Frames cannot be exported")] @@ -79,7 +90,7 @@ namespace UniGLTF if (info.Materials.Take(info.Mesh.subMeshCount).Any(x => x == null)) { // material に null が含まれる(unity で magenta になっているはず) - yield return Validation.Error($"{info.Renderers}: {Messages.MATERIALS_CONTAINS_NULL.Msg()}"); + yield return Validation.Error(Messages.MATERIALS_CONTAINS_NULL.Msg(), ValidationContext.Create(info.Renderers[0].Item1)); } } diff --git a/Assets/UniGLTF/Runtime/UniGLTF/Format/GltfSerializer.g.cs b/Assets/UniGLTF/Runtime/UniGLTF/Format/GltfSerializer.g.cs index 502aec107..326834f80 100644 --- a/Assets/UniGLTF/Runtime/UniGLTF/Format/GltfSerializer.g.cs +++ b/Assets/UniGLTF/Runtime/UniGLTF/Format/GltfSerializer.g.cs @@ -475,9 +475,9 @@ public static void Serialize_gltf_textures_ITEM(JsonFormatter f, glTFTexture val f.Value(value.sampler); } - if(value.source>=0){ + if(value.source.HasValue){ f.Key("source"); - f.Value(value.source); + f.Value(value.source.Value); } if(value.extensions!=null){ diff --git a/Assets/UniGLTF/Runtime/UniGLTF/Format/glTFTexture.cs b/Assets/UniGLTF/Runtime/UniGLTF/Format/glTFTexture.cs index 7601237e6..c7dc033ae 100644 --- a/Assets/UniGLTF/Runtime/UniGLTF/Format/glTFTexture.cs +++ b/Assets/UniGLTF/Runtime/UniGLTF/Format/glTFTexture.cs @@ -58,8 +58,7 @@ namespace UniGLTF [JsonSchema(Minimum = 0)] public int sampler; - [JsonSchema(Minimum = 0)] - public int source; + public int? source; // empty schemas public glTFExtension extensions; diff --git a/Assets/UniGLTF/Runtime/UniGLTF/IO/GltfUtility.cs b/Assets/UniGLTF/Runtime/UniGLTF/IO/GltfUtility.cs index 881f74b0a..dd2238c18 100644 --- a/Assets/UniGLTF/Runtime/UniGLTF/IO/GltfUtility.cs +++ b/Assets/UniGLTF/Runtime/UniGLTF/IO/GltfUtility.cs @@ -1,3 +1,4 @@ +using System; using System.IO; using System.Threading.Tasks; using UnityEngine; @@ -14,12 +15,37 @@ namespace UniGLTF throw new FileNotFoundException(path); } - Debug.LogFormat("{0}", path); + if (awaitCaller == null) + { + Debug.LogWarning("GltfUtility.LoadAsync: awaitCaller argument is null. ImmediateCaller is used as the default fallback. When playing, we recommend RuntimeOnlyAwaitCaller."); + awaitCaller = new ImmediateCaller(); + } + using (GltfData data = new AutoGltfFileParser(path).Parse()) using (var loader = new UniGLTF.ImporterContext(data, materialGenerator: materialGenerator)) { return await loader.LoadAsync(awaitCaller); } } + + public static async Task LoadBytesAsync(string path, byte[] bytes, IAwaitCaller awaitCaller = null, IMaterialDescriptorGenerator materialGenerator = null) + { + if (bytes == null) + { + throw new ArgumentNullException("bytes"); + } + + if (awaitCaller == null) + { + Debug.LogWarning("GltfUtility.LoadAsync: awaitCaller argument is null. ImmediateCaller is used as the default fallback. When playing, we recommend RuntimeOnlyAwaitCaller."); + awaitCaller = new ImmediateCaller(); + } + + using (GltfData data = new GlbBinaryParser(bytes, path).Parse()) + using (var loader = new UniGLTF.ImporterContext(data, materialGenerator: materialGenerator)) + { + return await loader.LoadAsync(awaitCaller); + } + } } } diff --git a/Assets/UniGLTF/Runtime/UniGLTF/IO/MaterialIO/GltfPbrMaterialImporter.cs b/Assets/UniGLTF/Runtime/UniGLTF/IO/MaterialIO/GltfPbrMaterialImporter.cs index 526a7faed..cb5c8767e 100644 --- a/Assets/UniGLTF/Runtime/UniGLTF/IO/MaterialIO/GltfPbrMaterialImporter.cs +++ b/Assets/UniGLTF/Runtime/UniGLTF/IO/MaterialIO/GltfPbrMaterialImporter.cs @@ -1,5 +1,6 @@ using System; using System.Collections.Generic; +using System.Linq; using UnityEngine; using VRMShaders; using ColorSpace = VRMShaders.ColorSpace; @@ -70,13 +71,15 @@ namespace UniGLTF var vectors = new Dictionary(); var actions = new List>(); - var standardTexDesc = default(TextureDescriptor); + TextureDescriptor? standardTexDesc = default; if (src.pbrMetallicRoughness != null || src.occlusionTexture != null) { if (src.pbrMetallicRoughness.metallicRoughnessTexture != null || src.occlusionTexture != null) { - SubAssetKey key; - (key, standardTexDesc) = GltfPbrTextureImporter.StandardTexture(data, src); + if (GltfPbrTextureImporter.TryStandardTexture(data, src, out var key, out var desc)) + { + standardTexDesc = desc; + } } if (src.pbrMetallicRoughness.baseColorFactor != null && @@ -90,15 +93,18 @@ namespace UniGLTF if (src.pbrMetallicRoughness.baseColorTexture != null && src.pbrMetallicRoughness.baseColorTexture.index != -1) { - var (key, textureParam) = GltfPbrTextureImporter.BaseColorTexture(data, src); - textureSlots.Add("_MainTex", textureParam); + if (GltfPbrTextureImporter.TryBaseColorTexture(data, src, out var key, out var desc)) + { + textureSlots.Add("_MainTex", desc); + } } if (src.pbrMetallicRoughness.metallicRoughnessTexture != null && - src.pbrMetallicRoughness.metallicRoughnessTexture.index != -1) + src.pbrMetallicRoughness.metallicRoughnessTexture.index != -1 && + standardTexDesc.HasValue) { actions.Add(material => material.EnableKeyword("_METALLICGLOSSMAP")); - textureSlots.Add("_MetallicGlossMap", standardTexDesc); + textureSlots.Add("_MetallicGlossMap", standardTexDesc.Value); // Set 1.0f as hard-coded. See: https://github.com/dwango/UniVRM/issues/212. floatValues.Add("_Metallic", 1.0f); floatValues.Add("_GlossMapScale", 1.0f); @@ -113,14 +119,16 @@ namespace UniGLTF if (src.normalTexture != null && src.normalTexture.index != -1) { actions.Add(material => material.EnableKeyword("_NORMALMAP")); - var (_, textureParam) = GltfPbrTextureImporter.NormalTexture(data, src); - textureSlots.Add("_BumpMap", textureParam); - floatValues.Add("_BumpScale", src.normalTexture.scale); + if (GltfPbrTextureImporter.TryNormalTexture(data, src, out var key, out var desc)) + { + textureSlots.Add("_BumpMap", desc); + floatValues.Add("_BumpScale", src.normalTexture.scale); + } } - if (src.occlusionTexture != null && src.occlusionTexture.index != -1) + if (src.occlusionTexture != null && src.occlusionTexture.index != -1 && standardTexDesc.HasValue) { - textureSlots.Add("_OcclusionMap", standardTexDesc); + textureSlots.Add("_OcclusionMap", standardTexDesc.Value); floatValues.Add("_OcclusionStrength", src.occlusionTexture.strength); } @@ -152,8 +160,10 @@ namespace UniGLTF if (src.emissiveTexture != null && src.emissiveTexture.index != -1) { - var (key, textureParam) = GltfPbrTextureImporter.EmissiveTexture(data, src); - textureSlots.Add("_EmissionMap", textureParam); + if (GltfPbrTextureImporter.TryEmissiveTexture(data, src, out var key, out var desc)) + { + textureSlots.Add("_EmissionMap", desc); + } } } diff --git a/Assets/UniGLTF/Runtime/UniGLTF/IO/MaterialIO/GltfUnlitMaterialImporter.cs b/Assets/UniGLTF/Runtime/UniGLTF/IO/MaterialIO/GltfUnlitMaterialImporter.cs index 7bbde1681..0f2549189 100644 --- a/Assets/UniGLTF/Runtime/UniGLTF/IO/MaterialIO/GltfUnlitMaterialImporter.cs +++ b/Assets/UniGLTF/Runtime/UniGLTF/IO/MaterialIO/GltfUnlitMaterialImporter.cs @@ -42,11 +42,11 @@ namespace UniGLTF // texture if (src.pbrMetallicRoughness.baseColorTexture != null) { - var (offset, scale) = - GltfTextureImporter.GetTextureOffsetAndScale(src.pbrMetallicRoughness.baseColorTexture); - var (key, textureParam) = GltfTextureImporter.CreateSrgb(data, - src.pbrMetallicRoughness.baseColorTexture.index, offset, scale); - textureSlots.Add("_MainTex", textureParam); + var (offset, scale) = GltfTextureImporter.GetTextureOffsetAndScale(src.pbrMetallicRoughness.baseColorTexture); + if (GltfTextureImporter.TryCreateSrgb(data, src.pbrMetallicRoughness.baseColorTexture.index, offset, scale, out var key, out var desc)) + { + textureSlots.Add("_MainTex", desc); + } } matDesc = new MaterialDescriptor( diff --git a/Assets/UniGLTF/Runtime/UniGLTF/IO/MaterialIO/URP/GltfPbrURPMaterialImporter.cs b/Assets/UniGLTF/Runtime/UniGLTF/IO/MaterialIO/URP/GltfPbrURPMaterialImporter.cs index e9996cfac..3660af82f 100644 --- a/Assets/UniGLTF/Runtime/UniGLTF/IO/MaterialIO/URP/GltfPbrURPMaterialImporter.cs +++ b/Assets/UniGLTF/Runtime/UniGLTF/IO/MaterialIO/URP/GltfPbrURPMaterialImporter.cs @@ -42,13 +42,19 @@ namespace UniGLTF var actions = new List>(); var src = data.GLTF.materials[i]; - var standardTexDesc = default(TextureDescriptor); + TextureDescriptor? standardTexDesc = default; if (src.pbrMetallicRoughness != null || src.occlusionTexture != null) { if (src.pbrMetallicRoughness.metallicRoughnessTexture != null || src.occlusionTexture != null) { - SubAssetKey key; - (key, standardTexDesc) = GltfPbrTextureImporter.StandardTexture(data, src); + if (GltfPbrTextureImporter.TryStandardTexture(data, src, out var key, out var desc)) + { + if (string.IsNullOrEmpty(desc.UnityObjectName)) + { + throw new ArgumentNullException(); + } + standardTexDesc = desc; + } } if (src.pbrMetallicRoughness.baseColorFactor != null && src.pbrMetallicRoughness.baseColorFactor.Length == 4) @@ -61,15 +67,17 @@ namespace UniGLTF if (src.pbrMetallicRoughness.baseColorTexture != null && src.pbrMetallicRoughness.baseColorTexture.index != -1) { - var (key, textureParam) = GltfPbrTextureImporter.BaseColorTexture(data, src); - // from _MainTex ! - textureSlots.Add("_BaseMap", textureParam); + if (GltfPbrTextureImporter.TryBaseColorTexture(data, src, out var key, out var desc)) + { + // from _MainTex ! + textureSlots.Add("_BaseMap", desc); + } } - if (src.pbrMetallicRoughness.metallicRoughnessTexture != null && src.pbrMetallicRoughness.metallicRoughnessTexture.index != -1) + if (src.pbrMetallicRoughness.metallicRoughnessTexture != null && src.pbrMetallicRoughness.metallicRoughnessTexture.index != -1 && standardTexDesc.HasValue) { actions.Add(material => material.EnableKeyword("_METALLICGLOSSMAP")); - textureSlots.Add("_MetallicGlossMap", standardTexDesc); + textureSlots.Add("_MetallicGlossMap", standardTexDesc.Value); // Set 1.0f as hard-coded. See: https://github.com/dwango/UniVRM/issues/212. floatValues.Add("_Metallic", 1.0f); floatValues.Add("_GlossMapScale", 1.0f); @@ -87,14 +95,16 @@ namespace UniGLTF if (src.normalTexture != null && src.normalTexture.index != -1) { actions.Add(material => material.EnableKeyword("_NORMALMAP")); - var (key, textureParam) = GltfPbrTextureImporter.NormalTexture(data, src); - textureSlots.Add("_BumpMap", textureParam); - floatValues.Add("_BumpScale", src.normalTexture.scale); + if (GltfPbrTextureImporter.TryNormalTexture(data, src, out var key, out var desc)) + { + textureSlots.Add("_BumpMap", desc); + floatValues.Add("_BumpScale", src.normalTexture.scale); + } } - if (src.occlusionTexture != null && src.occlusionTexture.index != -1) + if (src.occlusionTexture != null && src.occlusionTexture.index != -1 && standardTexDesc.HasValue) { - textureSlots.Add("_OcclusionMap", standardTexDesc); + textureSlots.Add("_OcclusionMap", standardTexDesc.Value); floatValues.Add("_OcclusionStrength", src.occlusionTexture.strength); } @@ -125,8 +135,10 @@ namespace UniGLTF if (src.emissiveTexture != null && src.emissiveTexture.index != -1) { - var (key, textureParam) = GltfPbrTextureImporter.EmissiveTexture(data, src); - textureSlots.Add("_EmissionMap", textureParam); + if (GltfPbrTextureImporter.TryEmissiveTexture(data, src, out var key, out var desc)) + { + textureSlots.Add("_EmissionMap", desc); + } } } diff --git a/Assets/UniGLTF/Runtime/UniGLTF/IO/MeshIO/MeshUploader.cs b/Assets/UniGLTF/Runtime/UniGLTF/IO/MeshIO/MeshUploader.cs index 7185b724e..e3fdf102d 100644 --- a/Assets/UniGLTF/Runtime/UniGLTF/IO/MeshIO/MeshUploader.cs +++ b/Assets/UniGLTF/Runtime/UniGLTF/IO/MeshIO/MeshUploader.cs @@ -107,7 +107,6 @@ namespace UniGLTF MeshData data, Func materialFromIndex) { - Profiler.BeginSample("MeshUploader.BuildMesh"); //Debug.Log(prims.ToJson()); var mesh = new Mesh @@ -150,7 +149,6 @@ namespace UniGLTF await BuildBlendShapeAsync(awaitCaller, mesh, blendShape, emptyVertices); } } - Profiler.EndSample(); Profiler.BeginSample("Mesh.UploadMeshData"); mesh.UploadMeshData(false); diff --git a/Assets/UniGLTF/Runtime/UniGLTF/IO/Parser/GlbLowLevelParser.cs b/Assets/UniGLTF/Runtime/UniGLTF/IO/Parser/GlbLowLevelParser.cs index bdb31f01d..ce3d4e5aa 100644 --- a/Assets/UniGLTF/Runtime/UniGLTF/IO/Parser/GlbLowLevelParser.cs +++ b/Assets/UniGLTF/Runtime/UniGLTF/IO/Parser/GlbLowLevelParser.cs @@ -172,16 +172,19 @@ namespace UniGLTF for (var textureIdx = 0; textureIdx < GLTF.textures.Count; ++textureIdx) { var gltfTexture = GLTF.textures[textureIdx]; - var gltfImage = GLTF.images[gltfTexture.source]; - if (!string.IsNullOrEmpty(gltfImage.uri) && !gltfImage.uri.StartsWith("data:")) + if (gltfTexture.source.HasValidIndex()) { - // from image uri - gltfTexture.name = Path.GetFileNameWithoutExtension(gltfImage.uri); - } - if (string.IsNullOrEmpty(gltfTexture.name)) - { - // use image name - gltfTexture.name = gltfImage.name; + var gltfImage = GLTF.images[gltfTexture.source.Value]; + if (!string.IsNullOrEmpty(gltfImage.uri) && !gltfImage.uri.StartsWith("data:")) + { + // from image uri + gltfTexture.name = Path.GetFileNameWithoutExtension(gltfImage.uri); + } + if (string.IsNullOrEmpty(gltfTexture.name)) + { + // use image name + gltfTexture.name = gltfImage.name; + } } if (string.IsNullOrEmpty(gltfTexture.name)) { diff --git a/Assets/UniGLTF/Runtime/UniGLTF/IO/TextureIO/GltfPbrTextureImporter.cs b/Assets/UniGLTF/Runtime/UniGLTF/IO/TextureIO/GltfPbrTextureImporter.cs index 5d7ab1dfa..e8fc3e10b 100644 --- a/Assets/UniGLTF/Runtime/UniGLTF/IO/TextureIO/GltfPbrTextureImporter.cs +++ b/Assets/UniGLTF/Runtime/UniGLTF/IO/TextureIO/GltfPbrTextureImporter.cs @@ -15,7 +15,10 @@ namespace UniGLTF // base color if (m.pbrMetallicRoughness?.baseColorTexture != null) { - yield return BaseColorTexture(data, m); + if (TryBaseColorTexture(data, m, out var key, out var desc)) + { + yield return (key, desc); + } } // metallic roughness @@ -28,13 +31,19 @@ namespace UniGLTF // emission if (m.emissiveTexture != null) { - yield return EmissiveTexture(data, m); + if (TryEmissiveTexture(data, m, out var key, out var desc)) + { + yield return (key, desc); + } } // normal if (m.normalTexture != null) { - yield return NormalTexture(data, m); + if (TryNormalTexture(data, m, out var key, out var desc)) + { + yield return (key, desc); + } } // occlusion @@ -47,17 +56,20 @@ namespace UniGLTF // metallicSmooth and occlusion if (metallicRoughnessTexture.HasValue || occlusionTexture.HasValue) { - yield return StandardTexture(data, m); + if (TryStandardTexture(data, m, out var key, out var desc)) + { + yield return (key, desc); + } } } - public static (SubAssetKey, TextureDescriptor) BaseColorTexture(GltfData data, glTFMaterial src) + public static bool TryBaseColorTexture(GltfData data, glTFMaterial src, out SubAssetKey key, out TextureDescriptor desc) { var (offset, scale) = GltfTextureImporter.GetTextureOffsetAndScale(src.pbrMetallicRoughness.baseColorTexture); - return GltfTextureImporter.CreateSrgb(data, src.pbrMetallicRoughness.baseColorTexture.index, offset, scale); + return GltfTextureImporter.TryCreateSrgb(data, src.pbrMetallicRoughness.baseColorTexture.index, offset, scale, out key, out desc); } - public static (SubAssetKey, TextureDescriptor) StandardTexture(GltfData data, glTFMaterial src) + public static bool TryStandardTexture(GltfData data, glTFMaterial src, out SubAssetKey key, out TextureDescriptor desc) { var metallicFactor = 1.0f; var roughnessFactor = 1.0f; @@ -67,25 +79,24 @@ namespace UniGLTF roughnessFactor = src.pbrMetallicRoughness.roughnessFactor; } var (offset, scale) = GltfTextureImporter.GetTextureOffsetAndScale(src.pbrMetallicRoughness.metallicRoughnessTexture); - return GltfTextureImporter.CreateStandard(data, + return GltfTextureImporter.TryCreateStandard(data, src.pbrMetallicRoughness?.metallicRoughnessTexture?.index, src.occlusionTexture?.index, offset, scale, metallicFactor, - roughnessFactor); + roughnessFactor, out key, out desc); } - public static (SubAssetKey, TextureDescriptor) NormalTexture(GltfData data, glTFMaterial src) + public static bool TryNormalTexture(GltfData data, glTFMaterial src, out SubAssetKey key, out TextureDescriptor desc) { var (offset, scale) = GltfTextureImporter.GetTextureOffsetAndScale(src.normalTexture); - return GltfTextureImporter.CreateNormal(data, src.normalTexture.index, offset, scale); + return GltfTextureImporter.TryCreateNormal(data, src.normalTexture.index, offset, scale, out key, out desc); } - public static (SubAssetKey, TextureDescriptor) EmissiveTexture(GltfData data, glTFMaterial src) + public static bool TryEmissiveTexture(GltfData data, glTFMaterial src, out SubAssetKey key, out TextureDescriptor desc) { var (offset, scale) = GltfTextureImporter.GetTextureOffsetAndScale(src.emissiveTexture); - return GltfTextureImporter.CreateSrgb(data, src.emissiveTexture.index, offset, scale); + return GltfTextureImporter.TryCreateSrgb(data, src.emissiveTexture.index, offset, scale, out key, out desc); } - } } diff --git a/Assets/UniGLTF/Runtime/UniGLTF/IO/TextureIO/GltfTextureImporter.cs b/Assets/UniGLTF/Runtime/UniGLTF/IO/TextureIO/GltfTextureImporter.cs index bde1d5d2b..6fdb77787 100644 --- a/Assets/UniGLTF/Runtime/UniGLTF/IO/TextureIO/GltfTextureImporter.cs +++ b/Assets/UniGLTF/Runtime/UniGLTF/IO/TextureIO/GltfTextureImporter.cs @@ -35,13 +35,20 @@ namespace UniGLTF return (texDesc.SubAssetKey, texDesc); } - public static (SubAssetKey, TextureDescriptor) CreateSrgb(GltfData data, int textureIndex, Vector2 offset, Vector2 scale) + public static bool TryCreateSrgb(GltfData data, int textureIndex, Vector2 offset, Vector2 scale, out SubAssetKey key, out TextureDescriptor desc) { var gltfTexture = data.GLTF.textures[textureIndex]; - var gltfImage = data.GLTF.images[gltfTexture.source]; + if (!gltfTexture.source.HasValidIndex()) + { + key = default; + desc = default; + return false; + } + + var gltfImage = data.GLTF.images[gltfTexture.source.Value]; var name = TextureImportName.GetUnityObjectName(TextureImportTypes.sRGB, gltfTexture.name, gltfImage.uri); var sampler = TextureSamplerUtil.CreateSampler(data.GLTF, textureIndex); - var param = new TextureDescriptor( + desc = new TextureDescriptor( name, offset, scale, sampler, @@ -50,16 +57,24 @@ namespace UniGLTF default, () => Task.FromResult(GetImageBytesFromTextureIndex(data, textureIndex)), default, default, default, default, default); - return (param.SubAssetKey, param); + key = desc.SubAssetKey; + return true; } - public static (SubAssetKey, TextureDescriptor) CreateLinear(GltfData data, int textureIndex, Vector2 offset, Vector2 scale) + public static bool TryCreateLinear(GltfData data, int textureIndex, Vector2 offset, Vector2 scale, out SubAssetKey key, out TextureDescriptor desc) { var gltfTexture = data.GLTF.textures[textureIndex]; - var gltfImage = data.GLTF.images[gltfTexture.source]; + if (!gltfTexture.source.HasValidIndex()) + { + key = default; + desc = default; + return false; + } + + var gltfImage = data.GLTF.images[gltfTexture.source.Value]; var name = TextureImportName.GetUnityObjectName(TextureImportTypes.Linear, gltfTexture.name, gltfImage.uri); var sampler = TextureSamplerUtil.CreateSampler(data.GLTF, textureIndex); - var param = new TextureDescriptor( + desc = new TextureDescriptor( name, offset, scale, @@ -69,16 +84,24 @@ namespace UniGLTF default, () => Task.FromResult(GetImageBytesFromTextureIndex(data, textureIndex)), default, default, default, default, default); - return (param.SubAssetKey, param); + key = desc.SubAssetKey; + return true; } - public static (SubAssetKey, TextureDescriptor) CreateNormal(GltfData data, int textureIndex, Vector2 offset, Vector2 scale) + public static bool TryCreateNormal(GltfData data, int textureIndex, Vector2 offset, Vector2 scale, out SubAssetKey key, out TextureDescriptor desc) { var gltfTexture = data.GLTF.textures[textureIndex]; - var gltfImage = data.GLTF.images[gltfTexture.source]; + if (!gltfTexture.source.HasValidIndex()) + { + key = default; + desc = default; + return false; + } + + var gltfImage = data.GLTF.images[gltfTexture.source.Value]; var name = TextureImportName.GetUnityObjectName(TextureImportTypes.NormalMap, gltfTexture.name, gltfImage.uri); var sampler = TextureSamplerUtil.CreateSampler(data.GLTF, textureIndex); - var param = new TextureDescriptor( + desc = new TextureDescriptor( name, offset, scale, @@ -88,10 +111,11 @@ namespace UniGLTF default, () => Task.FromResult(GetImageBytesFromTextureIndex(data, textureIndex)), default, default, default, default, default); - return (param.SubAssetKey, param); + key = desc.SubAssetKey; + return true; } - public static (SubAssetKey, TextureDescriptor) CreateStandard(GltfData data, int? metallicRoughnessTextureIndex, int? occlusionTextureIndex, Vector2 offset, Vector2 scale, float metallicFactor, float roughnessFactor) + public static bool TryCreateStandard(GltfData data, int? metallicRoughnessTextureIndex, int? occlusionTextureIndex, Vector2 offset, Vector2 scale, float metallicFactor, float roughnessFactor, out SubAssetKey key, out TextureDescriptor desc) { string name = default; @@ -100,24 +124,37 @@ namespace UniGLTF if (metallicRoughnessTextureIndex.HasValue) { var gltfTexture = data.GLTF.textures[metallicRoughnessTextureIndex.Value]; - name = TextureImportName.GetUnityObjectName(TextureImportTypes.StandardMap, gltfTexture.name, data.GLTF.images[gltfTexture.source].uri); - sampler = TextureSamplerUtil.CreateSampler(data.GLTF, metallicRoughnessTextureIndex.Value); - getMetallicRoughnessAsync = () => Task.FromResult(GetImageBytesFromTextureIndex(data, metallicRoughnessTextureIndex.Value)); + if (gltfTexture.source.HasValidIndex()) + { + name = TextureImportName.GetUnityObjectName(TextureImportTypes.StandardMap, gltfTexture.name, data.GLTF.images[gltfTexture.source.Value].uri); + sampler = TextureSamplerUtil.CreateSampler(data.GLTF, metallicRoughnessTextureIndex.Value); + getMetallicRoughnessAsync = () => Task.FromResult(GetImageBytesFromTextureIndex(data, metallicRoughnessTextureIndex.Value)); + } } GetTextureBytesAsync getOcclusionAsync = default; if (occlusionTextureIndex.HasValue) { var gltfTexture = data.GLTF.textures[occlusionTextureIndex.Value]; - if (string.IsNullOrEmpty(name)) + if (gltfTexture.source.HasValidIndex()) { - name = TextureImportName.GetUnityObjectName(TextureImportTypes.StandardMap, gltfTexture.name, data.GLTF.images[gltfTexture.source].uri); + if (string.IsNullOrEmpty(name)) + { + name = TextureImportName.GetUnityObjectName(TextureImportTypes.StandardMap, gltfTexture.name, data.GLTF.images[gltfTexture.source.Value].uri); + } + sampler = TextureSamplerUtil.CreateSampler(data.GLTF, occlusionTextureIndex.Value); + getOcclusionAsync = () => Task.FromResult(GetImageBytesFromTextureIndex(data, occlusionTextureIndex.Value)); } - sampler = TextureSamplerUtil.CreateSampler(data.GLTF, occlusionTextureIndex.Value); - getOcclusionAsync = () => Task.FromResult(GetImageBytesFromTextureIndex(data, occlusionTextureIndex.Value)); } - var texDesc = new TextureDescriptor( + if (string.IsNullOrEmpty(name)) + { + key = default; + desc = default; + return false; + } + + desc = new TextureDescriptor( name, offset, scale, @@ -128,7 +165,13 @@ namespace UniGLTF getMetallicRoughnessAsync, getOcclusionAsync, default, default, default, default); - return (texDesc.SubAssetKey, texDesc); + key = desc.SubAssetKey; + if (string.IsNullOrEmpty(desc.UnityObjectName)) + { + throw new ArgumentNullException(); + } + Debug.Log("${name}"); + return true; } public static (Vector2, Vector2) GetTextureOffsetAndScale(glTFTextureInfo textureInfo) diff --git a/Assets/VRM/Runtime/IO/VRMImporterContext.cs b/Assets/VRM/Runtime/IO/VRMImporterContext.cs index 8f73cf326..f48a19309 100644 --- a/Assets/VRM/Runtime/IO/VRMImporterContext.cs +++ b/Assets/VRM/Runtime/IO/VRMImporterContext.cs @@ -301,8 +301,10 @@ namespace VRM meta.Title = gltfMeta.title; if (gltfMeta.texture >= 0) { - var (key, param) = GltfTextureImporter.CreateSrgb(Data, gltfMeta.texture, Vector2.zero, Vector2.one); - meta.Thumbnail = await TextureFactory.GetTextureAsync(param, awaitCaller) as Texture2D; + if (GltfTextureImporter.TryCreateSrgb(Data, gltfMeta.texture, Vector2.zero, Vector2.one, out var key, out var desc)) + { + meta.Thumbnail = await TextureFactory.GetTextureAsync(desc, awaitCaller) as Texture2D; + } } meta.AllowedUser = gltfMeta.allowedUser; meta.ViolentUssage = gltfMeta.violentUssage; diff --git a/Assets/VRM/Runtime/IO/VRMMToonMaterialImporter.cs b/Assets/VRM/Runtime/IO/VRMMToonMaterialImporter.cs index 56c9c95a9..13772d106 100644 --- a/Assets/VRM/Runtime/IO/VRMMToonMaterialImporter.cs +++ b/Assets/VRM/Runtime/IO/VRMMToonMaterialImporter.cs @@ -85,9 +85,9 @@ namespace VRM foreach (var kv in vrmMaterial.textureProperties) { if (VRMMToonTextureImporter.TryGetTextureFromMaterialProperty(data, vrmMaterial, kv.Key, - out var texture)) + out var key, out var desc)) { - textureSlots.Add(kv.Key, texture.Item2); + textureSlots.Add(kv.Key, desc); } } diff --git a/Assets/VRM/Runtime/IO/VRMMToonTextureImporter.cs b/Assets/VRM/Runtime/IO/VRMMToonTextureImporter.cs index 52485a320..cdb3f94d7 100644 --- a/Assets/VRM/Runtime/IO/VRMMToonTextureImporter.cs +++ b/Assets/VRM/Runtime/IO/VRMMToonTextureImporter.cs @@ -12,13 +12,13 @@ namespace VRM var vrmMaterial = vrm.materialProperties[materialIdx]; foreach (var kv in vrmMaterial.textureProperties) { - if (TryGetTextureFromMaterialProperty(data, vrmMaterial, kv.Key, out var texture)) + if (TryGetTextureFromMaterialProperty(data, vrmMaterial, kv.Key, out var key, out var desc)) { - yield return texture; + yield return (key, desc); } } } - public static bool TryGetTextureFromMaterialProperty(GltfData data, glTF_VRM_Material vrmMaterial, string textureKey, out (SubAssetKey, TextureDescriptor) texture) + public static bool TryGetTextureFromMaterialProperty(GltfData data, glTF_VRM_Material vrmMaterial, string textureKey, out SubAssetKey key, out TextureDescriptor desc) { // 任意の shader の import を許容する if (/*vrmMaterial.shader == MToon.Utils.ShaderName &&*/ vrmMaterial.textureProperties.TryGetValue(textureKey, out var textureIdx)) @@ -33,16 +33,14 @@ namespace VRM switch (textureKey) { case MToon.Utils.PropBumpMap: - texture = GltfTextureImporter.CreateNormal(data, textureIdx, offset, scale); - break; + return GltfTextureImporter.TryCreateNormal(data, textureIdx, offset, scale, out key, out desc); default: - texture = GltfTextureImporter.CreateSrgb(data, textureIdx, offset, scale); - break; + return GltfTextureImporter.TryCreateSrgb(data, textureIdx, offset, scale, out key, out desc); } - return true; } - texture = default; + key = default; + desc = default; return false; } diff --git a/Assets/VRM/Runtime/IO/VRMUnlitTransparentZWriteMaterialImporter.cs b/Assets/VRM/Runtime/IO/VRMUnlitTransparentZWriteMaterialImporter.cs index 9d8a57780..dd0792efe 100644 --- a/Assets/VRM/Runtime/IO/VRMUnlitTransparentZWriteMaterialImporter.cs +++ b/Assets/VRM/Runtime/IO/VRMUnlitTransparentZWriteMaterialImporter.cs @@ -48,9 +48,9 @@ namespace VRM if (vrmMaterial.textureProperties.ContainsKey(UnlitTransparentZWriteMainTexturePropName)) { if (VRMMToonTextureImporter.TryGetTextureFromMaterialProperty(data, vrmMaterial, - UnlitTransparentZWriteMainTexturePropName, out var texture)) + UnlitTransparentZWriteMainTexturePropName, out var key, out var desc)) { - textureSlots.Add(MToon.Utils.PropMainTex, texture.Item2); + textureSlots.Add(MToon.Utils.PropMainTex, desc); } } diff --git a/Assets/VRM/Runtime/IO/VrmTextureDescriptorGenerator.cs b/Assets/VRM/Runtime/IO/VrmTextureDescriptorGenerator.cs index 047d866cb..8a02a9bc0 100644 --- a/Assets/VRM/Runtime/IO/VrmTextureDescriptorGenerator.cs +++ b/Assets/VRM/Runtime/IO/VrmTextureDescriptorGenerator.cs @@ -59,21 +59,21 @@ namespace VRM } // Thumbnail - if (TryGetThumbnailTexture(data, vrm, out var thumbnail)) + if (TryGetThumbnailTexture(data, vrm, out var key, out var desc)) { - yield return thumbnail; + yield return (key, desc); } } - private static bool TryGetThumbnailTexture(GltfData data, glTF_VRM_extensions vrm, out (SubAssetKey, TextureDescriptor) texture) + private static bool TryGetThumbnailTexture(GltfData data, glTF_VRM_extensions vrm, out SubAssetKey key, out TextureDescriptor desc) { if (vrm.meta.texture > -1) { - texture = GltfTextureImporter.CreateSrgb(data, vrm.meta.texture, Vector2.zero, Vector2.one); - return true; + return GltfTextureImporter.TryCreateSrgb(data, vrm.meta.texture, Vector2.zero, Vector2.one, out key, out desc); } - texture = default; + key = default; + desc = default; return false; } } diff --git a/Assets/VRM/Runtime/IO/VrmUtility.cs b/Assets/VRM/Runtime/IO/VrmUtility.cs index 5a7b60296..fec35b4d7 100644 --- a/Assets/VRM/Runtime/IO/VrmUtility.cs +++ b/Assets/VRM/Runtime/IO/VrmUtility.cs @@ -60,5 +60,57 @@ namespace VRM } } } + + + public static async Task LoadBytesAsync(string path, + byte[] bytes, + IAwaitCaller awaitCaller = null, + MaterialGeneratorCallback materialGeneratorCallback = null, + MetaCallback metaCallback = null, + bool loadAnimation = false + ) + { + if (bytes == null) + { + throw new ArgumentNullException("bytes"); + } + + if (awaitCaller == null) + { + Debug.LogWarning("VrmUtility.LoadAsync: awaitCaller argument is null. ImmediateCaller is used as the default fallback. When playing, we recommend RuntimeOnlyAwaitCaller."); + awaitCaller = new ImmediateCaller(); + } + + using (GltfData data = new GlbBinaryParser(bytes, path).Parse()) + { + try + { + var vrm = new VRMData(data); + IMaterialDescriptorGenerator materialGen = default; + if (materialGeneratorCallback != null) + { + materialGen = materialGeneratorCallback(vrm.VrmExtension); + } + using (var loader = new VRMImporterContext(vrm, materialGenerator: materialGen, loadAnimation: loadAnimation)) + { + if (metaCallback != null) + { + var meta = await loader.ReadMetaAsync(awaitCaller, true); + metaCallback(meta); + } + return await loader.LoadAsync(awaitCaller); + } + } + catch (NotVrm0Exception) + { + // retry + Debug.LogWarning("file extension is vrm. but not vrm ?"); + using (var loader = new UniGLTF.ImporterContext(data)) + { + return await loader.LoadAsync(awaitCaller); + } + } + } + } } } diff --git a/Assets/VRM10/Runtime/Components/Constraint/Vrm10AimConstraint.cs b/Assets/VRM10/Runtime/Components/Constraint/Vrm10AimConstraint.cs index 72d364c82..15d489eae 100644 --- a/Assets/VRM10/Runtime/Components/Constraint/Vrm10AimConstraint.cs +++ b/Assets/VRM10/Runtime/Components/Constraint/Vrm10AimConstraint.cs @@ -70,11 +70,37 @@ namespace UniVRM10 var toVec = (Source.position - transform.position).normalized; var fromToQuat = Quaternion.FromToRotation(fromVec, toVec); - transform.rotation = Quaternion.SlerpUnclamped( + transform.localRotation = Quaternion.SlerpUnclamped( _dstRestLocalQuat, Quaternion.Inverse(dstParentWorldQuat) * fromToQuat * dstParentWorldQuat * _dstRestLocalQuat, Weight ); } + + public void OnDrawGizmosSelected() + { + if (Source == null) + { + return; + } + + Gizmos.color = Color.magenta; + Gizmos.DrawLine(transform.position, Source.position); + Gizmos.DrawSphere(Source.position, 0.01f); + + Gizmos.matrix = transform.localToWorldMatrix; + var len = 0.1f; + switch (AimAxis) + { + case AimAxis.PositiveX: + Gizmos.color = Color.red; + Gizmos.DrawLine(Vector3.zero, Vector3.right * len); + break; + case AimAxis.NegativeX: + Gizmos.color = Color.red; + Gizmos.DrawLine(Vector3.zero, Vector3.left * len); + break; + } + } } } diff --git a/Assets/VRM10/Runtime/Components/Constraint/Vrm10ConstraintUtil.cs b/Assets/VRM10/Runtime/Components/Constraint/Vrm10ConstraintUtil.cs new file mode 100644 index 000000000..702f17d02 --- /dev/null +++ b/Assets/VRM10/Runtime/Components/Constraint/Vrm10ConstraintUtil.cs @@ -0,0 +1,18 @@ +namespace UniVRM10 +{ + public static class Vrm10ConstraintUtil + { + /// + /// 右手系と左手系を相互に変換する + /// + public static UniGLTF.Extensions.VRMC_node_constraint.AimAxis ReverseX(UniGLTF.Extensions.VRMC_node_constraint.AimAxis src) + { + switch (src) + { + case UniGLTF.Extensions.VRMC_node_constraint.AimAxis.PositiveX: return UniGLTF.Extensions.VRMC_node_constraint.AimAxis.NegativeX; + case UniGLTF.Extensions.VRMC_node_constraint.AimAxis.NegativeX: return UniGLTF.Extensions.VRMC_node_constraint.AimAxis.PositiveX; + default: return src; + } + } + } +} diff --git a/Assets/VRM10/Runtime/Components/Constraint/Vrm10ConstraintUtil.cs.meta b/Assets/VRM10/Runtime/Components/Constraint/Vrm10ConstraintUtil.cs.meta new file mode 100644 index 000000000..461a75070 --- /dev/null +++ b/Assets/VRM10/Runtime/Components/Constraint/Vrm10ConstraintUtil.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: e2c7b76ebe42e9543ac52153ea9f2728 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/VRM10/Runtime/IO/Texture/Vrm10MToonTextureImporter.cs b/Assets/VRM10/Runtime/IO/Texture/Vrm10MToonTextureImporter.cs index edbb26db1..9dbba8a44 100644 --- a/Assets/VRM10/Runtime/IO/Texture/Vrm10MToonTextureImporter.cs +++ b/Assets/VRM10/Runtime/IO/Texture/Vrm10MToonTextureImporter.cs @@ -12,175 +12,180 @@ namespace UniVRM10 { public static IEnumerable<(string key, (SubAssetKey, TextureDescriptor))> EnumerateAllTextures(GltfData data, glTFMaterial material, VRMC_materials_mtoon mToon) { - if (TryGetBaseColorTexture(data, material, out var litTex)) + if (TryGetBaseColorTexture(data, material, out var key, out var desc)) { - yield return (MToon10Prop.BaseColorTexture.ToUnityShaderLabName(), litTex); + yield return (MToon10Prop.BaseColorTexture.ToUnityShaderLabName(), (key, desc)); } - if (TryGetEmissiveTexture(data, material, out var emissiveTex)) + if (TryGetEmissiveTexture(data, material, out key, out desc)) { - yield return (MToon10Prop.EmissiveTexture.ToUnityShaderLabName(), emissiveTex); + yield return (MToon10Prop.EmissiveTexture.ToUnityShaderLabName(), (key, desc)); } - if (TryGetNormalTexture(data, material, out var normalTex)) + if (TryGetNormalTexture(data, material, out key, out desc)) { - yield return (MToon10Prop.NormalTexture.ToUnityShaderLabName(), normalTex); + yield return (MToon10Prop.NormalTexture.ToUnityShaderLabName(), (key, desc)); } - if (TryGetShadeMultiplyTexture(data, mToon, out var shadeTex)) + if (TryGetShadeMultiplyTexture(data, mToon, out key, out desc)) { - yield return (MToon10Prop.ShadeColorTexture.ToUnityShaderLabName(), shadeTex); + yield return (MToon10Prop.ShadeColorTexture.ToUnityShaderLabName(), (key, desc)); } - if (TryGetShadingShiftTexture(data, mToon, out var shadeShiftTex)) + if (TryGetShadingShiftTexture(data, mToon, out key, out desc)) { - yield return (MToon10Prop.ShadingShiftTexture.ToUnityShaderLabName(), shadeShiftTex); + yield return (MToon10Prop.ShadingShiftTexture.ToUnityShaderLabName(), (key, desc)); } - if (TryGetMatcapTexture(data, mToon, out var matcapTex)) + if (TryGetMatcapTexture(data, mToon, out key, out desc)) { - yield return (MToon10Prop.MatcapTexture.ToUnityShaderLabName(), matcapTex); + yield return (MToon10Prop.MatcapTexture.ToUnityShaderLabName(), (key, desc)); } - if (TryGetRimMultiplyTexture(data, mToon, out var rimTex)) + if (TryGetRimMultiplyTexture(data, mToon, out key, out desc)) { - yield return (MToon10Prop.RimMultiplyTexture.ToUnityShaderLabName(), rimTex); + yield return (MToon10Prop.RimMultiplyTexture.ToUnityShaderLabName(), (key, desc)); } - if (TryGetOutlineWidthMultiplyTexture(data, mToon, out var outlineTex)) + if (TryGetOutlineWidthMultiplyTexture(data, mToon, out key, out desc)) { - yield return (MToon10Prop.OutlineWidthMultiplyTexture.ToUnityShaderLabName(), outlineTex); + yield return (MToon10Prop.OutlineWidthMultiplyTexture.ToUnityShaderLabName(), (key, desc)); } - if (TryGetUvAnimationMaskTexture(data, mToon, out var uvAnimMaskTex)) + if (TryGetUvAnimationMaskTexture(data, mToon, out key, out desc)) { - yield return (MToon10Prop.UvAnimationMaskTexture.ToUnityShaderLabName(), uvAnimMaskTex); + yield return (MToon10Prop.UvAnimationMaskTexture.ToUnityShaderLabName(), (key, desc)); } } - private static bool TryGetBaseColorTexture(GltfData data, glTFMaterial src, out (SubAssetKey, TextureDescriptor) pair) + private static bool TryGetBaseColorTexture(GltfData data, glTFMaterial src, out SubAssetKey key, out TextureDescriptor desc) { try { - pair = GltfPbrTextureImporter.BaseColorTexture(data, src); - return true; + return GltfPbrTextureImporter.TryBaseColorTexture(data, src, out key, out desc); } catch (NullReferenceException) { - pair = default; + key = default; + desc = default; return false; } catch (ArgumentOutOfRangeException) { - pair = default; + key = default; + desc = default; return false; } } - private static bool TryGetEmissiveTexture(GltfData data, glTFMaterial src, out (SubAssetKey, TextureDescriptor) pair) + private static bool TryGetEmissiveTexture(GltfData data, glTFMaterial src, out SubAssetKey key, out TextureDescriptor desc) { try { - pair = GltfPbrTextureImporter.EmissiveTexture(data, src); - return true; + return GltfPbrTextureImporter.TryEmissiveTexture(data, src, out key, out desc); } catch (NullReferenceException) { - pair = default; + key = default; + desc = default; return false; } catch (ArgumentOutOfRangeException) { - pair = default; + key = default; + desc = default; return false; } } - private static bool TryGetNormalTexture(GltfData data, glTFMaterial src, out (SubAssetKey, TextureDescriptor) pair) + private static bool TryGetNormalTexture(GltfData data, glTFMaterial src, out SubAssetKey key, out TextureDescriptor desc) { try { - pair = GltfPbrTextureImporter.NormalTexture(data, src); - return true; + return GltfPbrTextureImporter.TryNormalTexture(data, src, out key, out desc); } catch (NullReferenceException) { - pair = default; + key = default; + desc = default; return false; } catch (ArgumentOutOfRangeException) { - pair = default; + key = default; + desc = default; return false; } } - private static bool TryGetShadeMultiplyTexture(GltfData data, VRMC_materials_mtoon mToon, out (SubAssetKey, TextureDescriptor) pair) + private static bool TryGetShadeMultiplyTexture(GltfData data, VRMC_materials_mtoon mToon, out SubAssetKey key, out TextureDescriptor desc) { - return TryGetSRGBTexture(data, new Vrm10TextureInfo(mToon.ShadeMultiplyTexture), out pair); + return TryGetSRGBTexture(data, new Vrm10TextureInfo(mToon.ShadeMultiplyTexture), out key, out desc); } - private static bool TryGetShadingShiftTexture(GltfData data, VRMC_materials_mtoon mToon, out (SubAssetKey, TextureDescriptor) pair) + private static bool TryGetShadingShiftTexture(GltfData data, VRMC_materials_mtoon mToon, out SubAssetKey key, out TextureDescriptor desc) { - return TryGetLinearTexture(data, new Vrm10TextureInfo(mToon.ShadingShiftTexture), out pair); + return TryGetLinearTexture(data, new Vrm10TextureInfo(mToon.ShadingShiftTexture), out key, out desc); } - private static bool TryGetMatcapTexture(GltfData data, VRMC_materials_mtoon mToon, out (SubAssetKey, TextureDescriptor) pair) + private static bool TryGetMatcapTexture(GltfData data, VRMC_materials_mtoon mToon, out SubAssetKey key, out TextureDescriptor desc) { - return TryGetSRGBTexture(data, new Vrm10TextureInfo(mToon.MatcapTexture), out pair); + return TryGetSRGBTexture(data, new Vrm10TextureInfo(mToon.MatcapTexture), out key, out desc); } - private static bool TryGetRimMultiplyTexture(GltfData data, VRMC_materials_mtoon mToon, out (SubAssetKey, TextureDescriptor) pair) + private static bool TryGetRimMultiplyTexture(GltfData data, VRMC_materials_mtoon mToon, out SubAssetKey key, out TextureDescriptor desc) { - return TryGetSRGBTexture(data, new Vrm10TextureInfo(mToon.RimMultiplyTexture), out pair); + return TryGetSRGBTexture(data, new Vrm10TextureInfo(mToon.RimMultiplyTexture), out key, out desc); } - private static bool TryGetOutlineWidthMultiplyTexture(GltfData data, VRMC_materials_mtoon mToon, out (SubAssetKey, TextureDescriptor) pair) + private static bool TryGetOutlineWidthMultiplyTexture(GltfData data, VRMC_materials_mtoon mToon, out SubAssetKey key, out TextureDescriptor desc) { - return TryGetLinearTexture(data, new Vrm10TextureInfo(mToon.OutlineWidthMultiplyTexture), out pair); + return TryGetLinearTexture(data, new Vrm10TextureInfo(mToon.OutlineWidthMultiplyTexture), out key, out desc); } - private static bool TryGetUvAnimationMaskTexture(GltfData data, VRMC_materials_mtoon mToon, out (SubAssetKey, TextureDescriptor) pair) + private static bool TryGetUvAnimationMaskTexture(GltfData data, VRMC_materials_mtoon mToon, out SubAssetKey key, out TextureDescriptor desc) { - return TryGetLinearTexture(data, new Vrm10TextureInfo(mToon.UvAnimationMaskTexture), out pair); + return TryGetLinearTexture(data, new Vrm10TextureInfo(mToon.UvAnimationMaskTexture), out key, out desc); } - private static bool TryGetSRGBTexture(GltfData data, Vrm10TextureInfo info, out (SubAssetKey, TextureDescriptor) pair) + private static bool TryGetSRGBTexture(GltfData data, Vrm10TextureInfo info, out SubAssetKey key, out TextureDescriptor desc) { try { var (offset, scale) = GetTextureOffsetAndScale(info); - pair = GltfTextureImporter.CreateSrgb(data, info.index, offset, scale); - return true; + return GltfTextureImporter.TryCreateSrgb(data, info.index, offset, scale, out key, out desc); } catch (NullReferenceException) { - pair = default; + key = default; + desc = default; return false; } catch (ArgumentOutOfRangeException) { - pair = default; + key = default; + desc = default; return false; } } - private static bool TryGetLinearTexture(GltfData data, Vrm10TextureInfo info, out (SubAssetKey, TextureDescriptor) pair) + private static bool TryGetLinearTexture(GltfData data, Vrm10TextureInfo info, out SubAssetKey key, out TextureDescriptor desc) { try { var (offset, scale) = GetTextureOffsetAndScale(info); - pair = GltfTextureImporter.CreateLinear(data, info.index, offset, scale); - return true; + return GltfTextureImporter.TryCreateLinear(data, info.index, offset, scale, out key, out desc); } catch (NullReferenceException) { - pair = default; + key = default; + desc = default; return false; } catch (ArgumentOutOfRangeException) { - pair = default; + key = default; + desc = default; return false; } } diff --git a/Assets/VRM10/Runtime/IO/Vrm10Exporter.cs b/Assets/VRM10/Runtime/IO/Vrm10Exporter.cs index af3dc02f4..bd20f8cb4 100644 --- a/Assets/VRM10/Runtime/IO/Vrm10Exporter.cs +++ b/Assets/VRM10/Runtime/IO/Vrm10Exporter.cs @@ -430,7 +430,7 @@ namespace UniVRM10 { Source = model.Nodes.IndexOf(converter.Nodes[aimConstraint.Source.gameObject]), Weight = aimConstraint.Weight, - AimAxis = aimConstraint.AimAxis, + AimAxis = Vrm10ConstraintUtil.ReverseX(aimConstraint.AimAxis), }; break; diff --git a/Assets/VRM10/Runtime/IO/Vrm10Importer.cs b/Assets/VRM10/Runtime/IO/Vrm10Importer.cs index 1fab7d277..6aed057d5 100644 --- a/Assets/VRM10/Runtime/IO/Vrm10Importer.cs +++ b/Assets/VRM10/Runtime/IO/Vrm10Importer.cs @@ -701,7 +701,7 @@ namespace UniVRM10 var component = node.gameObject.AddComponent(); component.Source = Nodes[aim.Source.Value]; // required component.Weight = aim.Weight.GetValueOrDefault(1.0f); - component.AimAxis = aim.AimAxis; // required + component.AimAxis = Vrm10ConstraintUtil.ReverseX(aim.AimAxis); // required } else if (constraint.Rotation != null) { diff --git a/Assets/VRMShaders/GLTF/IO/Runtime/AwaitCaller/RuntimeOnlyNoThreadAwaitCaller.cs b/Assets/VRMShaders/GLTF/IO/Runtime/AwaitCaller/RuntimeOnlyNoThreadAwaitCaller.cs new file mode 100644 index 000000000..e3b53c9a8 --- /dev/null +++ b/Assets/VRMShaders/GLTF/IO/Runtime/AwaitCaller/RuntimeOnlyNoThreadAwaitCaller.cs @@ -0,0 +1,51 @@ +using System; +using System.Threading.Tasks; + +namespace VRMShaders +{ + /// + /// Runtime (Build 後と、Editor Playing) での非同期ロードを実現する AwaitCaller. + /// WebGL など Thread が無いもの向け + /// + public sealed class RuntimeOnlyNoThreadAwaitCaller : IAwaitCaller + { + private readonly NextFrameTaskScheduler _scheduler; + + public RuntimeOnlyNoThreadAwaitCaller() + { + _scheduler = new NextFrameTaskScheduler(); + } + + public Task NextFrame() + { + var tcs = new TaskCompletionSource(); + _scheduler.Enqueue(() => tcs.SetResult(default)); + return tcs.Task; + } + + public Task Run(Action action) + { + try + { + action(); + return Task.FromResult(null); + } + catch (Exception ex) + { + return Task.FromException(ex); + } + } + + public Task Run(Func action) + { + try + { + return Task.FromResult(action()); + } + catch (Exception ex) + { + return Task.FromException(ex); + } + } + } +} \ No newline at end of file diff --git a/Assets/VRMShaders/GLTF/IO/Runtime/AwaitCaller/RuntimeOnlyNoThreadAwaitCaller.cs.meta b/Assets/VRMShaders/GLTF/IO/Runtime/AwaitCaller/RuntimeOnlyNoThreadAwaitCaller.cs.meta new file mode 100644 index 000000000..42bdc91ae --- /dev/null +++ b/Assets/VRMShaders/GLTF/IO/Runtime/AwaitCaller/RuntimeOnlyNoThreadAwaitCaller.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 6d3630f9fecf62f4a8137907b0f7beb2 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/VRMShaders/GLTF/IO/Runtime/SubAssetKey.cs b/Assets/VRMShaders/GLTF/IO/Runtime/SubAssetKey.cs index d9bd042b0..ffd1e18f7 100644 --- a/Assets/VRMShaders/GLTF/IO/Runtime/SubAssetKey.cs +++ b/Assets/VRMShaders/GLTF/IO/Runtime/SubAssetKey.cs @@ -55,9 +55,14 @@ namespace VRMShaders public SubAssetKey(Type type, string name) { - if (type == null || string.IsNullOrEmpty(name)) + if (type == null) { - throw new System.ArgumentNullException(); + throw new System.ArgumentNullException("type"); + } + + if (string.IsNullOrEmpty(name)) + { + throw new System.ArgumentNullException("name"); } if (!type.IsSubclassOf(typeof(UnityEngine.Object))) diff --git a/Assets/VRMShaders/GLTF/IO/Runtime/Texture/Importer/TextureDescriptor.cs b/Assets/VRMShaders/GLTF/IO/Runtime/Texture/Importer/TextureDescriptor.cs index 37b4ea2c7..83c434c58 100644 --- a/Assets/VRMShaders/GLTF/IO/Runtime/Texture/Importer/TextureDescriptor.cs +++ b/Assets/VRMShaders/GLTF/IO/Runtime/Texture/Importer/TextureDescriptor.cs @@ -52,6 +52,10 @@ namespace VRMShaders GetTextureBytesAsync i4, GetTextureBytesAsync i5) { + if (string.IsNullOrEmpty(name)) + { + throw new ArgumentNullException("name"); + } UnityObjectName = name; Offset = offset; Scale = scale; diff --git a/Assets/VRM_Samples/SimpleViewer/Plugins.meta b/Assets/VRM_Samples/SimpleViewer/Plugins.meta new file mode 100644 index 000000000..fdecce026 --- /dev/null +++ b/Assets/VRM_Samples/SimpleViewer/Plugins.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: ccb1849bc34bcd740ba2e17462125200 +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/VRM_Samples/SimpleViewer/Plugins/OpenFile.jslib b/Assets/VRM_Samples/SimpleViewer/Plugins/OpenFile.jslib new file mode 100644 index 000000000..48ba0ce57 --- /dev/null +++ b/Assets/VRM_Samples/SimpleViewer/Plugins/OpenFile.jslib @@ -0,0 +1,21 @@ +mergeInto(LibraryManager.library, { + WebGLFileDialog: function () { + const file_input_id = "file-input"; + var file_input = document.getElementById(file_input_id); + if (!file_input) { + file_input = document.createElement('input'); + file_input.setAttribute('type', 'file'); + file_input.setAttribute('id', file_input_id); + // file_input.setAttribute('accept', '.vrm') + file_input.style.visibility = 'hidden'; + file_input.onclick = function (event) { + event.target.value = null; + }; + file_input.onchange = function (event) { + SendMessage('Canvas', 'FileSelected', URL.createObjectURL(event.target.files[0])); + } + document.body.appendChild(file_input); + } + file_input.click(); + }, +}); \ No newline at end of file diff --git a/Assets/VRM_Samples/SimpleViewer/Plugins/OpenFile.jslib.meta b/Assets/VRM_Samples/SimpleViewer/Plugins/OpenFile.jslib.meta new file mode 100644 index 000000000..ee0cd7c4f --- /dev/null +++ b/Assets/VRM_Samples/SimpleViewer/Plugins/OpenFile.jslib.meta @@ -0,0 +1,32 @@ +fileFormatVersion: 2 +guid: 2e8941ad33d65584f8ef2f8b829a05e7 +PluginImporter: + externalObjects: {} + serializedVersion: 2 + iconMap: {} + executionOrder: {} + defineConstraints: [] + isPreloaded: 0 + isOverridable: 0 + isExplicitlyReferenced: 0 + validateReferences: 1 + platformData: + - first: + Any: + second: + enabled: 0 + settings: {} + - first: + Editor: Editor + second: + enabled: 0 + settings: + DefaultValueInitialized: true + - first: + WebGL: WebGL + second: + enabled: 1 + settings: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/VRM_Samples/SimpleViewer/ViewerUI.cs b/Assets/VRM_Samples/SimpleViewer/ViewerUI.cs index d7ea46692..b9e034fdc 100644 --- a/Assets/VRM_Samples/SimpleViewer/ViewerUI.cs +++ b/Assets/VRM_Samples/SimpleViewer/ViewerUI.cs @@ -1,6 +1,8 @@ using System; +using System.Collections; using System.IO; using System.Linq; +using System.Runtime.InteropServices; using System.Threading.Tasks; using UniGLTF; using UniHumanoid; @@ -11,10 +13,13 @@ using VRMShaders; namespace VRM.SimpleViewer { - - public class ViewerUI : MonoBehaviour { +#if UNITY_WEBGL + [DllImport("__Internal")] + private static extern void WebGLFileDialog(); +#endif + #region UI [SerializeField] Text m_version = default; @@ -353,10 +358,29 @@ namespace VRM.SimpleViewer } } + IEnumerator LoadTexture(string url) + { + var www = new WWW(url); + yield return www; + LoadModelAsync("tmp.vrm", www.bytes); + } + + public void FileSelected(string url) + { + Debug.Log($"FileSelected: {url}"); + StartCoroutine(LoadTexture(url)); + } + void OnOpenClicked() { #if UNITY_STANDALONE_WIN var path = FileDialogForWindows.FileDialog("open VRM", "vrm", "glb", "bvh", "gltf", "zip"); +#elif UNITY_WEBGL + { + WebGLFileDialog(); + return; + } + var path = ""; #elif UNITY_EDITOR var path = UnityEditor.EditorUtility.OpenFilePanel("Open VRM", "", "vrm"); #else @@ -370,8 +394,11 @@ namespace VRM.SimpleViewer LoadModelAsync(path); } - async void LoadModelAsync(string path) + async void LoadModelAsync(string path, byte[] bytes = null) { + var size = bytes != null ? bytes.Length : 0; + Debug.Log($"LoadModelAsync: {path}: {size}bytes"); + var ext = Path.GetExtension(path).ToLower(); switch (ext) { @@ -379,7 +406,7 @@ namespace VRM.SimpleViewer case ".glb": case ".zip": { - var instance = await GltfUtility.LoadAsync(path, + var instance = await GltfUtility.LoadBytesAsync(path, bytes, GetIAwaitCaller(m_useAsync.isOn), GetGltfMaterialGenerator(m_useUrpMaterial.isOn)); break; @@ -389,7 +416,7 @@ namespace VRM.SimpleViewer { VrmUtility.MaterialGeneratorCallback materialCallback = (VRM.glTF_VRM_extensions vrm) => GetVrmMaterialGenerator(m_useUrpMaterial.isOn, vrm); VrmUtility.MetaCallback metaCallback = m_texts.UpdateMeta; - var instance = await VrmUtility.LoadAsync(path, GetIAwaitCaller(m_useAsync.isOn), materialCallback, metaCallback, loadAnimation: m_loadAnimation.isOn); + var instance = await VrmUtility.LoadBytesAsync(path, bytes, GetIAwaitCaller(m_useAsync.isOn), materialCallback, metaCallback, loadAnimation: m_loadAnimation.isOn); SetModel(instance); break; } @@ -433,7 +460,11 @@ namespace VRM.SimpleViewer { if (useAsync) { +#if UNITY_WEBGL + return new RuntimeOnlyNoThreadAwaitCaller(); +#else return new RuntimeOnlyAwaitCaller(); +#endif } else {