From 990b5b35b81d30d97cf9f9140cffe1322671d947 Mon Sep 17 00:00:00 2001 From: ousttrue Date: Thu, 7 Oct 2021 13:46:20 +0900 Subject: [PATCH 1/6] =?UTF-8?q?Vrm10Exporter=E3=82=92=E6=95=B4=E7=90=86?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- Assets/VRM10/Runtime/IO/Vrm10Exporter.cs | 185 ++++++++++++----------- 1 file changed, 96 insertions(+), 89 deletions(-) diff --git a/Assets/VRM10/Runtime/IO/Vrm10Exporter.cs b/Assets/VRM10/Runtime/IO/Vrm10Exporter.cs index 9c11abfbb..b689ff4cc 100644 --- a/Assets/VRM10/Runtime/IO/Vrm10Exporter.cs +++ b/Assets/VRM10/Runtime/IO/Vrm10Exporter.cs @@ -49,54 +49,45 @@ namespace UniVRM10 m_textureExporter.Dispose(); } - public void ExportAsset(Model model) + public static glTFAssets ExportAsset(Model model) { - Storage.Gltf.asset = new glTFAssets - { - }; - if (!string.IsNullOrEmpty(model.AssetVersion)) Storage.Gltf.asset.version = model.AssetVersion; - if (!string.IsNullOrEmpty(model.AssetMinVersion)) Storage.Gltf.asset.minVersion = model.AssetMinVersion; - - if (!string.IsNullOrEmpty(model.AssetGenerator)) Storage.Gltf.asset.generator = model.AssetGenerator; - - if (!string.IsNullOrEmpty(model.AssetCopyright)) Storage.Gltf.asset.copyright = model.AssetCopyright; + var asset = new glTFAssets(); + if (!string.IsNullOrEmpty(model.AssetVersion)) asset.version = model.AssetVersion; + if (!string.IsNullOrEmpty(model.AssetMinVersion)) asset.minVersion = model.AssetMinVersion; + if (!string.IsNullOrEmpty(model.AssetGenerator)) asset.generator = model.AssetGenerator; + if (!string.IsNullOrEmpty(model.AssetCopyright)) asset.copyright = model.AssetCopyright; + return asset; } - public void Reserve(int bytesLength) - { - Storage.Reserve(bytesLength); - } - - public void ExportMeshes(List groups, List materials, ExportArgs option) + public static IEnumerable ExportMeshes(List groups, List materials, Vrm10Storage storage, ExportArgs option) { foreach (var group in groups) { - var mesh = group.ExportMeshGroup(materials, Storage, option); - Storage.Gltf.meshes.Add(mesh); + yield return group.ExportMeshGroup(materials, storage, option); } } - public void ExportNodes(Node root, List nodes, List groups, ExportArgs option) + public static IEnumerable<(glTFNode, glTFSkin)> ExportNodes(List nodes, List groups, Vrm10Storage storage, ExportArgs option) { - foreach (var x in nodes) + foreach (var node in nodes) { - var node = new glTFNode + var gltfNode = new glTFNode { - name = x.Name, + name = node.Name, }; + glTFSkin gltfSkin = default; - node.translation = x.LocalTranslation.ToFloat3(); - node.rotation = x.LocalRotation.ToFloat4(); - node.scale = x.LocalScaling.ToFloat3(); + gltfNode.translation = node.LocalTranslation.ToFloat3(); + gltfNode.rotation = node.LocalRotation.ToFloat4(); + gltfNode.scale = node.LocalScaling.ToFloat3(); - if (x.MeshGroup != null) + if (node.MeshGroup != null) { - node.mesh = groups.IndexOfThrow(x.MeshGroup); - var skin = x.MeshGroup.Skin; + gltfNode.mesh = groups.IndexOfThrow(node.MeshGroup); + var skin = node.MeshGroup.Skin; if (skin != null) { - var skinIndex = Storage.Gltf.skins.Count; - var gltfSkin = new glTFSkin() + gltfSkin = new glTFSkin() { joints = skin.Joints.Select(joint => nodes.IndexOfThrow(joint)).ToArray() }; @@ -106,26 +97,19 @@ namespace UniVRM10 } if (skin.InverseMatrices != null) { - gltfSkin.inverseBindMatrices = skin.InverseMatrices.AddAccessorTo(Storage, 0, option.sparse); + gltfSkin.inverseBindMatrices = skin.InverseMatrices.AddAccessorTo(storage, 0, option.sparse); } if (skin.Root != null) { gltfSkin.skeleton = nodes.IndexOf(skin.Root); } - Storage.Gltf.skins.Add(gltfSkin); - node.skin = skinIndex; } } - node.children = x.Children.Select(child => nodes.IndexOfThrow(child)).ToArray(); + gltfNode.children = node.Children.Select(child => nodes.IndexOfThrow(child)).ToArray(); - Storage.Gltf.nodes.Add(node); + yield return (gltfNode, gltfSkin); } - - Storage.Gltf.scenes.Add(new gltfScene() - { - nodes = root.Children.Select(child => nodes.IndexOfThrow(child)).ToArray() - }); } /// @@ -138,55 +122,77 @@ namespace UniVRM10 return new float[] { -v.x, v.y, v.z }; } - public void Export(GameObject root, Model model, ModelExporter converter, ExportArgs option, VRM10ObjectMeta vrmMeta = null) + /// + /// 必要な容量を計算 + /// (sparseは考慮してないので大きめ) + static int CalcReserveBytes(Model model) { - ExportAsset(model); - - /// - /// 必要な容量を先に確保 - /// (sparseは考慮してないので大きめ) - /// + int reserveBytes = 0; + // mesh + foreach (var g in model.MeshGroups) { - var reserveBytes = 0; - // mesh - foreach (var g in model.MeshGroups) + foreach (var mesh in g.Meshes) { - foreach (var mesh in g.Meshes) + // 頂点バッファ + reserveBytes += mesh.IndexBuffer.ByteLength; + foreach (var kv in mesh.VertexBuffer) { - // 頂点バッファ - 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; } - // morph - foreach (var morph in mesh.MorphTargets) - { - foreach (var kv in morph.VertexBuffer) - { - reserveBytes += kv.Value.ByteLength; - } - } } } - Reserve(reserveBytes); } + return reserveBytes; + } - // material + static IEnumerable ExportMaterials(Model model, ITextureExporter textureExporter, GltfExportSettings settings) + { var materialExporter = new Vrm10MaterialExporter(); foreach (Material material in model.Materials) { - var glTFMaterial = materialExporter.ExportMaterial(material, m_textureExporter, m_settings); - Storage.Gltf.materials.Add(glTFMaterial); + yield return materialExporter.ExportMaterial(material, textureExporter, settings); + } + } + + public void Export(GameObject root, Model model, ModelExporter converter, ExportArgs option, VRM10ObjectMeta vrmMeta = null) + { + Storage.Gltf.asset = ExportAsset(model); + + Storage.Reserve(CalcReserveBytes(model)); + + foreach (var material in ExportMaterials(model, m_textureExporter, m_settings)) + { + Storage.Gltf.materials.Add(material); } - // mesh - ExportMeshes(model.MeshGroups, model.Materials, option); + foreach (var mesh in ExportMeshes(model.MeshGroups, model.Materials, Storage, option)) + { + Storage.Gltf.meshes.Add(mesh); + } - // node - ExportNodes(model.Root, model.Nodes, model.MeshGroups, option); + foreach (var (node, skin) in ExportNodes(model.Nodes, model.MeshGroups, Storage, option)) + { + Storage.Gltf.nodes.Add(node); + if (skin != null) + { + var skinIndex = Storage.Gltf.skins.Count; + Storage.Gltf.skins.Add(skin); + node.skin = skinIndex; + } + } + Storage.Gltf.scenes.Add(new gltfScene() + { + nodes = model.Root.Children.Select(child => model.Nodes.IndexOfThrow(child)).ToArray() + }); - var (vrm, vrmSpringBone, thumbnailTextureIndex) = ExportVrm(root, model, converter, vrmMeta); + var (vrm, vrmSpringBone, thumbnailTextureIndex) = ExportVrm(root, model, converter, vrmMeta, Storage.Gltf.nodes, m_textureExporter); // Extension で Texture が増える場合があるので最後に呼ぶ var exportedTextures = m_textureExporter.Export(); @@ -225,7 +231,8 @@ namespace UniVRM10 /// (UniGLTF.Extensions.VRMC_vrm.VRMC_vrm vrm, UniGLTF.Extensions.VRMC_springBone.VRMC_springBone springBone, - int? thumbnailIndex) ExportVrm(GameObject root, Model model, ModelExporter converter, VRM10ObjectMeta vrmMeta) + int? thumbnailIndex) ExportVrm(GameObject root, Model model, ModelExporter converter, + VRM10ObjectMeta vrmMeta, List nodes, ITextureExporter textureExporter) { var vrmController = root?.GetComponent(); @@ -259,7 +266,7 @@ namespace UniVRM10 // required // ExportHumanoid(vrm, model); - var thumbnailTextureIndex = ExportMeta(vrm, vrmMeta); + var thumbnailTextureIndex = ExportMeta(vrm, vrmMeta, textureExporter); // // optional @@ -272,13 +279,13 @@ namespace UniVRM10 ExportFirstPerson(vrm, vrmController, model, converter); vrmSpringBone = ExportSpringBone(vrmController, model, converter); - ExportConstraints(vrmController, model, converter); + ExportConstraints(vrmController, model, converter, nodes); } return (vrm, vrmSpringBone, thumbnailTextureIndex); } - UniGLTF.Extensions.VRMC_springBone.ColliderShape ExportShape(VRM10SpringBoneCollider z) + static UniGLTF.Extensions.VRMC_springBone.ColliderShape ExportShape(VRM10SpringBoneCollider z) { var shape = new UniGLTF.Extensions.VRMC_springBone.ColliderShape(); switch (z.ColliderType) @@ -307,7 +314,7 @@ namespace UniVRM10 return shape; } - UniGLTF.Extensions.VRMC_springBone.SpringBoneJoint ExportJoint(VRM10SpringBoneJoint y, Func getIndexFromTransform) + static UniGLTF.Extensions.VRMC_springBone.SpringBoneJoint ExportJoint(VRM10SpringBoneJoint y, Func getIndexFromTransform) { var joint = new UniGLTF.Extensions.VRMC_springBone.SpringBoneJoint { @@ -321,7 +328,7 @@ namespace UniVRM10 return joint; } - UniGLTF.Extensions.VRMC_springBone.VRMC_springBone ExportSpringBone(Vrm10Instance controller, Model model, ModelExporter converter) + static UniGLTF.Extensions.VRMC_springBone.VRMC_springBone ExportSpringBone(Vrm10Instance controller, Model model, ModelExporter converter) { var springBone = new UniGLTF.Extensions.VRMC_springBone.VRMC_springBone { @@ -371,7 +378,7 @@ namespace UniVRM10 return springBone; } - void ExportConstraints(Vrm10Instance vrmController, Model model, ModelExporter converter) + static void ExportConstraints(Vrm10Instance vrmController, Model model, ModelExporter converter, List nodes) { var constraints = vrmController.GetComponentsInChildren(); foreach (var constraint in constraints) @@ -398,7 +405,7 @@ namespace UniVRM10 // serialize to gltfNode var node = converter.Nodes[constraint.gameObject]; var nodeIndex = model.Nodes.IndexOf(node); - var gltfNode = Storage.Gltf.nodes[nodeIndex]; + var gltfNode = nodes[nodeIndex]; UniGLTF.Extensions.VRMC_node_constraint.GltfSerializer.SerializeTo(ref gltfNode.extensions, vrmConstraint); } } @@ -497,7 +504,7 @@ namespace UniVRM10 } } - UniGLTF.Extensions.VRMC_vrm.LookAtRangeMap ExportLookAtRangeMap(CurveMapper mapper) + static UniGLTF.Extensions.VRMC_vrm.LookAtRangeMap ExportLookAtRangeMap(CurveMapper mapper) { return new UniGLTF.Extensions.VRMC_vrm.LookAtRangeMap { @@ -506,7 +513,7 @@ namespace UniVRM10 }; } - void ExportLookAt(UniGLTF.Extensions.VRMC_vrm.VRMC_vrm vrm, Vrm10Instance vrmController) + static void ExportLookAt(UniGLTF.Extensions.VRMC_vrm.VRMC_vrm vrm, Vrm10Instance vrmController) { if (!(vrmController?.Vrm?.LookAt is VRM10ObjectLookAt lookAt)) { @@ -528,7 +535,7 @@ namespace UniVRM10 }; } - UniGLTF.Extensions.VRMC_vrm.MorphTargetBind ExportMorphTargetBinding(MorphTargetBinding binding, Func getIndex) + static UniGLTF.Extensions.VRMC_vrm.MorphTargetBind ExportMorphTargetBinding(MorphTargetBinding binding, Func getIndex) { return new UniGLTF.Extensions.VRMC_vrm.MorphTargetBind { @@ -538,7 +545,7 @@ namespace UniVRM10 }; } - UniGLTF.Extensions.VRMC_vrm.MaterialColorBind ExportMaterialColorBinding(MaterialColorBinding binding, Func getIndex) + static UniGLTF.Extensions.VRMC_vrm.MaterialColorBind ExportMaterialColorBinding(MaterialColorBinding binding, Func getIndex) { return new UniGLTF.Extensions.VRMC_vrm.MaterialColorBind { @@ -548,7 +555,7 @@ namespace UniVRM10 }; } - UniGLTF.Extensions.VRMC_vrm.TextureTransformBind ExportTextureTransformBinding(MaterialUVBinding binding, Func getIndex) + static UniGLTF.Extensions.VRMC_vrm.TextureTransformBind ExportTextureTransformBinding(MaterialUVBinding binding, Func getIndex) { var (scale, offset) = TextureTransform.VerticalFlipScaleOffset(binding.Scaling, binding.Offset); return new UniGLTF.Extensions.VRMC_vrm.TextureTransformBind @@ -559,7 +566,7 @@ namespace UniVRM10 }; } - UniGLTF.Extensions.VRMC_vrm.Expression ExportExpression(VRM10Expression e, Vrm10Instance vrmController, Model model, ModelExporter converter) + static UniGLTF.Extensions.VRMC_vrm.Expression ExportExpression(VRM10Expression e, Vrm10Instance vrmController, Model model, ModelExporter converter) { if (e == null) { @@ -634,7 +641,7 @@ namespace UniVRM10 return vrmExpression; } - void ExportExpression(UniGLTF.Extensions.VRMC_vrm.VRMC_vrm vrm, Vrm10Instance vrmController, Model model, ModelExporter converter) + static void ExportExpression(UniGLTF.Extensions.VRMC_vrm.VRMC_vrm vrm, Vrm10Instance vrmController, Model model, ModelExporter converter) { if (vrmController?.Vrm?.Expression?.Clips == null) { @@ -667,7 +674,7 @@ namespace UniVRM10 }; } - int? ExportMeta(UniGLTF.Extensions.VRMC_vrm.VRMC_vrm vrm, VRM10ObjectMeta meta) + static int? ExportMeta(UniGLTF.Extensions.VRMC_vrm.VRMC_vrm vrm, VRM10ObjectMeta meta, ITextureExporter textureExporter) { vrm.Meta.Name = meta.Name; vrm.Meta.Version = meta.Version; @@ -689,12 +696,12 @@ namespace UniVRM10 int? thumbnailTextureIndex = default; if (meta.Thumbnail != null) { - thumbnailTextureIndex = m_textureExporter.RegisterExportingAsSRgb(meta.Thumbnail, needsAlpha: true); + thumbnailTextureIndex = textureExporter.RegisterExportingAsSRgb(meta.Thumbnail, needsAlpha: true); } return thumbnailTextureIndex; } - void ExportHumanoid(UniGLTF.Extensions.VRMC_vrm.VRMC_vrm vrm, Model model) + static void ExportHumanoid(UniGLTF.Extensions.VRMC_vrm.VRMC_vrm vrm, Model model) { // humanoid for (int i = 0; i < model.Nodes.Count; ++i) From faedf96c1d12c4a5804ac413b2fde5d842df1214 Mon Sep 17 00:00:00 2001 From: ousttrue Date: Thu, 7 Oct 2021 13:55:49 +0900 Subject: [PATCH 2/6] Migrate(UniGLTF.GltfData data) --- .../Runtime/UniGLTF/Format/IStorage.cs | 2 +- Assets/UniGLTF/Runtime/UniGLTF/IO/GltfData.cs | 9 +++++--- .../UniGLTF/IO/Parser/GlbBinaryParser.cs | 4 ++-- Assets/VRM10/Runtime/IO/Vrm10Data.cs | 4 +--- .../VRM10/Runtime/Migration/MigrationVrm.cs | 21 +++++++------------ 5 files changed, 18 insertions(+), 22 deletions(-) diff --git a/Assets/UniGLTF/Runtime/UniGLTF/Format/IStorage.cs b/Assets/UniGLTF/Runtime/UniGLTF/Format/IStorage.cs index d12009ce2..b7495b2be 100644 --- a/Assets/UniGLTF/Runtime/UniGLTF/Format/IStorage.cs +++ b/Assets/UniGLTF/Runtime/UniGLTF/Format/IStorage.cs @@ -4,7 +4,7 @@ namespace UniGLTF { public interface IStorage { - ArraySegment Get(string url); + ArraySegment Get(string url = default); /// /// Get original filepath if exists diff --git a/Assets/UniGLTF/Runtime/UniGLTF/IO/GltfData.cs b/Assets/UniGLTF/Runtime/UniGLTF/IO/GltfData.cs index 67534b39b..8196458d5 100644 --- a/Assets/UniGLTF/Runtime/UniGLTF/IO/GltfData.cs +++ b/Assets/UniGLTF/Runtime/UniGLTF/IO/GltfData.cs @@ -1,9 +1,6 @@ using System; using System.Collections.Generic; -using System.IO; using System.Linq; -using System.Text; -using UnityEngine; namespace UniGLTF { @@ -31,6 +28,12 @@ namespace UniGLTF /// public IReadOnlyList Chunks { get; } + /// + /// Bin chunk bytes + /// + /// + public ArraySegment Bin => Chunks.First(x => x.ChunkType == GlbChunkType.BIN).Bytes; + /// /// URI access /// diff --git a/Assets/UniGLTF/Runtime/UniGLTF/IO/Parser/GlbBinaryParser.cs b/Assets/UniGLTF/Runtime/UniGLTF/IO/Parser/GlbBinaryParser.cs index e14fe83d8..6785a6f22 100644 --- a/Assets/UniGLTF/Runtime/UniGLTF/IO/Parser/GlbBinaryParser.cs +++ b/Assets/UniGLTF/Runtime/UniGLTF/IO/Parser/GlbBinaryParser.cs @@ -6,8 +6,8 @@ namespace UniGLTF { private readonly byte[] _data; private readonly string _name; - - public GlbBinaryParser(byte[] data, string uniqueName) + + public GlbBinaryParser(byte[] data, string uniqueName = "tmp") { _data = data; diff --git a/Assets/VRM10/Runtime/IO/Vrm10Data.cs b/Assets/VRM10/Runtime/IO/Vrm10Data.cs index 9ad29fcea..4e0deb9ee 100644 --- a/Assets/VRM10/Runtime/IO/Vrm10Data.cs +++ b/Assets/VRM10/Runtime/IO/Vrm10Data.cs @@ -68,8 +68,6 @@ namespace UniVRM10 try { var json = data.Json.ParseAsJson(); - var bin = data.Chunks.First(x => x.ChunkType == GlbChunkType.BIN); - try { if (!json.TryGet("extensions", out JsonNode extensions)) @@ -95,7 +93,7 @@ namespace UniVRM10 return false; } - migrated = MigrationVrm.Migrate(json, bin.Bytes); + migrated = MigrationVrm.Migrate(data); if (migrated == null) { result = new Vrm10Data(default, default, Vrm10FileType.Vrm0, "vrm0: cannot migrate"); diff --git a/Assets/VRM10/Runtime/Migration/MigrationVrm.cs b/Assets/VRM10/Runtime/Migration/MigrationVrm.cs index 5d027fa91..9f23fb099 100644 --- a/Assets/VRM10/Runtime/Migration/MigrationVrm.cs +++ b/Assets/VRM10/Runtime/Migration/MigrationVrm.cs @@ -12,20 +12,14 @@ namespace UniVRM10 { public static byte[] Migrate(byte[] src) { - var glb = UniGLTF.Glb.Parse(src); - var json = glb.Json.Bytes.ParseAsJson(); - return Migrate(json, glb.Binary.Bytes); + var data = new UniGLTF.GlbBinaryParser(src).Parse(); + return Migrate(data); } - public static byte[] Migrate(JsonNode json, ArraySegment bin) + public static byte[] Migrate(UniGLTF.GltfData data) { - var gltf = UniGLTF.GltfDeserializer.Deserialize(json); - - // attach glb bin to buffer - foreach (var buffer in gltf.buffers) - { - buffer.OpenStorage(new UniGLTF.SimpleStorage(bin)); - } + var gltf = data.GLTF; + var json = data.Json.ParseAsJson(); // https://github.com/vrm-c/vrm-specification/issues/205 RotateY180.Rotate(gltf); @@ -107,7 +101,7 @@ namespace UniVRM10 vrm1Json = f.GetStoreBytes(); } // JSON 部分だけが改変されて、BIN はそのまま - return UniGLTF.Glb.Create(vrm1Json, bin).ToBytes(); + return UniGLTF.Glb.Create(vrm1Json, data.Bin).ToBytes(); } public static void Check(JsonNode vrm0, UniGLTF.Extensions.VRMC_vrm.VRMC_vrm vrm1) @@ -121,4 +115,5 @@ namespace UniVRM10 // Migration.CheckSpringBone(vrm0["secondaryAnimation"], vrm1.sp) } } -} + +} \ No newline at end of file From 8001d3673e356c6a0c4aead190de2799e6fe9b85 Mon Sep 17 00:00:00 2001 From: ousttrue Date: Thu, 7 Oct 2021 14:22:04 +0900 Subject: [PATCH 3/6] MeshUpdater --- .../Runtime/Extensions/glTFExtensions.cs | 6 +- .../Runtime/UniGLTF/IO/ArrayByteBuffer.cs | 3 +- Assets/VRM10/Runtime/IO/Model/ModelReader.cs | 9 +- Assets/VRM10/Runtime/Migration/MeshUpdater.cs | 133 ++++++++++++++++++ .../Runtime/Migration/MeshUpdater.cs.meta | 11 ++ .../VRM10/Runtime/Migration/MigrationMToon.cs | 4 +- .../VRM10/Runtime/Migration/MigrationVrm.cs | 41 ++++-- .../Runtime/ModelExtensionsForCoordinates.cs | 4 + 8 files changed, 188 insertions(+), 23 deletions(-) create mode 100644 Assets/VRM10/Runtime/Migration/MeshUpdater.cs create mode 100644 Assets/VRM10/Runtime/Migration/MeshUpdater.cs.meta diff --git a/Assets/UniGLTF/Runtime/Extensions/glTFExtensions.cs b/Assets/UniGLTF/Runtime/Extensions/glTFExtensions.cs index 7b104d0bd..d69a192ec 100644 --- a/Assets/UniGLTF/Runtime/Extensions/glTFExtensions.cs +++ b/Assets/UniGLTF/Runtime/Extensions/glTFExtensions.cs @@ -65,14 +65,14 @@ namespace UniGLTF { typeof(Color), new ComponentVec(glComponentType.FLOAT, 4) }, }; - static glComponentType GetComponentType() + public static glComponentType GetComponentType() { var cv = default(ComponentVec); if (ComponentTypeMap.TryGetValue(typeof(T), out cv)) { return cv.ComponentType; } - else if (typeof(T) == typeof(uint)) + else if (typeof(T) == typeof(uint) || typeof(T) == typeof(int)) { return glComponentType.UNSIGNED_INT; } @@ -86,7 +86,7 @@ namespace UniGLTF } } - static string GetAccessorType() + public static string GetAccessorType() { var cv = default(ComponentVec); if (ComponentTypeMap.TryGetValue(typeof(T), out cv)) diff --git a/Assets/UniGLTF/Runtime/UniGLTF/IO/ArrayByteBuffer.cs b/Assets/UniGLTF/Runtime/UniGLTF/IO/ArrayByteBuffer.cs index a08c767fb..a29dde5e1 100644 --- a/Assets/UniGLTF/Runtime/UniGLTF/IO/ArrayByteBuffer.cs +++ b/Assets/UniGLTF/Runtime/UniGLTF/IO/ArrayByteBuffer.cs @@ -1,4 +1,5 @@ using System; +using System.IO; using System.Runtime.InteropServices; @@ -24,7 +25,7 @@ namespace UniGLTF m_bytes = bytes; } - public glTFBufferView Extend(ArraySegment array, glBufferTarget target) where T : struct + public glTFBufferView Extend(ArraySegment array, glBufferTarget target = default) where T : struct { using (var pin = Pin.Create(array)) { diff --git a/Assets/VRM10/Runtime/IO/Model/ModelReader.cs b/Assets/VRM10/Runtime/IO/Model/ModelReader.cs index 8a3a871b0..91aaae049 100644 --- a/Assets/VRM10/Runtime/IO/Model/ModelReader.cs +++ b/Assets/VRM10/Runtime/IO/Model/ModelReader.cs @@ -9,19 +9,20 @@ namespace UniVRM10 /// public static class ModelReader { - static Model Load(Vrm10Storage storage, string rootName) + static Model Load(Vrm10Storage storage, string rootName, Coordinates coords) { if (storage == null) { return null; } - var model = new Model(Coordinates.Vrm1) + var model = new Model(coords) { AssetVersion = storage.AssetVersion, AssetGenerator = storage.AssetGenerator, AssetCopyright = storage.AssetCopyright, AssetMinVersion = storage.AssetMinVersion, + Coordinates = coords, }; // node @@ -74,10 +75,10 @@ namespace UniVRM10 return model; } - public static Model Read(UniGLTF.GltfData data) + public static Model Read(UniGLTF.GltfData data, Coordinates? coords = default) { var storage = new Vrm10Storage(data); - var model = Load(storage, Path.GetFileName(data.TargetPath)); + var model = Load(storage, Path.GetFileName(data.TargetPath), coords.GetValueOrDefault(Coordinates.Vrm1)); model.ConvertCoordinate(Coordinates.Unity); return model; } diff --git a/Assets/VRM10/Runtime/Migration/MeshUpdater.cs b/Assets/VRM10/Runtime/Migration/MeshUpdater.cs new file mode 100644 index 000000000..476a0e440 --- /dev/null +++ b/Assets/VRM10/Runtime/Migration/MeshUpdater.cs @@ -0,0 +1,133 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using UniGLTF; +using UnityEngine; + +namespace UniVRM10 +{ + /// + /// 座標系を変換した Model により、Mesh, Node, BindMatrices を更新する。 + /// buffer, bufferAccessor の更新もある。 + /// + class MeshUpdater + { + GltfData _data; + ArrayByteBuffer _buffer; + List _bufferViews = new List(); + List _accessors = new List(); + + public MeshUpdater(GltfData data) + { + _data = data; + _buffer = new ArrayByteBuffer(new byte[data.Bin.Count]); + } + + int AddBuffer(ArraySegment bytes) + { + var bufferView = _buffer.Extend(bytes); + var index = _bufferViews.Count; + _bufferViews.Add(bufferView); + return index; + } + + int AddAccessor(SpanLike span) where T : struct + { + var bufferViewIndex = AddBuffer(span.Bytes); + var accessor = new glTFAccessor + { + bufferView = bufferViewIndex, + count = span.Length, + byteOffset = 0, + componentType = glTFExtensions.GetComponentType(), + type = glTFExtensions.GetAccessorType(), + }; + var index = _accessors.Count; + _accessors.Add(accessor); + return index; + } + + int? AddAccessor(VrmLib.BufferAccessor buffer) where T : struct + { + if (buffer == null) + { + return default; + } + return AddAccessor(buffer.GetSpan()); + } + + struct MorphAccessor + { + public int? Position; + public int? Normal; + }; + + public (glTF, ArraySegment) Update(VrmLib.Model model) + { + var gltf = _data.GLTF; + + // copy images + foreach (var image in gltf.images) + { + var bytes = gltf.GetViewBytes(image.bufferView); + image.bufferView = AddBuffer(bytes); + } + + // update Mesh + foreach (var (gltfMesh, mesh) in Enumerable.Zip(gltf.meshes, model.MeshGroups, (l, r) => (l, r.Meshes[0]))) + { + var indices = mesh.IndexBuffer.GetSpan(); + var position = AddAccessor(mesh.VertexBuffer.Positions); + var normal = AddAccessor(mesh.VertexBuffer.Normals); + var uv = AddAccessor(mesh.VertexBuffer.TexCoords); + var weights = AddAccessor(mesh.VertexBuffer.Weights); + var joints = AddAccessor(mesh.VertexBuffer.Joints); + + var morphTargets = new MorphAccessor[] { }; + if (mesh.MorphTargets != null) + { + morphTargets = mesh.MorphTargets.Select(x => new MorphAccessor + { + Position = AddAccessor(x.VertexBuffer.Positions), + Normal = AddAccessor(x.VertexBuffer.Normals), + }).ToArray(); + } + + foreach (var (gltfPrim, submesh) in Enumerable.Zip(gltfMesh.primitives, mesh.Submeshes, (l, r) => (l, r))) + { + var subIndices = indices.Slice(submesh.Offset, submesh.DrawCount); + gltfPrim.indices = AddAccessor(subIndices); + gltfPrim.attributes.POSITION = position.Value; + gltfPrim.attributes.NORMAL = normal.Value; + gltfPrim.attributes.TEXCOORD_0 = uv.Value; + gltfPrim.attributes.WEIGHTS_0 = weights.GetValueOrDefault(-1); + gltfPrim.attributes.JOINTS_0 = joints.GetValueOrDefault(-1); + foreach (var (gltfMorph, morph) in Enumerable.Zip(gltfPrim.targets, morphTargets, (l, r) => (l, r))) + { + gltfMorph.POSITION = morph.Position.GetValueOrDefault(-1); + gltfMorph.NORMAL = morph.Normal.GetValueOrDefault(-1); + } + } + } + + // update nodes + foreach (var (gltfNode, node) in Enumerable.Zip(gltf.nodes, model.Nodes, (l, r) => (l, r))) + { + gltfNode.translation = node.LocalTranslation.ToFloat3(); + gltfNode.rotation = node.LocalRotation.ToFloat4(); + gltfNode.scale = node.LocalScaling.ToFloat3(); + if (gltfNode.skin >= 0) + { + var gltfSkin = gltf.skins[gltfNode.skin]; + gltfSkin.inverseBindMatrices = AddAccessor(node.MeshGroup.Skin.InverseMatrices.GetSpan()); + } + } + + // replace + gltf.bufferViews = _bufferViews; + gltf.accessors = _accessors; + + return (gltf, _buffer.Bytes); + } + } +} diff --git a/Assets/VRM10/Runtime/Migration/MeshUpdater.cs.meta b/Assets/VRM10/Runtime/Migration/MeshUpdater.cs.meta new file mode 100644 index 000000000..1a0dd05c2 --- /dev/null +++ b/Assets/VRM10/Runtime/Migration/MeshUpdater.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: c49ea19813d8f214dbe789fd79f78b28 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/VRM10/Runtime/Migration/MigrationMToon.cs b/Assets/VRM10/Runtime/Migration/MigrationMToon.cs index b719592e4..c770feab4 100644 --- a/Assets/VRM10/Runtime/Migration/MigrationMToon.cs +++ b/Assets/VRM10/Runtime/Migration/MigrationMToon.cs @@ -268,13 +268,13 @@ namespace UniVRM10 } } - public static void Migrate(glTF gltf, JsonNode json) + public static void Migrate(glTF gltf, JsonNode vrm0) { // Create MToonDefinition(0.x) from JSON(0.x) var sourceMaterials = new (Vrm0XMToonValue, glTFMaterial)[gltf.materials.Count]; for (int i = 0; i < gltf.materials.Count; ++i) { - var vrmMaterial = json["extensions"]["VRM"]["materialProperties"][i]; + var vrmMaterial = vrm0["materialProperties"][i]; if (vrmMaterial["shader"].GetString() != "VRM/MToon") { continue; diff --git a/Assets/VRM10/Runtime/Migration/MigrationVrm.cs b/Assets/VRM10/Runtime/Migration/MigrationVrm.cs index 9f23fb099..650bbe7ca 100644 --- a/Assets/VRM10/Runtime/Migration/MigrationVrm.cs +++ b/Assets/VRM10/Runtime/Migration/MigrationVrm.cs @@ -1,6 +1,6 @@ using System; using System.Collections.Generic; -using System.Linq; +using UniGLTF; using UniJSON; namespace UniVRM10 @@ -12,21 +12,36 @@ namespace UniVRM10 { public static byte[] Migrate(byte[] src) { - var data = new UniGLTF.GlbBinaryParser(src).Parse(); + var data = new GlbBinaryParser(src).Parse(); return Migrate(data); } - public static byte[] Migrate(UniGLTF.GltfData data) + static (int, int) GetVertexRange(SpanLike indices) { - var gltf = data.GLTF; - var json = data.Json.ParseAsJson(); + var min = int.MaxValue; ; + var max = 0; + foreach (var i in indices) + { + if (i < min) min = i; + if (i > max) max = i; + } + return (min, max); + } - // https://github.com/vrm-c/vrm-specification/issues/205 - RotateY180.Rotate(gltf); + public static byte[] Migrate(GltfData data) + { + // VRM0 -> Unity + var model = ModelReader.Read(data, VrmLib.Coordinates.Vrm0); + // Unity -> VRM1 + VrmLib.ModelExtensionsForCoordinates.ConvertCoordinate(model, VrmLib.Coordinates.Vrm1); - var vrm0 = json["extensions"]["VRM"]; + var (gltf, bin) = new MeshUpdater(data).Update(model); gltf.extensions = null; + return MigrateVrm(gltf, bin, data.Json.ParseAsJson()["extensions"]["VRM"]); + } + static byte[] MigrateVrm(glTF gltf, ArraySegment bin, JsonNode vrm0) + { { // vrm var vrm1 = new UniGLTF.Extensions.VRMC_vrm.VRMC_vrm(); @@ -90,18 +105,18 @@ namespace UniVRM10 // MToon { - MigrationMToon.Migrate(gltf, json); + MigrationMToon.Migrate(gltf, vrm0); } // Serialize whole glTF ArraySegment vrm1Json = default; { var f = new JsonFormatter(); - UniGLTF.GltfSerializer.Serialize(f, gltf); + GltfSerializer.Serialize(f, gltf); vrm1Json = f.GetStoreBytes(); } - // JSON 部分だけが改変されて、BIN はそのまま - return UniGLTF.Glb.Create(vrm1Json, data.Bin).ToBytes(); + + return Glb.Create(vrm1Json, bin).ToBytes(); } public static void Check(JsonNode vrm0, UniGLTF.Extensions.VRMC_vrm.VRMC_vrm vrm1) @@ -110,7 +125,7 @@ namespace UniVRM10 MigrationVrmHumanoid.Check(vrm0["humanoid"], vrm1.Humanoid); } - public static void Check(JsonNode vrm0, UniGLTF.Extensions.VRMC_springBone.VRMC_springBone vrm1, List nodes) + public static void Check(JsonNode vrm0, UniGLTF.Extensions.VRMC_springBone.VRMC_springBone vrm1, List nodes) { // Migration.CheckSpringBone(vrm0["secondaryAnimation"], vrm1.sp) } diff --git a/Assets/VRM10/vrmlib/Runtime/ModelExtensionsForCoordinates.cs b/Assets/VRM10/vrmlib/Runtime/ModelExtensionsForCoordinates.cs index 3dfc4d18a..648ded8a1 100644 --- a/Assets/VRM10/vrmlib/Runtime/ModelExtensionsForCoordinates.cs +++ b/Assets/VRM10/vrmlib/Runtime/ModelExtensionsForCoordinates.cs @@ -98,21 +98,25 @@ namespace VrmLib { model.ReverseAxisAndFlipTriangle(ZReverser, ignoreVrm); model.UVVerticalFlip(); + model.Coordinates = coordinates; } else if (model.Coordinates.IsUnity && coordinates.IsVrm0) { model.ReverseAxisAndFlipTriangle(ZReverser, ignoreVrm); model.UVVerticalFlip(); + model.Coordinates = coordinates; } else if (model.Coordinates.IsVrm1 && coordinates.IsUnity) { model.ReverseAxisAndFlipTriangle(XReverser, ignoreVrm); model.UVVerticalFlip(); + model.Coordinates = coordinates; } else if (model.Coordinates.IsUnity && coordinates.IsVrm1) { model.ReverseAxisAndFlipTriangle(XReverser, ignoreVrm); model.UVVerticalFlip(); + model.Coordinates = coordinates; } else { From 2adbb21f7bab99f6d1d8c1310af53433b6ea3b1a Mon Sep 17 00:00:00 2001 From: ousttrue Date: Fri, 8 Oct 2021 14:38:51 +0900 Subject: [PATCH 4/6] =?UTF-8?q?GetComponentType=20=E3=82=92=E4=BB=95?= =?UTF-8?q?=E6=A7=98=E3=81=AB=E6=BA=96=E6=8B=A0=E3=81=97=E3=81=A6=E4=B8=8D?= =?UTF-8?q?=E8=A8=B1=E5=8F=AF=E3=81=AB=E3=80=82=E4=B8=8A=E6=B5=81=E3=82=92?= =?UTF-8?q?=20uint=20=E3=81=AB=E4=BF=AE=E6=AD=A3?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- Assets/UniGLTF/Runtime/Extensions/glTFExtensions.cs | 2 +- Assets/VRM10/Runtime/Migration/MeshUpdater.cs | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/Assets/UniGLTF/Runtime/Extensions/glTFExtensions.cs b/Assets/UniGLTF/Runtime/Extensions/glTFExtensions.cs index d69a192ec..2ea4400cd 100644 --- a/Assets/UniGLTF/Runtime/Extensions/glTFExtensions.cs +++ b/Assets/UniGLTF/Runtime/Extensions/glTFExtensions.cs @@ -72,7 +72,7 @@ namespace UniGLTF { return cv.ComponentType; } - else if (typeof(T) == typeof(uint) || typeof(T) == typeof(int)) + else if (typeof(T) == typeof(uint)) { return glComponentType.UNSIGNED_INT; } diff --git a/Assets/VRM10/Runtime/Migration/MeshUpdater.cs b/Assets/VRM10/Runtime/Migration/MeshUpdater.cs index 476a0e440..01fc05ef6 100644 --- a/Assets/VRM10/Runtime/Migration/MeshUpdater.cs +++ b/Assets/VRM10/Runtime/Migration/MeshUpdater.cs @@ -76,7 +76,7 @@ namespace UniVRM10 // update Mesh foreach (var (gltfMesh, mesh) in Enumerable.Zip(gltf.meshes, model.MeshGroups, (l, r) => (l, r.Meshes[0]))) { - var indices = mesh.IndexBuffer.GetSpan(); + var indices = mesh.IndexBuffer.GetSpan(); var position = AddAccessor(mesh.VertexBuffer.Positions); var normal = AddAccessor(mesh.VertexBuffer.Normals); var uv = AddAccessor(mesh.VertexBuffer.TexCoords); From 828e018afaaa2fd1d3dfa90cfa842c2c87a81924 Mon Sep 17 00:00:00 2001 From: ousttrue Date: Fri, 8 Oct 2021 14:49:39 +0900 Subject: [PATCH 5/6] =?UTF-8?q?bin=20chunk=20=E3=81=AF=20[1]=E3=80=82=20fi?= =?UTF-8?q?eld=20=E3=81=AE=E9=A0=86=E7=95=AA=E3=82=92=E6=95=B4=E7=90=86?= =?UTF-8?q?=E3=80=82GLB=20=E4=BB=95=E6=A7=98=E3=81=AB=E9=96=A2=E3=81=99?= =?UTF-8?q?=E3=82=8B=E3=82=B3=E3=83=A1=E3=83=B3=E3=83=88=E3=82=92=E8=BF=BD?= =?UTF-8?q?=E5=8A=A0=E3=80=82?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- Assets/UniGLTF/Runtime/UniGLTF/IO/GltfData.cs | 31 +++++++++++-------- 1 file changed, 18 insertions(+), 13 deletions(-) diff --git a/Assets/UniGLTF/Runtime/UniGLTF/IO/GltfData.cs b/Assets/UniGLTF/Runtime/UniGLTF/IO/GltfData.cs index 8196458d5..a1fb057e9 100644 --- a/Assets/UniGLTF/Runtime/UniGLTF/IO/GltfData.cs +++ b/Assets/UniGLTF/Runtime/UniGLTF/IO/GltfData.cs @@ -1,6 +1,5 @@ using System; using System.Collections.Generic; -using System.Linq; namespace UniGLTF { @@ -12,27 +11,33 @@ namespace UniGLTF /// public string TargetPath { get; } - /// - /// JSON source - /// - public string Json { get; } - - /// - /// GLTF parsed from JSON - /// - public glTF GLTF { get; } - /// /// Chunk Data. /// Maybe empty if source file was not glb format. + /// https://www.khronos.org/registry/glTF/specs/2.0/glTF-2.0.html#chunks + /// [0] must JSON + /// [1] must BIN + /// [2...] may exists. /// public IReadOnlyList Chunks { get; } /// - /// Bin chunk bytes + /// JSON chunk ToString + /// > This chunk MUST be the very first chunk of Binary glTF asset + /// + public string Json { get; } + + /// + /// GLTF parsed from JSON chunk + /// + public glTF GLTF { get; } + + /// + /// BIN chunk + /// > This chunk MUST be the second chunk of the Binary glTF asset /// /// - public ArraySegment Bin => Chunks.First(x => x.ChunkType == GlbChunkType.BIN).Bytes; + public ArraySegment Bin => Chunks[1].Bytes; /// /// URI access From 6506bef0694b147b6f6b4ddcb31a4b1231c0371f Mon Sep 17 00:00:00 2001 From: ousttrue Date: Fri, 8 Oct 2021 14:50:41 +0900 Subject: [PATCH 6/6] =?UTF-8?q?default=20=E5=BC=95=E3=81=8D=E6=95=B0?= =?UTF-8?q?=E3=81=A8=E3=82=8A=E3=82=84=E3=82=81?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- Assets/UniGLTF/Runtime/UniGLTF/IO/Parser/GlbBinaryParser.cs | 2 +- Assets/VRM10/Runtime/Migration/MigrationVrm.cs | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/Assets/UniGLTF/Runtime/UniGLTF/IO/Parser/GlbBinaryParser.cs b/Assets/UniGLTF/Runtime/UniGLTF/IO/Parser/GlbBinaryParser.cs index 6785a6f22..2138363b7 100644 --- a/Assets/UniGLTF/Runtime/UniGLTF/IO/Parser/GlbBinaryParser.cs +++ b/Assets/UniGLTF/Runtime/UniGLTF/IO/Parser/GlbBinaryParser.cs @@ -7,7 +7,7 @@ namespace UniGLTF private readonly byte[] _data; private readonly string _name; - public GlbBinaryParser(byte[] data, string uniqueName = "tmp") + public GlbBinaryParser(byte[] data, string uniqueName) { _data = data; diff --git a/Assets/VRM10/Runtime/Migration/MigrationVrm.cs b/Assets/VRM10/Runtime/Migration/MigrationVrm.cs index 650bbe7ca..3e736a4a4 100644 --- a/Assets/VRM10/Runtime/Migration/MigrationVrm.cs +++ b/Assets/VRM10/Runtime/Migration/MigrationVrm.cs @@ -12,7 +12,7 @@ namespace UniVRM10 { public static byte[] Migrate(byte[] src) { - var data = new GlbBinaryParser(src).Parse(); + var data = new GlbBinaryParser(src, "migration").Parse(); return Migrate(data); }