diff --git a/Assets/VRM/UniGLTF/Scripts/Format/glTF.cs b/Assets/VRM/UniGLTF/Scripts/Format/glTF.cs index b9be6d1b68..4180f52be8 100644 --- a/Assets/VRM/UniGLTF/Scripts/Format/glTF.cs +++ b/Assets/VRM/UniGLTF/Scripts/Format/glTF.cs @@ -500,5 +500,26 @@ public byte[] ToGlbBytes(SerializerTypes serializer = SerializerTypes.Generated) return Glb.ToBytes(json, buffers[0].GetBytes()); } + + public (string, List) ToGltf(string gltfPath) + { + var f = new JsonFormatter(); + + // fix buffer path + if (buffers.Count == 1) + { + var withoutExt = Path.GetFileNameWithoutExtension(gltfPath); + buffers[0].uri = $"{withoutExt}.bin"; + } + else + { + throw new NotImplementedException(); + } + + f.GenSerialize(this); + var json = f.ToString().ParseAsJson().ToString(" "); + RemoveUnusedExtensions(json); + return (json, buffers); + } } } diff --git a/Assets/VRM/UniGLTF/Scripts/IO/MeshExporter.cs b/Assets/VRM/UniGLTF/Scripts/IO/MeshExporter.cs index de44ec80a3..73050b3970 100644 --- a/Assets/VRM/UniGLTF/Scripts/IO/MeshExporter.cs +++ b/Assets/VRM/UniGLTF/Scripts/IO/MeshExporter.cs @@ -306,7 +306,7 @@ static gltfMorphTarget ExportMorphTarget(glTF gltf, int bufferIndex, blendShapePositionAccessorIndex = gltf.ExtendSparseBufferAndGetAccessorIndex(bufferIndex, accessorCount, blendShapeVertices, sparseIndices, sparseIndicesViewIndex, - glBufferTarget.ARRAY_BUFFER); + glBufferTarget.NONE); } if (useNormal) @@ -315,7 +315,7 @@ static gltfMorphTarget ExportMorphTarget(glTF gltf, int bufferIndex, blendShapeNormalAccessorIndex = gltf.ExtendSparseBufferAndGetAccessorIndex(bufferIndex, accessorCount, blendShapeNormals, sparseIndices, sparseIndicesViewIndex, - glBufferTarget.ARRAY_BUFFER); + glBufferTarget.NONE); } if (useTangent) @@ -323,7 +323,7 @@ static gltfMorphTarget ExportMorphTarget(glTF gltf, int bufferIndex, blendShapeTangents = sparseIndices.Select(x => blendShapeTangents[x].ReverseZ()).ToArray(); blendShapeTangentAccessorIndex = gltf.ExtendSparseBufferAndGetAccessorIndex(bufferIndex, accessorCount, blendShapeTangents, sparseIndices, sparseIndicesViewIndex, - glBufferTarget.ARRAY_BUFFER); + glBufferTarget.NONE); } } else @@ -380,6 +380,10 @@ static gltfMorphTarget ExportMorphTarget(glTF gltf, int bufferIndex, var gltfMesh = ExportPrimitives(gltf, bufferIndex, x.Renderer.name, mesh, materials, unityMaterials); + if (gltfMesh.extras == null) + { + gltfMesh.extras = new glTFMesh_extras(); + } var blendShapeIndexMap = new Dictionary(); int exportBlendShapes = 0; @@ -395,7 +399,9 @@ static gltfMorphTarget ExportMorphTarget(glTF gltf, int bufferIndex, } // maybe skip + var blendShapeName = mesh.GetBlendShapeName(j); blendShapeIndexMap.Add(j, exportBlendShapes++); + gltfMesh.extras.targetNames.Add(blendShapeName); // // all primitive has same blendShape @@ -403,7 +409,7 @@ static gltfMorphTarget ExportMorphTarget(glTF gltf, int bufferIndex, for (int k = 0; k < gltfMesh.primitives.Count; ++k) { gltfMesh.primitives[k].targets.Add(morphTarget); - gltfMesh.primitives[k].extras.targetNames.Add(mesh.GetBlendShapeName(j)); + gltfMesh.primitives[k].extras.targetNames.Add(blendShapeName); } } diff --git a/Assets/VRM/UniGLTF/Scripts/IO/gltfExporter.cs b/Assets/VRM/UniGLTF/Scripts/IO/gltfExporter.cs index 68cc36ebc5..7b383e875b 100644 --- a/Assets/VRM/UniGLTF/Scripts/IO/gltfExporter.cs +++ b/Assets/VRM/UniGLTF/Scripts/IO/gltfExporter.cs @@ -12,26 +12,45 @@ namespace UniGLTF { public class gltfExporter : IDisposable { - const string CONVERT_HUMANOID_KEY = UniGLTFVersion.MENU + "/Export"; + const string MENU_EXPORT_GLB_KEY = UniGLTFVersion.MENU + "/Export(glb)"; + const string MENU_EXPORT_GLTF_KEY = UniGLTFVersion.MENU + "/Export(gltf)"; #if UNITY_EDITOR - [MenuItem(CONVERT_HUMANOID_KEY, true, 1)] + [MenuItem(MENU_EXPORT_GLTF_KEY, true, 1)] + [MenuItem(MENU_EXPORT_GLB_KEY, true, 1)] private static bool ExportValidate() { return Selection.activeObject != null && Selection.activeObject is GameObject; } - [MenuItem(CONVERT_HUMANOID_KEY, false, 1)] - private static void ExportFromMenu() + [MenuItem(MENU_EXPORT_GLTF_KEY, false, 1)] + private static void ExportGltfFromMenu() + { + ExportFromMenu(false, new MeshExportSettings + { + ExportOnlyBlendShapePosition = false, + UseSparseAccessorForMorphTarget = true, + }); + } + + [MenuItem(MENU_EXPORT_GLB_KEY, false, 1)] + private static void ExportGlbFromMenu() + { + ExportFromMenu(true, MeshExportSettings.Default); + } + + private static void ExportFromMenu(bool isGlb, MeshExportSettings settings) { var go = Selection.activeObject as GameObject; + var ext = isGlb ? "glb" : "gltf"; + if (go.transform.position == Vector3.zero && go.transform.rotation == Quaternion.identity && go.transform.localScale == Vector3.one) { var path = EditorUtility.SaveFilePanel( - "Save glb", "", go.name + ".glb", "glb"); + $"Save {ext}", "", go.name + $".{ext}", $"{ext}"); if (string.IsNullOrEmpty(path)) { return; @@ -41,10 +60,28 @@ private static void ExportFromMenu() using (var exporter = new gltfExporter(gltf)) { exporter.Prepare(go); - exporter.Export(MeshExportSettings.Default); + exporter.Export(settings); + } + + if (isGlb) + { + var bytes = gltf.ToGlbBytes(); + File.WriteAllBytes(path, bytes); + } + else + { + var (json, buffers) = gltf.ToGltf(path); + // without BOM + var encoding = new System.Text.UTF8Encoding(false); + File.WriteAllText(path, json, encoding); + // write to local folder + var dir = Path.GetDirectoryName(path); + foreach (var b in buffers) + { + var bufferPath = Path.Combine(dir, b.uri); + File.WriteAllBytes(bufferPath, b.GetBytes().ToArray()); + } } - var bytes = gltf.ToGlbBytes(); - File.WriteAllBytes(path, bytes); if (path.StartsWithUnityAssetPath()) {