diff --git a/Assets/UniGLTF/MeshUtility/Editor/ExportDialog/ExportDialogState.cs b/Assets/UniGLTF/MeshUtility/Editor/ExportDialog/ExportDialogState.cs index 0ae1dd4d3c..26fb20e708 100644 --- a/Assets/UniGLTF/MeshUtility/Editor/ExportDialog/ExportDialogState.cs +++ b/Assets/UniGLTF/MeshUtility/Editor/ExportDialog/ExportDialogState.cs @@ -41,8 +41,16 @@ public GameObject ExportRoot if (value != null && AssetDatabase.IsMainAsset(value)) { assetPath = AssetDatabase.GetAssetPath(value); - isPrefab = true; - value = PrefabUtility.LoadPrefabContents(assetPath); + try + { + var prefab = PrefabUtility.LoadPrefabContents(assetPath); + value = prefab; + isPrefab = true; + } + catch (ArgumentException ex) + { + // Debug.LogWarning(ex); + } } if (m_root.GameObject == value) { diff --git a/Assets/UniGLTF/Runtime/Extensions/ArrayExtensions.cs b/Assets/UniGLTF/Runtime/Extensions/ArrayExtensions.cs index 2687025e7d..0f8b857350 100644 --- a/Assets/UniGLTF/Runtime/Extensions/ArrayExtensions.cs +++ b/Assets/UniGLTF/Runtime/Extensions/ArrayExtensions.cs @@ -156,5 +156,6 @@ public static ArraySegment Slice(this ArraySegment self, int start) } return self.Slice(start, self.Count - start); } + } } diff --git a/Assets/UniGLTF/Runtime/UniGLTF/IO/MaterialIO/MaterialExporter.cs b/Assets/UniGLTF/Runtime/UniGLTF/IO/MaterialIO/MaterialExporter.cs index b319014181..20a5ea7b97 100644 --- a/Assets/UniGLTF/Runtime/UniGLTF/IO/MaterialIO/MaterialExporter.cs +++ b/Assets/UniGLTF/Runtime/UniGLTF/IO/MaterialIO/MaterialExporter.cs @@ -15,21 +15,21 @@ public enum glTFBlendMode public interface IMaterialExporter { - glTFMaterial ExportMaterial(Material m, TextureExporter textureManager); + glTFMaterial ExportMaterial(Material m, TextureExporter textureExporter); } public class MaterialExporter : IMaterialExporter { - public virtual glTFMaterial ExportMaterial(Material m, TextureExporter textureManager) + public virtual glTFMaterial ExportMaterial(Material m, TextureExporter textureExporter) { var material = CreateMaterial(m); // common params material.name = m.name; - Export_Color(m, textureManager, material); - Export_Emission(m, textureManager, material); - Export_Normal(m, textureManager, material); - Export_OcclusionMetallicRoughness(m, textureManager, material); + Export_Color(m, textureExporter, material); + Export_Emission(m, textureExporter, material); + Export_Normal(m, textureExporter, material); + Export_OcclusionMetallicRoughness(m, textureExporter, material); return material; } diff --git a/Assets/UniGLTF/Runtime/UniGLTF/IO/gltfExporter.cs b/Assets/UniGLTF/Runtime/UniGLTF/IO/gltfExporter.cs index 1bdb2f0608..3f54a66c51 100644 --- a/Assets/UniGLTF/Runtime/UniGLTF/IO/gltfExporter.cs +++ b/Assets/UniGLTF/Runtime/UniGLTF/IO/gltfExporter.cs @@ -4,11 +4,11 @@ using UnityEngine; using VRMShaders; + namespace UniGLTF { public class gltfExporter : IDisposable { - protected glTF glTF; public GameObject Copy diff --git a/Assets/VRM10/Editor/ScriptedImporter/VrmScriptedImporterEditorGUI.cs b/Assets/VRM10/Editor/ScriptedImporter/VrmScriptedImporterEditorGUI.cs index 5a627919c3..60f1d21397 100644 --- a/Assets/VRM10/Editor/ScriptedImporter/VrmScriptedImporterEditorGUI.cs +++ b/Assets/VRM10/Editor/ScriptedImporter/VrmScriptedImporterEditorGUI.cs @@ -18,14 +18,17 @@ public class VrmScriptedImporterEditorGUI : ScriptedImporterEditor VrmLib.Model m_model; UniGLTF.Extensions.VRMC_vrm.VRMC_vrm m_vrm; + string m_message; + public override void OnEnable() { base.OnEnable(); m_importer = target as VrmScriptedImporter; - m_parser = VrmScriptedImporterImpl.Parse(m_importer.assetPath, m_importer.MigrateToVrm1); - if (m_parser == null) + m_message = VrmScriptedImporterImpl.TryParseOrMigrate(m_importer.assetPath, m_importer.MigrateToVrm1, out m_parser); + if (string.IsNullOrEmpty(m_message)) { + // ok return; } if (!UniGLTF.Extensions.VRMC_vrm.GltfDeserializer.TryGet(m_parser.GLTF.extensions, out m_vrm)) @@ -45,6 +48,11 @@ enum Tabs public override void OnInspectorGUI() { + if (!string.IsNullOrEmpty(m_message)) + { + EditorGUILayout.HelpBox(m_message, MessageType.Error); + } + s_currentTab = MeshUtility.TabBar.OnGUI(s_currentTab); GUILayout.Space(10); diff --git a/Assets/VRM10/Editor/ScriptedImporter/VrmScriptedImporterImpl.cs b/Assets/VRM10/Editor/ScriptedImporter/VrmScriptedImporterImpl.cs index 93eae8c74e..434003be03 100644 --- a/Assets/VRM10/Editor/ScriptedImporter/VrmScriptedImporterImpl.cs +++ b/Assets/VRM10/Editor/ScriptedImporter/VrmScriptedImporterImpl.cs @@ -2,6 +2,8 @@ using UnityEngine; using UniGLTF; using System.IO; +using System; +using UniJSON; #if UNITY_2020_2_OR_NEWER using UnityEditor.AssetImporters; #else @@ -19,38 +21,71 @@ public static class VrmScriptedImporterImpl /// /// /// - public static GltfParser Parse(string path, bool migrateToVrm1) + public static string TryParseOrMigrate(string path, bool migrateToVrm1, out GltfParser parser) { // // Parse(parse glb, parser gltf json) // - var parser = new GltfParser(); + parser = new GltfParser(); parser.ParsePath(path); if (UniGLTF.Extensions.VRMC_vrm.GltfDeserializer.TryGet(parser.GLTF.extensions, out UniGLTF.Extensions.VRMC_vrm.VRMC_vrm vrm)) { - return parser; + // success + return default; } - if (migrateToVrm1) + if (!migrateToVrm1) { - // try migrateion - var migrated = MigrationVrm.Migrate(File.ReadAllBytes(path)); - parser = new GltfParser(); - parser.Parse(path, migrated); - return parser; + return "vrm1 not found"; } - return null; + // try migrateion + Byte[] migrated = default; + try + { + var src = File.ReadAllBytes(path); + var glb = UniGLTF.Glb.Parse(src); + var json = glb.Json.Bytes.ParseAsJson(); + if (!json.TryGet("extensions", out JsonNode extensions)) + { + return "no gltf.extensions"; + } + if (!extensions.TryGet("VRM", out JsonNode vrm0)) + { + return "vrm0 not found"; + } + + migrated = MigrationVrm.Migrate(json, glb.Binary.Bytes); + if (migrated == null) + { + return "cannot migrate"; + } + } + catch (Exception) + { + return "migration error"; + } + + parser = new GltfParser(); + parser.Parse(path, migrated); + if (UniGLTF.Extensions.VRMC_vrm.GltfDeserializer.TryGet(parser.GLTF.extensions, out vrm)) + { + // success + return default; + } + + parser = default; + return "migrate but no vrm1. unknown"; } public static void Import(ScriptedImporter scriptedImporter, AssetImportContext context, bool migrateToVrm1) { -#if VRM_DEVELOP +#if VRM_DEVELOP Debug.Log("OnImportAsset to " + scriptedImporter.assetPath); #endif - var parser = Parse(scriptedImporter.assetPath, migrateToVrm1); - if (parser == null) + var message = TryParseOrMigrate(scriptedImporter.assetPath, migrateToVrm1, out GltfParser parser); + if (!string.IsNullOrEmpty(message)) { // fail to parse vrm1 return; diff --git a/Assets/VRM10/Editor/Vrm10ExportDialog.cs b/Assets/VRM10/Editor/Vrm10ExportDialog.cs index de2d5665f4..90f8768b3e 100644 --- a/Assets/VRM10/Editor/Vrm10ExportDialog.cs +++ b/Assets/VRM10/Editor/Vrm10ExportDialog.cs @@ -4,9 +4,11 @@ using System.Linq; using System.Reflection; using MeshUtility; +using UniGLTF; using UnityEditor; using UnityEngine; using VrmLib; +using VRMShaders; namespace UniVRM10 { @@ -300,8 +302,8 @@ void OnExportClicked(GameObject root) try { - var exporter = new UniVRM10.RuntimeVrmConverter(); - var model = exporter.ToModelFrom10(root, Meta ? Meta : m_tmpMeta); + var converter = new UniVRM10.RuntimeVrmConverter(); + var model = converter.ToModelFrom10(root); // if (MeshUtility.Validators.HumanoidValidator.HasRotationOrScale(root)) // { @@ -315,7 +317,13 @@ void OnExportClicked(GameObject root) m_logLabel += $"convert to right handed coordinate...\n"; model.ConvertCoordinate(VrmLib.Coordinates.Vrm1, ignoreVrm: false); - var exportedBytes = GetGlb(model); + // export vrm-1.0 + var exporter = new UniVRM10.Vrm10Exporter(AssetTextureUtil.IsTextureEditorAsset); + var option = new VrmLib.ExportArgs(); + exporter.Export(root, model, converter, option, Meta ? Meta : m_tmpMeta); + + var exportedBytes = exporter.Storage.ToBytes(); + m_logLabel += $"write to {path}...\n"; File.WriteAllBytes(path, exportedBytes); Debug.Log("exportedBytes: " + exportedBytes.Length); @@ -334,23 +342,9 @@ void OnExportClicked(GameObject root) } } - static byte[] GetGlb(VrmLib.Model model) - { - // export vrm-1.0 - var exporter = new UniVRM10.Vrm10Exporter(); - var option = new VrmLib.ExportArgs - { - // vrm = false - }; - var glbBytes10 = exporter.Export(model, option); - // ? - var glb10 = UniGLTF.Glb.Parse(glbBytes10); - return glb10.ToBytes(); - } - static string ToAssetPath(string path) { - var assetPath = UnityPath.FromFullpath(path); + var assetPath = UniGLTF.UnityPath.FromFullpath(path); return assetPath.Value; } } diff --git a/Assets/VRM10/Runtime/Components/VRM10ControllerExpression.cs b/Assets/VRM10/Runtime/Components/VRM10ControllerExpression.cs index c1254b5f59..e023752660 100644 --- a/Assets/VRM10/Runtime/Components/VRM10ControllerExpression.cs +++ b/Assets/VRM10/Runtime/Components/VRM10ControllerExpression.cs @@ -31,12 +31,17 @@ public sealed class VRM10ControllerExpression public float LookAtOverrideRate { get; private set; } public float MouthOverrideRate { get; private set; } + int m_debugCount; + internal void Setup(Transform transform, ILookAtEyeDirectionProvider eyeDirectionProvider, ILookAtEyeDirectionApplicable eyeDirectionApplicable) { if (ExpressionAvatar == null) { -#if VRM_DEVELOP - Debug.LogWarning($"{nameof(VRM10ControllerExpression)}.{nameof(ExpressionAvatar)} is null."); +#if VRM_DEVELOP + if (m_debugCount++ == 0) + { + Debug.LogWarning($"{nameof(VRM10ControllerExpression)}.{nameof(ExpressionAvatar)} is null."); + } #endif return; } diff --git a/Assets/VRM10/Runtime/IO/ModelExtensions.cs b/Assets/VRM10/Runtime/IO/ModelExtensions.cs index 7ed669d129..3f8a292048 100644 --- a/Assets/VRM10/Runtime/IO/ModelExtensions.cs +++ b/Assets/VRM10/Runtime/IO/ModelExtensions.cs @@ -7,13 +7,13 @@ public static class ModelExtensions public static byte[] ToGlb(this VrmLib.Model model) { // export vrm-1.0 - var exporter10 = new Vrm10Exporter(); + var exporter10 = new Vrm10Exporter(_ => false); var option = new VrmLib.ExportArgs { // vrm = false }; - var glbBytes10 = exporter10.Export(model, option); - var glb10 = UniGLTF.Glb.Parse(glbBytes10); + exporter10.Export(null, model, null, option); + var glb10 = UniGLTF.Glb.Parse(exporter10.Storage.ToBytes()); return glb10.ToBytes(); } } diff --git a/Assets/VRM10/Runtime/IO/RuntimeUnityBuilder.cs b/Assets/VRM10/Runtime/IO/RuntimeUnityBuilder.cs index 486390cc15..0b63716f2b 100644 --- a/Assets/VRM10/Runtime/IO/RuntimeUnityBuilder.cs +++ b/Assets/VRM10/Runtime/IO/RuntimeUnityBuilder.cs @@ -18,17 +18,10 @@ public class RuntimeUnityBuilder : UniGLTF.ImporterContext UniGLTF.Extensions.VRMC_vrm.VRMC_vrm m_vrm; - List<(string, UnityEngine.Object)> m_external = new List<(string, UnityEngine.Object)>(); - public RuntimeUnityBuilder(UniGLTF.GltfParser parser, IEnumerable<(string, UnityEngine.Object)> externalObjectMap = null) : base(parser, externalObjectMap) { m_model = VrmLoader.CreateVrmModel(parser); - if (externalObjectMap != null) - { - m_external.AddRange(externalObjectMap); - } - // for `VRMC_materials_mtoon` this.GltfMaterialImporter.GltfMaterialParamProcessors.Insert(0, Vrm10MToonMaterialImporter.TryCreateParam); @@ -233,20 +226,22 @@ protected override async Task OnLoadHierarchy(IAwaitCaller awaitCaller, Func x.Item2 as VRM10MetaObject).FirstOrDefault(x => x != null); - // external meta != null のとき m_meta は null になる - if (controller.Meta != null) + if (e.Preset == UniGLTF.Extensions.VRMC_vrm.ExpressionPreset.custom) { - // texture の 取得 - if (Vrm10MToonMaterialImporter.TryGetMetaThumbnailTextureImportParam(Parser, vrm, out VRMShaders.TextureImportParam param)) - { - var texture = await TextureFactory.GetTextureAsync(param); - } + return ExpressionKey.CreateCustom(e.Name); + } + else + { + return ExpressionKey.CreateFromPreset(e.Preset); } - else if (vrm.Meta != null) + } + + async Task LoadVrmAsync(IAwaitCaller awaitCaller, VRM10Controller controller, UniGLTF.Extensions.VRMC_vrm.VRMC_vrm vrm) + { + // meta + if (vrm.Meta != null) { var src = vrm.Meta; m_meta = ScriptableObject.CreateInstance(); @@ -286,8 +281,7 @@ async Task LoadVrmAsync(IAwaitCaller awaitCaller, VRM10Controller controller, Un } // expression - controller.Expression.ExpressionAvatar = m_external.Select(x => x.Item2 as VRM10ExpressionAvatar).FirstOrDefault(x => x != null); - if (controller.Expression.ExpressionAvatar == null && vrm.Expressions != null) + if (vrm.Expressions != null) { controller.Expression.ExpressionAvatar = ScriptableObject.CreateInstance(); @@ -299,7 +293,7 @@ async Task LoadVrmAsync(IAwaitCaller awaitCaller, VRM10Controller controller, Un var clip = ScriptableObject.CreateInstance(); clip.Preset = expression.Preset; clip.ExpressionName = expression.Name; - clip.name = expression.ExtractKey(); + clip.name = Key(expression).ExtractKey; clip.IsBinary = expression.IsBinary.GetValueOrDefault(); clip.OverrideBlink = expression.OverrideBlink; clip.OverrideLookAt = expression.OverrideLookAt; @@ -573,15 +567,12 @@ public override void TransferOwnership(Func take) m_humanoid = null; } - if (m_meta != null) + if (take(m_meta)) { - if (take(m_meta)) - { - m_meta = null; - } + m_meta = null; } - if (m_exressionAvatar != null) + if (m_exressionAvatar != null && m_exressionAvatar.Clips != null) { foreach (var x in m_exressionAvatar.Clips) { diff --git a/Assets/VRM10/Runtime/IO/RuntimeVrmConverter.cs b/Assets/VRM10/Runtime/IO/RuntimeVrmConverter.cs index 738ef51e74..a1cc905f2d 100644 --- a/Assets/VRM10/Runtime/IO/RuntimeVrmConverter.cs +++ b/Assets/VRM10/Runtime/IO/RuntimeVrmConverter.cs @@ -20,20 +20,10 @@ public class RuntimeVrmConverter /// /// metaObject が null のときは、root から取得する /// - public VrmLib.Model ToModelFrom10(GameObject root, VRM10MetaObject metaObject = null) + public VrmLib.Model ToModelFrom10(GameObject root) { Model = new VrmLib.Model(VrmLib.Coordinates.Unity); - if (metaObject is null) - { - var vrmController = root.GetComponent(); - if (vrmController is null || vrmController.Meta is null) - { - throw new NullReferenceException("metaObject is null"); - } - metaObject = vrmController.Meta; - } - ToGlbModel(root); // humanoid diff --git a/Assets/VRM10/Runtime/IO/Vrm10Exporter.cs b/Assets/VRM10/Runtime/IO/Vrm10Exporter.cs index 2de6c1ae74..82f6de8562 100644 --- a/Assets/VRM10/Runtime/IO/Vrm10Exporter.cs +++ b/Assets/VRM10/Runtime/IO/Vrm10Exporter.cs @@ -2,18 +2,22 @@ using System.Collections.Generic; using System.Linq; using UniGLTF; -using UniJSON; +using UnityEngine; using VrmLib; +using VRMShaders; + namespace UniVRM10 { - public class Vrm10Exporter + public class Vrm10Exporter : IDisposable { public readonly Vrm10Storage Storage = new Vrm10Storage(); public readonly string VrmExtensionName = "VRMC_vrm"; - public Vrm10Exporter() + TextureExporter m_textureExporter; + + public Vrm10Exporter(Func useAsset) { Storage.Gltf.extensionsUsed.Add(glTF_KHR_materials_unlit.ExtensionName); Storage.Gltf.extensionsUsed.Add(glTF_KHR_texture_transform.ExtensionName); @@ -26,18 +30,13 @@ public Vrm10Exporter() { }); + + m_textureExporter = new TextureExporter(useAsset); } - public byte[] ToBytes() + public void Dispose() { - Storage.Gltf.buffers[0].byteLength = Storage.Buffers[0].Bytes.Count; - - var f = new JsonFormatter(); - UniGLTF.GltfSerializer.Serialize(f, Storage.Gltf); - var json = f.GetStoreBytes(); - - var glb = UniGLTF.Glb.Create(json, Storage.Buffers[0].Bytes); - return glb.ToBytes(); + m_textureExporter.Dispose(); } public void ExportAsset(Model model) @@ -118,5 +117,546 @@ public void ExportNodes(Node root, List nodes, List groups, Exp nodes = root.Children.Select(child => nodes.IndexOfThrow(child)).ToArray() }); } + + /// + /// revere X + /// + /// + /// + static float[] ReverseX(Vector3 v) + { + return new float[] { -v.x, v.y, v.z }; + } + + public void Export(GameObject root, Model model, RuntimeVrmConverter converter, ExportArgs option, VRM10MetaObject metaObject = null) + { + ExportAsset(model); + + /// + /// 必要な容量を先に確保 + /// (sparseは考慮してないので大きめ) + /// + { + var reserveBytes = 0; + // mesh + foreach (var g in model.MeshGroups) + { + foreach (var mesh in g.Meshes) + { + // 頂点バッファ + reserveBytes += mesh.IndexBuffer.ByteLength; + foreach (var kv in mesh.VertexBuffer) + { + reserveBytes += kv.Value.ByteLength; + } + // morph + foreach (var morph in mesh.MorphTargets) + { + foreach (var kv in morph.VertexBuffer) + { + reserveBytes += kv.Value.ByteLength; + } + } + } + } + Reserve(reserveBytes); + } + + // mesh + ExportMeshes(model.MeshGroups, model.Materials, option); + + // node + ExportNodes(model.Root, model.Nodes, model.MeshGroups, option); + + // material + var materialExporter = new Vrm10MaterialExporter(); + foreach (Material material in model.Materials) + { + var glTFMaterial = materialExporter.ExportMaterial(material, m_textureExporter); + Storage.Gltf.materials.Add(glTFMaterial); + } + + var (vrm, vrmSpringBone, thumbnailTextureIndex) = ExportVrm(root, model, converter, metaObject); + + // Extension で Texture が増える場合があるので最後に呼ぶ + for (int i = 0; i < m_textureExporter.Exported.Count; ++i) + { + var unityTexture = m_textureExporter.Exported[i]; + Storage.Gltf.PushGltfTexture(0, unityTexture); + } + + if (thumbnailTextureIndex.HasValue) + { + vrm.Meta.ThumbnailImage = Storage.Gltf.textures[thumbnailTextureIndex.Value].source; + } + + UniGLTF.Extensions.VRMC_vrm.GltfSerializer.SerializeTo(ref Storage.Gltf.extensions, vrm); + + if (vrmSpringBone != null) + { + UniGLTF.Extensions.VRMC_springBone.GltfSerializer.SerializeTo(ref Storage.Gltf.extensions, vrmSpringBone); + } + } + + (UniGLTF.Extensions.VRMC_vrm.VRMC_vrm vrm, UniGLTF.Extensions.VRMC_springBone.VRMC_springBone springBone, int? thumbnailIndex) ExportVrm(GameObject root, Model model, RuntimeVrmConverter converter, VRM10MetaObject meta) + { + var vrmController = root.GetComponent(); + + if (meta == null) + { + if (vrmController == null || vrmController.Meta == null) + { + throw new NullReferenceException("metaObject is null"); + } + meta = vrmController.Meta; + } + + var vrm = new UniGLTF.Extensions.VRMC_vrm.VRMC_vrm + { + Humanoid = new UniGLTF.Extensions.VRMC_vrm.Humanoid + { + HumanBones = new UniGLTF.Extensions.VRMC_vrm.HumanBones + { + }, + }, + Meta = new UniGLTF.Extensions.VRMC_vrm.Meta + { + AllowExcessivelySexualUsage = false, + AllowExcessivelyViolentUsage = false, + AllowPoliticalOrReligiousUsage = false, + AllowRedistribution = false, + }, + }; + + // + // required + // + ExportHumanoid(vrm, model); + var thumbnailTextureIndex = ExportMeta(vrm, meta); + + // + // optional + // + UniGLTF.Extensions.VRMC_springBone.VRMC_springBone vrmSpringBone = default; + if (vrmController != null) + { + ExportExpression(vrm, vrmController, model, converter); + ExportLookAt(vrm, vrmController); + ExportFirstPerson(vrm, vrmController, model, converter); + + vrmSpringBone = ExportSpringBone(vrmController, model, converter); + } + + return (vrm, vrmSpringBone, thumbnailTextureIndex); + } + + UniGLTF.Extensions.VRMC_node_collider.ColliderShape ExportShape(VRM10SpringBoneCollider z) + { + var shape = new UniGLTF.Extensions.VRMC_node_collider.ColliderShape(); + switch (z.ColliderType) + { + case VRM10SpringBoneColliderTypes.Sphere: + { + shape.Sphere = new UniGLTF.Extensions.VRMC_node_collider.ColliderShapeSphere + { + Radius = z.Radius, + Offset = ReverseX(z.Offset), + }; + break; + } + + case VRM10SpringBoneColliderTypes.Capsule: + { + shape.Capsule = new UniGLTF.Extensions.VRMC_node_collider.ColliderShapeCapsule + { + Radius = z.Radius, + Offset = new float[] { z.Offset.x, z.Offset.y, z.Offset.z }, + Tail = new float[] { z.Tail.x, z.Tail.y, z.Tail.z }, + }; + break; + } + } + return shape; + } + + UniGLTF.Extensions.VRMC_springBone.SpringBoneJoint ExportJoint(VRM10SpringJoint y, Func getIndexFromTransform) + { + var joint = new UniGLTF.Extensions.VRMC_springBone.SpringBoneJoint + { + Node = getIndexFromTransform(y.Transform), + HitRadius = y.m_jointRadius, + DragForce = y.m_dragForce, + Stiffness = y.m_stiffnessForce, + GravityDir = ReverseX(y.m_gravityDir), + GravityPower = y.m_gravityPower, + }; + return joint; + } + + UniGLTF.Extensions.VRMC_springBone.VRMC_springBone ExportSpringBone(VRM10Controller vrmController, Model model, RuntimeVrmConverter converter) + { + if (vrmController?.SpringBone?.Springs == null || vrmController.SpringBone.Springs.Count == 0) + { + return null; + } + + var springBone = new UniGLTF.Extensions.VRMC_springBone.VRMC_springBone + { + Springs = new List(), + }; + + Func getIndexFromTransform = t => + { + var node = converter.Nodes[t.gameObject]; + return model.Nodes.IndexOf(node); + }; + + foreach (var x in vrmController.SpringBone.Springs) + { + var spring = new UniGLTF.Extensions.VRMC_springBone.Spring + { + Name = x.Comment, + Joints = x.Joints.Select(y => ExportJoint(y, getIndexFromTransform)).ToList(), + }; + springBone.Springs.Add(spring); + + List colliders = new List(); + foreach (var y in x.ColliderGroups) + { + // node + var node = converter.Nodes[y.gameObject]; + var nodeIndex = model.Nodes.IndexOf(node); + var gltfNode = Storage.Gltf.nodes[nodeIndex]; + + // VRMC_node_collider + var collider = new UniGLTF.Extensions.VRMC_node_collider.VRMC_node_collider + { + Shapes = y.Colliders.Select(ExportShape).ToList(), + }; + + // serialize + UniGLTF.Extensions.VRMC_node_collider.GltfSerializer.SerializeTo(ref gltfNode.extensions, collider); + } + spring.Colliders = colliders.ToArray(); + } + + return springBone; + } + + static UniGLTF.Extensions.VRMC_vrm.MeshAnnotation ExportMeshAnnotation(RendererFirstPersonFlags flags, Func getIndex) + { + return new UniGLTF.Extensions.VRMC_vrm.MeshAnnotation + { + Node = getIndex(flags.Renderer), + FirstPersonType = flags.FirstPersonFlag, + }; + } + + void ExportFirstPerson(UniGLTF.Extensions.VRMC_vrm.VRMC_vrm vrm, VRM10Controller vrmController, Model model, RuntimeVrmConverter converter) + { + if (vrmController?.FirstPerson == null) + { + return; + } + + vrm.FirstPerson = new UniGLTF.Extensions.VRMC_vrm.FirstPerson + { + MeshAnnotations = new List(), + }; + Func getIndex = r => + { + var node = converter.Nodes[r.gameObject]; + return model.Nodes.IndexOf(node); + }; + foreach (var f in vrmController.FirstPerson.Renderers) + { + vrm.FirstPerson.MeshAnnotations.Add(ExportMeshAnnotation(f, getIndex)); + } + } + + UniGLTF.Extensions.VRMC_vrm.LookAtRangeMap ExportLookAtRangeMap(CurveMapper mapper) + { + return new UniGLTF.Extensions.VRMC_vrm.LookAtRangeMap + { + InputMaxValue = mapper.CurveXRangeDegree, + OutputScale = mapper.CurveYRangeDegree, + }; + } + + void ExportLookAt(UniGLTF.Extensions.VRMC_vrm.VRMC_vrm vrm, VRM10Controller vrmController) + { + if (vrmController?.LookAt == null) + { + return; + } + + vrm.LookAt = new UniGLTF.Extensions.VRMC_vrm.LookAt + { + LookAtType = vrmController.LookAt.LookAtType, + OffsetFromHeadBone = new float[]{ + vrmController.LookAt.OffsetFromHead.x , + vrmController.LookAt.OffsetFromHead.y , + vrmController.LookAt.OffsetFromHead.z , + }, + LookAtHorizontalInner = ExportLookAtRangeMap(vrmController.LookAt.HorizontalInner), + LookAtHorizontalOuter = ExportLookAtRangeMap(vrmController.LookAt.HorizontalOuter), + LookAtVerticalDown = ExportLookAtRangeMap(vrmController.LookAt.VerticalDown), + LookAtVerticalUp = ExportLookAtRangeMap(vrmController.LookAt.VerticalUp), + }; + } + + UniGLTF.Extensions.VRMC_vrm.MorphTargetBind ExportMorphTargetBinding(MorphTargetBinding binding, Func getIndex) + { + return new UniGLTF.Extensions.VRMC_vrm.MorphTargetBind + { + Node = getIndex(binding.RelativePath), + Index = binding.Index, + Weight = binding.Weight, + }; + } + + UniGLTF.Extensions.VRMC_vrm.MaterialColorBind ExportMaterialColorBinding(MaterialColorBinding binding, Func getIndex) + { + return new UniGLTF.Extensions.VRMC_vrm.MaterialColorBind + { + Material = getIndex(binding.MaterialName), + Type = binding.BindType, + TargetValue = new float[] { binding.TargetValue.x, binding.TargetValue.y, binding.TargetValue.z, binding.TargetValue.w }, + }; + } + + UniGLTF.Extensions.VRMC_vrm.TextureTransformBind ExportTextureTransformBinding(MaterialUVBinding binding, Func getIndex) + { + return new UniGLTF.Extensions.VRMC_vrm.TextureTransformBind + { + Material = getIndex(binding.MaterialName), + Offset = new float[] { binding.Offset.x, binding.Offset.y }, + Scaling = new float[] { binding.Scaling.x, binding.Scaling.y }, + }; + } + + void ExportExpression(UniGLTF.Extensions.VRMC_vrm.VRMC_vrm vrm, VRM10Controller vrmController, Model model, RuntimeVrmConverter converter) + { + if (vrmController?.Expression?.ExpressionAvatar?.Clips == null) + { + return; + } + + Func getIndexFromRelativePath = relativePath => + { + var rendererNode = vrmController.transform.GetFromPath(relativePath); + var node = converter.Nodes[rendererNode.gameObject]; + return model.Nodes.IndexOf(node); + }; + Func getIndexFromMaterialName = materialName => + { + for (int i = 0; i < model.Materials.Count; ++i) + { + var m = model.Materials[i] as Material; + if (m.name == materialName) + { + return i; + } + } + throw new KeyNotFoundException(); + }; + + vrm.Expressions = new List(); + foreach (var e in vrmController.Expression.ExpressionAvatar.Clips) + { + var vrmExpression = new UniGLTF.Extensions.VRMC_vrm.Expression + { + Preset = e.Preset, + Name = e.ExpressionName, + IsBinary = e.IsBinary, + OverrideBlink = e.OverrideBlink, + OverrideLookAt = e.OverrideLookAt, + OverrideMouth = e.OverrideMouth, + MorphTargetBinds = new List(), + MaterialColorBinds = new List(), + TextureTransformBinds = new List(), + }; + foreach (var b in e.MorphTargetBindings) + { + try + { + vrmExpression.MorphTargetBinds.Add(ExportMorphTargetBinding(b, getIndexFromRelativePath)); + } + catch (Exception ex) + { + Debug.LogWarning(ex); + } + } + foreach (var b in e.MaterialColorBindings) + { + try + { + vrmExpression.MaterialColorBinds.Add(ExportMaterialColorBinding(b, getIndexFromMaterialName)); + } + catch (Exception ex) + { + Debug.LogWarning(ex); + } + } + foreach (var b in e.MaterialUVBindings) + { + try + { + vrmExpression.TextureTransformBinds.Add(ExportTextureTransformBinding(b, getIndexFromMaterialName)); + } + catch (Exception ex) + { + Debug.LogWarning(ex); + } + } + vrm.Expressions.Add(vrmExpression); + } + } + + int? ExportMeta(UniGLTF.Extensions.VRMC_vrm.VRMC_vrm vrm, VRM10MetaObject meta) + { + vrm.Meta.Name = meta.Name; + vrm.Meta.Version = meta.Version; + vrm.Meta.Authors = meta.Authors.ToList(); + vrm.Meta.CopyrightInformation = meta.CopyrightInformation; + vrm.Meta.ContactInformation = meta.ContactInformation; + vrm.Meta.References = meta.References.ToList(); + // vrm.Meta.ThirdPartyLicenses = + vrm.Meta.AvatarPermission = meta.AllowedUser; + vrm.Meta.AllowExcessivelyViolentUsage = meta.ViolentUsage; + vrm.Meta.AllowExcessivelySexualUsage = meta.SexualUsage; + vrm.Meta.CommercialUsage = meta.CommercialUsage; + vrm.Meta.AllowPoliticalOrReligiousUsage = meta.PoliticalOrReligiousUsage; + vrm.Meta.CreditNotation = meta.CreditNotation; + vrm.Meta.AllowRedistribution = meta.Redistribution; + vrm.Meta.Modification = meta.ModificationLicense; + vrm.Meta.OtherLicenseUrl = meta.OtherLicenseUrl; + int? thumbnailTextureIndex = default; + if (meta.Thumbnail != null) + { + thumbnailTextureIndex = m_textureExporter.ExportSRGB(meta.Thumbnail); + } + return thumbnailTextureIndex; + } + + void ExportHumanoid(UniGLTF.Extensions.VRMC_vrm.VRMC_vrm vrm, Model model) + { + // humanoid + for (int i = 0; i < model.Nodes.Count; ++i) + { + var bone = model.Nodes[i]; + switch (bone.HumanoidBone) + { + case HumanoidBones.hips: vrm.Humanoid.HumanBones.Hips = new UniGLTF.Extensions.VRMC_vrm.HumanBone { Node = i }; break; + case HumanoidBones.spine: vrm.Humanoid.HumanBones.Spine = new UniGLTF.Extensions.VRMC_vrm.HumanBone { Node = i }; break; + + case HumanoidBones.chest: vrm.Humanoid.HumanBones.Chest = new UniGLTF.Extensions.VRMC_vrm.HumanBone { Node = i }; break; + + case HumanoidBones.upperChest: vrm.Humanoid.HumanBones.UpperChest = new UniGLTF.Extensions.VRMC_vrm.HumanBone { Node = i }; break; + + case HumanoidBones.neck: vrm.Humanoid.HumanBones.Neck = new UniGLTF.Extensions.VRMC_vrm.HumanBone { Node = i }; break; + + case HumanoidBones.head: vrm.Humanoid.HumanBones.Head = new UniGLTF.Extensions.VRMC_vrm.HumanBone { Node = i }; break; + + case HumanoidBones.leftEye: vrm.Humanoid.HumanBones.LeftEye = new UniGLTF.Extensions.VRMC_vrm.HumanBone { Node = i }; break; + + case HumanoidBones.rightEye: vrm.Humanoid.HumanBones.RightEye = new UniGLTF.Extensions.VRMC_vrm.HumanBone { Node = i }; break; + + case HumanoidBones.jaw: vrm.Humanoid.HumanBones.Jaw = new UniGLTF.Extensions.VRMC_vrm.HumanBone { Node = i }; break; + + case HumanoidBones.leftUpperLeg: vrm.Humanoid.HumanBones.LeftUpperLeg = new UniGLTF.Extensions.VRMC_vrm.HumanBone { Node = i }; break; + + case HumanoidBones.leftLowerLeg: vrm.Humanoid.HumanBones.LeftLowerLeg = new UniGLTF.Extensions.VRMC_vrm.HumanBone { Node = i }; break; + + case HumanoidBones.leftFoot: vrm.Humanoid.HumanBones.LeftFoot = new UniGLTF.Extensions.VRMC_vrm.HumanBone { Node = i }; break; + + case HumanoidBones.leftToes: vrm.Humanoid.HumanBones.LeftToes = new UniGLTF.Extensions.VRMC_vrm.HumanBone { Node = i }; break; + + case HumanoidBones.rightUpperLeg: vrm.Humanoid.HumanBones.RightUpperLeg = new UniGLTF.Extensions.VRMC_vrm.HumanBone { Node = i }; break; + + case HumanoidBones.rightLowerLeg: vrm.Humanoid.HumanBones.RightLowerLeg = new UniGLTF.Extensions.VRMC_vrm.HumanBone { Node = i }; break; + + case HumanoidBones.rightFoot: vrm.Humanoid.HumanBones.RightFoot = new UniGLTF.Extensions.VRMC_vrm.HumanBone { Node = i }; break; + + case HumanoidBones.rightToes: vrm.Humanoid.HumanBones.RightToes = new UniGLTF.Extensions.VRMC_vrm.HumanBone { Node = i }; break; + + case HumanoidBones.leftShoulder: vrm.Humanoid.HumanBones.LeftShoulder = new UniGLTF.Extensions.VRMC_vrm.HumanBone { Node = i }; break; + + case HumanoidBones.leftUpperArm: vrm.Humanoid.HumanBones.LeftUpperArm = new UniGLTF.Extensions.VRMC_vrm.HumanBone { Node = i }; break; + + case HumanoidBones.leftLowerArm: vrm.Humanoid.HumanBones.LeftLowerArm = new UniGLTF.Extensions.VRMC_vrm.HumanBone { Node = i }; break; + + case HumanoidBones.leftHand: vrm.Humanoid.HumanBones.LeftHand = new UniGLTF.Extensions.VRMC_vrm.HumanBone { Node = i }; break; + + case HumanoidBones.rightShoulder: vrm.Humanoid.HumanBones.RightShoulder = new UniGLTF.Extensions.VRMC_vrm.HumanBone { Node = i }; break; + + case HumanoidBones.rightUpperArm: vrm.Humanoid.HumanBones.RightUpperArm = new UniGLTF.Extensions.VRMC_vrm.HumanBone { Node = i }; break; + + case HumanoidBones.rightLowerArm: vrm.Humanoid.HumanBones.RightLowerArm = new UniGLTF.Extensions.VRMC_vrm.HumanBone { Node = i }; break; + + case HumanoidBones.rightHand: vrm.Humanoid.HumanBones.RightHand = new UniGLTF.Extensions.VRMC_vrm.HumanBone { Node = i }; break; + + case HumanoidBones.leftThumbProximal: vrm.Humanoid.HumanBones.LeftThumbProximal = new UniGLTF.Extensions.VRMC_vrm.HumanBone { Node = i }; break; + + case HumanoidBones.leftThumbIntermediate: vrm.Humanoid.HumanBones.LeftThumbIntermediate = new UniGLTF.Extensions.VRMC_vrm.HumanBone { Node = i }; break; + + case HumanoidBones.leftThumbDistal: vrm.Humanoid.HumanBones.LeftThumbDistal = new UniGLTF.Extensions.VRMC_vrm.HumanBone { Node = i }; break; + + case HumanoidBones.leftIndexProximal: vrm.Humanoid.HumanBones.LeftIndexProximal = new UniGLTF.Extensions.VRMC_vrm.HumanBone { Node = i }; break; + + case HumanoidBones.leftIndexIntermediate: vrm.Humanoid.HumanBones.LeftIndexIntermediate = new UniGLTF.Extensions.VRMC_vrm.HumanBone { Node = i }; break; + + case HumanoidBones.leftIndexDistal: vrm.Humanoid.HumanBones.LeftIndexDistal = new UniGLTF.Extensions.VRMC_vrm.HumanBone { Node = i }; break; + + case HumanoidBones.leftMiddleProximal: vrm.Humanoid.HumanBones.LeftMiddleProximal = new UniGLTF.Extensions.VRMC_vrm.HumanBone { Node = i }; break; + + case HumanoidBones.leftMiddleIntermediate: vrm.Humanoid.HumanBones.LeftMiddleIntermediate = new UniGLTF.Extensions.VRMC_vrm.HumanBone { Node = i }; break; + + case HumanoidBones.leftMiddleDistal: vrm.Humanoid.HumanBones.LeftMiddleDistal = new UniGLTF.Extensions.VRMC_vrm.HumanBone { Node = i }; break; + + case HumanoidBones.leftRingProximal: vrm.Humanoid.HumanBones.LeftRingProximal = new UniGLTF.Extensions.VRMC_vrm.HumanBone { Node = i }; break; + + case HumanoidBones.leftRingIntermediate: vrm.Humanoid.HumanBones.LeftRingIntermediate = new UniGLTF.Extensions.VRMC_vrm.HumanBone { Node = i }; break; + + case HumanoidBones.leftRingDistal: vrm.Humanoid.HumanBones.LeftRingDistal = new UniGLTF.Extensions.VRMC_vrm.HumanBone { Node = i }; break; + + case HumanoidBones.leftLittleProximal: vrm.Humanoid.HumanBones.LeftLittleProximal = new UniGLTF.Extensions.VRMC_vrm.HumanBone { Node = i }; break; + + case HumanoidBones.leftLittleIntermediate: vrm.Humanoid.HumanBones.LeftLittleIntermediate = new UniGLTF.Extensions.VRMC_vrm.HumanBone { Node = i }; break; + + case HumanoidBones.leftLittleDistal: vrm.Humanoid.HumanBones.LeftLittleDistal = new UniGLTF.Extensions.VRMC_vrm.HumanBone { Node = i }; break; + + case HumanoidBones.rightThumbProximal: vrm.Humanoid.HumanBones.RightThumbProximal = new UniGLTF.Extensions.VRMC_vrm.HumanBone { Node = i }; break; + + case HumanoidBones.rightThumbIntermediate: vrm.Humanoid.HumanBones.RightThumbIntermediate = new UniGLTF.Extensions.VRMC_vrm.HumanBone { Node = i }; break; + + case HumanoidBones.rightThumbDistal: vrm.Humanoid.HumanBones.RightThumbDistal = new UniGLTF.Extensions.VRMC_vrm.HumanBone { Node = i }; break; + + case HumanoidBones.rightIndexProximal: vrm.Humanoid.HumanBones.RightIndexProximal = new UniGLTF.Extensions.VRMC_vrm.HumanBone { Node = i }; break; + + case HumanoidBones.rightIndexIntermediate: vrm.Humanoid.HumanBones.RightIndexIntermediate = new UniGLTF.Extensions.VRMC_vrm.HumanBone { Node = i }; break; + + case HumanoidBones.rightIndexDistal: vrm.Humanoid.HumanBones.RightIndexDistal = new UniGLTF.Extensions.VRMC_vrm.HumanBone { Node = i }; break; + + case HumanoidBones.rightMiddleProximal: vrm.Humanoid.HumanBones.RightMiddleProximal = new UniGLTF.Extensions.VRMC_vrm.HumanBone { Node = i }; break; + + case HumanoidBones.rightMiddleIntermediate: vrm.Humanoid.HumanBones.RightMiddleIntermediate = new UniGLTF.Extensions.VRMC_vrm.HumanBone { Node = i }; break; + + case HumanoidBones.rightMiddleDistal: vrm.Humanoid.HumanBones.RightMiddleDistal = new UniGLTF.Extensions.VRMC_vrm.HumanBone { Node = i }; break; + + case HumanoidBones.rightRingProximal: vrm.Humanoid.HumanBones.RightRingProximal = new UniGLTF.Extensions.VRMC_vrm.HumanBone { Node = i }; break; + + case HumanoidBones.rightRingIntermediate: vrm.Humanoid.HumanBones.RightRingIntermediate = new UniGLTF.Extensions.VRMC_vrm.HumanBone { Node = i }; break; + + case HumanoidBones.rightRingDistal: vrm.Humanoid.HumanBones.RightRingDistal = new UniGLTF.Extensions.VRMC_vrm.HumanBone { Node = i }; break; + + case HumanoidBones.rightLittleProximal: vrm.Humanoid.HumanBones.RightLittleProximal = new UniGLTF.Extensions.VRMC_vrm.HumanBone { Node = i }; break; + + case HumanoidBones.rightLittleIntermediate: vrm.Humanoid.HumanBones.RightLittleIntermediate = new UniGLTF.Extensions.VRMC_vrm.HumanBone { Node = i }; break; + + case HumanoidBones.rightLittleDistal: vrm.Humanoid.HumanBones.RightLittleDistal = new UniGLTF.Extensions.VRMC_vrm.HumanBone { Node = i }; break; + } + } + } } } diff --git a/Assets/VRM10/Runtime/IO/Vrm10ExporterExtensions.cs b/Assets/VRM10/Runtime/IO/Vrm10ExporterExtensions.cs deleted file mode 100644 index b16c742ac9..0000000000 --- a/Assets/VRM10/Runtime/IO/Vrm10ExporterExtensions.cs +++ /dev/null @@ -1,51 +0,0 @@ -using System; -using VrmLib; - -namespace UniVRM10 -{ - public static class IExporterExtensions - { - public static byte[] Export(this Vrm10Exporter exporter, Model m, ExportArgs option) - { - exporter.ExportAsset(m); - - /// - /// 必要な容量を先に確保 - /// (sparseは考慮してないので大きめ) - /// - { - var reserveBytes = 0; - // mesh - foreach (var g in m.MeshGroups) - { - foreach (var mesh in g.Meshes) - { - // 頂点バッファ - reserveBytes += mesh.IndexBuffer.ByteLength; - foreach (var kv in mesh.VertexBuffer) - { - reserveBytes += kv.Value.ByteLength; - } - // morph - foreach (var morph in mesh.MorphTargets) - { - foreach (var kv in morph.VertexBuffer) - { - reserveBytes += kv.Value.ByteLength; - } - } - } - } - exporter.Reserve(reserveBytes); - } - - // mesh - exporter.ExportMeshes(m.MeshGroups, m.Materials, option); - - // node - exporter.ExportNodes(m.Root, m.Nodes, m.MeshGroups, option); - - return exporter.ToBytes(); - } - } -} diff --git a/Assets/VRM10/Runtime/IO/Vrm10MToonMaterialImporter.cs b/Assets/VRM10/Runtime/IO/Vrm10MToonMaterialImporter.cs index de563072c8..00695284c9 100644 --- a/Assets/VRM10/Runtime/IO/Vrm10MToonMaterialImporter.cs +++ b/Assets/VRM10/Runtime/IO/Vrm10MToonMaterialImporter.cs @@ -214,7 +214,7 @@ public static IEnumerable EnumerateTexturesForMaterial(GltfP /// public static bool TryGetMetaThumbnailTextureImportParam(GltfParser parser, UniGLTF.Extensions.VRMC_vrm.VRMC_vrm vrm, out TextureImportParam value) { - if (!vrm.Meta.ThumbnailImage.HasValue) + if (vrm?.Meta == null || !vrm.Meta.ThumbnailImage.HasValue) { value = default; return false; diff --git a/Assets/VRM10/Runtime/IO/Vrm10MaterialExporter.cs b/Assets/VRM10/Runtime/IO/Vrm10MaterialExporter.cs new file mode 100644 index 0000000000..d74da30036 --- /dev/null +++ b/Assets/VRM10/Runtime/IO/Vrm10MaterialExporter.cs @@ -0,0 +1,269 @@ +using System; +using UniGLTF; +using UnityEngine; +using VRMShaders; + +namespace UniVRM10 +{ + public class Vrm10MaterialExporter : MaterialExporter + { + protected override glTFMaterial CreateMaterial(Material m) + { + switch (m.shader.name) + { + case "VRM/UnlitTexture": + return Export_VRMUnlitTexture(m); + + case "VRM/UnlitTransparent": + return Export_VRMUnlitTransparent(m); + + case "VRM/UnlitCutout": + return Export_VRMUnlitCutout(m); + + case "VRM/UnlitTransparentZWrite": + return Export_VRMUnlitTransparentZWrite(m); + + case "VRM/MToon": + return Export_VRMMToon(m); + + default: + return base.CreateMaterial(m); + } + } + + static glTFMaterial Export_VRMUnlitTexture(Material m) + { + var material = glTF_KHR_materials_unlit.CreateDefault(); + material.alphaMode = "OPAQUE"; + return material; + } + static glTFMaterial Export_VRMUnlitTransparent(Material m) + { + var material = glTF_KHR_materials_unlit.CreateDefault(); + material.alphaMode = "BLEND"; + return material; + } + static glTFMaterial Export_VRMUnlitCutout(Material m) + { + var material = glTF_KHR_materials_unlit.CreateDefault(); + material.alphaMode = "MASK"; + return material; + } + static glTFMaterial Export_VRMUnlitTransparentZWrite(Material m) + { + var material = glTF_KHR_materials_unlit.CreateDefault(); + material.alphaMode = "BLEND"; + return material; + } + + static glTFMaterial Export_VRMMToon(Material m) + { + var material = glTF_KHR_materials_unlit.CreateDefault(); + + switch (m.GetTag("RenderType", true)) + { + case "Transparent": + material.alphaMode = "BLEND"; + break; + + case "TransparentCutout": + material.alphaMode = "MASK"; + material.alphaCutoff = m.GetFloat("_Cutoff"); + break; + + default: + material.alphaMode = "OPAQUE"; + break; + } + + switch ((int)m.GetFloat("_CullMode")) + { + case 0: + material.doubleSided = true; + break; + + case 1: + Debug.LogWarning("ignore cull front"); + break; + + case 2: + // cull back + break; + + default: + throw new NotImplementedException(); + } + + return material; + } + + #region CreateFromMaterial + + static readonly string[] TAGS = new string[]{ + "RenderType", + // "Queue", + }; + + public override glTFMaterial ExportMaterial(Material m, TextureExporter textureExporter) + { + if (m.shader.name != MToon.Utils.ShaderName) + { + return base.ExportMaterial(m, textureExporter); + } + + var material = new glTFMaterial + { + name = m.name, + + emissiveFactor = new float[] { 0, 0, 0 }, + }; + + // default values + var mtoon = new UniGLTF.Extensions.VRMC_materials_mtoon.VRMC_materials_mtoon + { + Version = "", + + TransparentWithZWrite = false, + + RenderQueueOffsetNumber = 0, + + ShadeFactor = new float[] { 0, 0, 0 }, + + // ShadeMultiplyTexture; + + // Lighting + ShadingShiftFactor = 0, + + ShadingToonyFactor = 0, + + LightColorAttenuationFactor = 0, + + GiIntensityFactor = 0, + + // MatCap + // AdditiveTexture; + + // Rim + RimFactor = new float[] { 0, 0, 0 }, + + // public int? RimMultiplyTexture; + + RimLightingMixFactor = 0, + + RimFresnelPowerFactor = 0, + + RimLiftFactor = 0, + + // Outline + OutlineWidthMode = UniGLTF.Extensions.VRMC_materials_mtoon.OutlineWidthMode.none, + + OutlineWidthFactor = 0, + + // public int? OutlineWidthMultiplyTexture; + + OutlineScaledMaxDistanceFactor = 0, + + OutlineColorMode = UniGLTF.Extensions.VRMC_materials_mtoon.OutlineColorMode.fixedColor, + + OutlineFactor = new float[] { 0, 0, 0 }, + + OutlineLightingMixFactor = 0, + + // public int? UvAnimationMaskTexture; + + UvAnimationScrollXSpeedFactor = 0, + + UvAnimationScrollYSpeedFactor = 0, + + UvAnimationRotationSpeedFactor = 0, + }; + + // var prop = PreShaderPropExporter.GetPropsForSupportedShader(m.shader.name); + // if (prop == null) + // { + // Debug.LogWarningFormat("Fail to export shader: {0}", m.shader.name); + // } + // else + // { + // foreach (var keyword in m.shaderKeywords) + // { + // material.keywordMap.Add(keyword, m.IsKeywordEnabled(keyword)); + // } + + // // get properties + // //material.SetProp(prop); + // foreach (var kv in prop.Properties) + // { + // switch (kv.ShaderPropertyType) + // { + // case ShaderPropertyType.Color: + // { + // var value = m.GetColor(kv.Key).ToArray(); + // material.vectorProperties.Add(kv.Key, value); + // } + // break; + + // case ShaderPropertyType.Range: + // case ShaderPropertyType.Float: + // { + // var value = m.GetFloat(kv.Key); + // material.floatProperties.Add(kv.Key, value); + // } + // break; + + // case ShaderPropertyType.TexEnv: + // { + // var texture = m.GetTexture(kv.Key); + // if (texture != null) + // { + // var value = kv.Key == "_BumpMap" + // ? textureExporter.ExportNormal(texture) + // : textureExporter.ExportSRGB(texture) + // ; + // if (value == -1) + // { + // Debug.LogFormat("not found {0}", texture.name); + // } + // else + // { + // material.textureProperties.Add(kv.Key, value); + // } + // } + + // // offset & scaling + // var offset = m.GetTextureOffset(kv.Key); + // var scaling = m.GetTextureScale(kv.Key); + // material.vectorProperties.Add(kv.Key, + // new float[] { offset.x, offset.y, scaling.x, scaling.y }); + // } + // break; + + // case ShaderPropertyType.Vector: + // { + // var value = m.GetVector(kv.Key).ToArray(); + // material.vectorProperties.Add(kv.Key, value); + // } + // break; + + // default: + // throw new NotImplementedException(); + // } + // } + // } + + // foreach (var tag in TAGS) + // { + // var value = m.GetTag(tag, false); + // if (!String.IsNullOrEmpty(value)) + // { + // material.tagMap.Add(tag, value); + // } + // } + + UniGLTF.Extensions.VRMC_materials_mtoon.GltfSerializer.SerializeTo(ref material.extensions, mtoon); + + return material; + } + #endregion + } +} diff --git a/Assets/VRM10/Runtime/IO/Vrm10ExporterExtensions.cs.meta b/Assets/VRM10/Runtime/IO/Vrm10MaterialExporter.cs.meta similarity index 83% rename from Assets/VRM10/Runtime/IO/Vrm10ExporterExtensions.cs.meta rename to Assets/VRM10/Runtime/IO/Vrm10MaterialExporter.cs.meta index 88fdbfa522..cb3f26adf2 100644 --- a/Assets/VRM10/Runtime/IO/Vrm10ExporterExtensions.cs.meta +++ b/Assets/VRM10/Runtime/IO/Vrm10MaterialExporter.cs.meta @@ -1,5 +1,5 @@ fileFormatVersion: 2 -guid: 984cd6e6d31fcc348a71adee5a752400 +guid: f6eeec83f2a72884dae19571cf1d749b MonoImporter: externalObjects: {} serializedVersion: 2 diff --git a/Assets/VRM10/Runtime/IO/Vrm10Storage.cs b/Assets/VRM10/Runtime/IO/Vrm10Storage.cs index cf055abe57..c0328f288e 100644 --- a/Assets/VRM10/Runtime/IO/Vrm10Storage.cs +++ b/Assets/VRM10/Runtime/IO/Vrm10Storage.cs @@ -3,6 +3,8 @@ using System.Linq; using System.Numerics; using System.Runtime.InteropServices; +using UniGLTF; +using UniJSON; using VrmLib; @@ -35,6 +37,8 @@ public Vrm10Storage() { new UniGLTF.ArrayByteBuffer() }; + + Gltf.AddBuffer(Buffers[0]); } /// @@ -479,5 +483,17 @@ public ArraySegment GetBufferBytes(UniGLTF.glTFBuffer buffer) int index = Gltf.buffers.IndexOf(buffer); return Buffers[index].Bytes; } + + public byte[] ToBytes() + { + Gltf.buffers[0].byteLength = Buffers[0].Bytes.Count; + + var f = new JsonFormatter(); + UniGLTF.GltfSerializer.Serialize(f, Gltf); + var json = f.GetStoreBytes(); + + var glb = UniGLTF.Glb.Create(json, Buffers[0].Bytes); + return glb.ToBytes(); + } } } diff --git a/Assets/VRM10/Runtime/Migration/MigrationVrm.cs b/Assets/VRM10/Runtime/Migration/MigrationVrm.cs index e7afc4d1fc..48ef62c10c 100644 --- a/Assets/VRM10/Runtime/Migration/MigrationVrm.cs +++ b/Assets/VRM10/Runtime/Migration/MigrationVrm.cs @@ -14,12 +14,17 @@ public static byte[] Migrate(byte[] src) { var glb = UniGLTF.Glb.Parse(src); var json = glb.Json.Bytes.ParseAsJson(); + return Migrate(json, glb.Binary.Bytes); + } + + public static byte[] Migrate(JsonNode json, ArraySegment bin) + { var gltf = UniGLTF.GltfDeserializer.Deserialize(json); // attach glb bin to buffer foreach (var buffer in gltf.buffers) { - buffer.OpenStorage(new UniGLTF.SimpleStorage(glb.Binary.Bytes)); + buffer.OpenStorage(new UniGLTF.SimpleStorage(bin)); } // https://github.com/vrm-c/vrm-specification/issues/205 @@ -71,7 +76,8 @@ public static byte[] Migrate(byte[] src) UniGLTF.GltfSerializer.Serialize(f, gltf); vrm1Json = f.GetStoreBytes(); } - return UniGLTF.Glb.Create(vrm1Json, glb.Binary.Bytes).ToBytes(); + // JSON 部分だけが改変されて、BIN はそのまま + return UniGLTF.Glb.Create(vrm1Json, bin).ToBytes(); } public static void Check(JsonNode vrm0, UniGLTF.Extensions.VRMC_vrm.VRMC_vrm vrm1) diff --git a/Assets/VRM10/Runtime/Scenes/ExportDebugUtil.cs b/Assets/VRM10/Runtime/Scenes/ExportDebugUtil.cs index f68cc24c0a..0b29ff9bc2 100644 --- a/Assets/VRM10/Runtime/Scenes/ExportDebugUtil.cs +++ b/Assets/VRM10/Runtime/Scenes/ExportDebugUtil.cs @@ -22,12 +22,13 @@ public static void SaveVrm(VrmLib.Model model, string path) public static string GetJsonString(VrmLib.Model model) { // export vrm-1.0 - var exporter10 = new Vrm10Exporter(); + var exporter10 = new Vrm10Exporter(_ => false); var option = new VrmLib.ExportArgs { // vrm = false }; - var glbBytes10 = exporter10.Export(model, option); + exporter10.Export(null, model, null, option); + var glbBytes10 = exporter10.Storage.ToBytes(); var glb10 = UniGLTF.Glb.Parse(glbBytes10); return System.Text.Encoding.UTF8.GetString(glb10.Json.Bytes.Array, glb10.Json.Bytes.Offset, glb10.Json.Bytes.Count); } diff --git a/Assets/VRM10/Tests.PlayMode/MaterialTests.cs b/Assets/VRM10/Tests.PlayMode/MaterialTests.cs index 5b67dc155d..da39116198 100644 --- a/Assets/VRM10/Tests.PlayMode/MaterialTests.cs +++ b/Assets/VRM10/Tests.PlayMode/MaterialTests.cs @@ -50,7 +50,7 @@ public class MaterialTests private Model ToVrmModel(GameObject root) { var exporter = new UniVRM10.RuntimeVrmConverter(); - var model = exporter.ToModelFrom10(root, root.GetComponent().Meta); + var model = exporter.ToModelFrom10(root); model.ConvertCoordinate(VrmLib.Coordinates.Vrm1, ignoreVrm: false); return model; diff --git a/Assets/VRM10/vrmlib/Runtime/BufferAccessor.cs b/Assets/VRM10/vrmlib/Runtime/BufferAccessor.cs index 52a369592d..591c83e495 100644 --- a/Assets/VRM10/vrmlib/Runtime/BufferAccessor.cs +++ b/Assets/VRM10/vrmlib/Runtime/BufferAccessor.cs @@ -3,6 +3,7 @@ using System.Linq; using System.Numerics; using System.Runtime.InteropServices; +using UniGLTF; namespace VrmLib { diff --git a/Assets/VRM10/vrmlib/Runtime/ExportArgs.cs b/Assets/VRM10/vrmlib/Runtime/ExportArgs.cs index ecd2a27ae2..b700666c2f 100644 --- a/Assets/VRM10/vrmlib/Runtime/ExportArgs.cs +++ b/Assets/VRM10/vrmlib/Runtime/ExportArgs.cs @@ -5,29 +5,6 @@ namespace VrmLib [Serializable] public struct ExportArgs { - /// - /// VRM拡張をエクスポートするか - /// - /// struct で初期値をdefault以外にするために - /// nullableなpropertyを使っている - /// - bool? m_vrm; - public bool vrm - { - get - { - if (!m_vrm.HasValue) - { - m_vrm = true; - } - return m_vrm.Value; - } - set - { - m_vrm = value; - } - } - /// /// 頂点バッファにsparse機能を使うか /// diff --git a/Assets/VRM10/vrmlib/Runtime/Extensions/ArraySegmentExtensions.cs b/Assets/VRM10/vrmlib/Runtime/Extensions/ArraySegmentExtensions.cs deleted file mode 100644 index a137534d50..0000000000 --- a/Assets/VRM10/vrmlib/Runtime/Extensions/ArraySegmentExtensions.cs +++ /dev/null @@ -1,29 +0,0 @@ -using System; - -namespace VrmLib -{ - public static class ArraySegmentExtensions - { - public static ArraySegment Slice(this ArraySegment self, int start, int length) - { - if (start + length > self.Count) - { - throw new ArgumentOutOfRangeException(); - } - return new ArraySegment( - self.Array, - self.Offset + start, - length - ); - } - - public static ArraySegment Slice(this ArraySegment self, int start) - { - if (start > self.Count) - { - throw new ArgumentOutOfRangeException(); - } - return self.Slice(start, self.Count - start); - } - } -} diff --git a/Assets/VRM10/vrmlib/Runtime/Extensions/ArraySegmentExtensions.cs.meta b/Assets/VRM10/vrmlib/Runtime/Extensions/ArraySegmentExtensions.cs.meta deleted file mode 100644 index 06000f6f4c..0000000000 --- a/Assets/VRM10/vrmlib/Runtime/Extensions/ArraySegmentExtensions.cs.meta +++ /dev/null @@ -1,11 +0,0 @@ -fileFormatVersion: 2 -guid: eb18d59756b3d844d8dddda3ab391541 -MonoImporter: - externalObjects: {} - serializedVersion: 2 - defaultReferences: [] - executionOrder: 0 - icon: {instanceID: 0} - userData: - assetBundleName: - assetBundleVariant: diff --git a/Assets/VRM10/vrmlib/Runtime/VrmLib.asmdef b/Assets/VRM10/vrmlib/Runtime/VrmLib.asmdef index d409f1b933..a81041ec6b 100644 --- a/Assets/VRM10/vrmlib/Runtime/VrmLib.asmdef +++ b/Assets/VRM10/vrmlib/Runtime/VrmLib.asmdef @@ -1,6 +1,8 @@ { "name": "VrmLib", - "references": [], + "references": [ + "UniGLTF" + ], "optionalUnityReferences": [], "includePlatforms": [], "excludePlatforms": [], diff --git a/Assets/VRMShaders/GLTF/IO/Runtime/TextureExporter.cs b/Assets/VRMShaders/GLTF/IO/Runtime/TextureExporter.cs index 086bc7f6b0..43f8e7d278 100644 --- a/Assets/VRMShaders/GLTF/IO/Runtime/TextureExporter.cs +++ b/Assets/VRMShaders/GLTF/IO/Runtime/TextureExporter.cs @@ -9,7 +9,7 @@ namespace VRMShaders /// glTF にエクスポートする Texture2D を蓄えて index を確定させる。 /// Exporter の最後でまとめて Texture2D から bytes 列を得て出力する。 /// - public class TextureExporter + public class TextureExporter : IDisposable { Func m_useAsset; @@ -18,6 +18,11 @@ public TextureExporter(Func useAsset) m_useAsset = useAsset; } + public void Dispose() + { + // TODO: export 用にコピー・変換したテクスチャーをここで解放したい + } + public enum ConvertTypes { // 無変換