From 5c8f8b24f62728b48cb89099cce3d4b83a2eeb64 Mon Sep 17 00:00:00 2001 From: Pierce Thompson Date: Tue, 20 Jun 2023 15:58:08 -0400 Subject: [PATCH] Add support for exporting meshes from the CLI --- AssetStudioCLI/Exporter.cs | 99 ++++++++++++++++++++++++++++ AssetStudioCLI/Options/CLIOptions.cs | 5 +- AssetStudioCLI/ReadMe.md | 6 +- AssetStudioCLI/Studio.cs | 1 + 4 files changed, 107 insertions(+), 4 deletions(-) diff --git a/AssetStudioCLI/Exporter.cs b/AssetStudioCLI/Exporter.cs index fef11a0..0b70cfd 100644 --- a/AssetStudioCLI/Exporter.cs +++ b/AssetStudioCLI/Exporter.cs @@ -270,6 +270,103 @@ namespace AssetStudioCLI return false; } + private static bool ExportMesh(AssetItem item, string exportPath) + { + var m_Mesh = (Mesh)item.Asset; + if (m_Mesh.m_VertexCount <= 0) + return false; + if (!TryExportFile(exportPath, item, ".obj", out var exportFullPath)) + return false; + var sb = new StringBuilder(); + sb.AppendLine("g " + m_Mesh.m_Name); + + #region Vertices + + if (m_Mesh.m_Vertices == null || m_Mesh.m_Vertices.Length == 0) + { + return false; + } + + int c = 3; + if (m_Mesh.m_Vertices.Length == m_Mesh.m_VertexCount * 4) + { + c = 4; + } + + for (int v = 0; v < m_Mesh.m_VertexCount; v++) + { + sb.Append($"v {-m_Mesh.m_Vertices[v * c]} {m_Mesh.m_Vertices[v * c + 1]} {m_Mesh.m_Vertices[v * c + 2]}\r\n"); + } + + #endregion + + #region UV + + if (m_Mesh.m_UV0?.Length > 0) + { + c = 4; + if (m_Mesh.m_UV0.Length == m_Mesh.m_VertexCount * 2) + { + c = 2; + } + else if (m_Mesh.m_UV0.Length == m_Mesh.m_VertexCount * 3) + { + c = 3; + } + + for (int v = 0; v < m_Mesh.m_VertexCount; v++) + { + sb.AppendFormat("vt {0} {1}\r\n", m_Mesh.m_UV0[v * c], m_Mesh.m_UV0[v * c + 1]); + } + } + + #endregion + + #region Normals + + if (m_Mesh.m_Normals?.Length > 0) + { + if (m_Mesh.m_Normals.Length == m_Mesh.m_VertexCount * 3) + { + c = 3; + } + else if (m_Mesh.m_Normals.Length == m_Mesh.m_VertexCount * 4) + { + c = 4; + } + + for (int v = 0; v < m_Mesh.m_VertexCount; v++) + { + sb.AppendFormat("vn {0} {1} {2}\r\n", -m_Mesh.m_Normals[v * c], m_Mesh.m_Normals[v * c + 1], m_Mesh.m_Normals[v * c + 2]); + } + } + + #endregion + + #region Face + + int sum = 0; + for (var i = 0; i < m_Mesh.m_SubMeshes.Length; i++) + { + sb.AppendLine($"g {m_Mesh.m_Name}_{i}"); + int indexCount = (int)m_Mesh.m_SubMeshes[i].indexCount; + var end = sum + indexCount / 3; + for (int f = sum; f < end; f++) + { + sb.AppendFormat("f {0}/{0}/{0} {1}/{1}/{1} {2}/{2}/{2}\r\n", m_Mesh.m_Indices[f * 3 + 2] + 1, m_Mesh.m_Indices[f * 3 + 1] + 1, m_Mesh.m_Indices[f * 3] + 1); + } + + sum = end; + } + + #endregion + + sb.Replace("NaN", "0"); + File.WriteAllText(exportFullPath, sb.ToString()); + Logger.Debug($"{item.TypeString}: \"{item.Text}\" exported to \"{exportFullPath}\""); + return true; + } + public static bool ExportConvertFile(AssetItem item, string exportPath, CLIOptions options) { switch (item.Type) @@ -292,6 +389,8 @@ namespace AssetStudioCLI return ExportFont(item, exportPath); case ClassIDType.Sprite: return ExportSprite(item, exportPath, options); + case ClassIDType.Mesh: + return ExportMesh(item, exportPath); default: return ExportRawFile(item, exportPath); } diff --git a/AssetStudioCLI/Options/CLIOptions.cs b/AssetStudioCLI/Options/CLIOptions.cs index 892a30d..e341324 100644 --- a/AssetStudioCLI/Options/CLIOptions.cs +++ b/AssetStudioCLI/Options/CLIOptions.cs @@ -145,7 +145,7 @@ namespace AssetStudioCLI.Options optionName: "-t, --asset-type ", optionDescription: "Specify asset type(s) to export\n" + "\n" + + "audio, video, mesh | all(default)>\n" + "All - export all asset types, which are listed in the values\n" + "*To specify multiple asset types, write them separated by ',' or ';' without spaces\n" + "Examples: \"-t sprite\" or \"-t all\" or \"-t tex2d,sprite,audio\" or \"-t tex2d;sprite;font\"\n", @@ -457,6 +457,9 @@ namespace AssetStudioCLI.Options case "movietexture": o_exportAssetTypes.Value.Add(ClassIDType.MovieTexture); break; + case "mesh": + o_exportAssetTypes.Value.Add(ClassIDType.Mesh); + break; case "all": o_exportAssetTypes.Value = supportedAssetTypes; break; diff --git a/AssetStudioCLI/ReadMe.md b/AssetStudioCLI/ReadMe.md index d768ebd..5fa3618 100644 --- a/AssetStudioCLI/ReadMe.md +++ b/AssetStudioCLI/ReadMe.md @@ -1,7 +1,7 @@ ## AssetStudioCLI CLI version of AssetStudio Mod. -- Supported asset types: `Texture2D`, `Sprite`, `TextAsset`, `MonoBehaviour`, `Font`, `Shader`, `MovieTexture`, `AudioClip`, `VideoClip` -- *There are no plans to add support for `Mesh`/`AnimationClip`/`Animator` for now* +- Supported asset types: `Texture2D`, `Sprite`, `TextAsset`, `MonoBehaviour`, `Font`, `Shader`, `MovieTexture`, `AudioClip`, `VideoClip`, `Mesh` +- *There are no plans to add support for `AnimationClip`/`Animator` for now* ### Usage ``` @@ -28,7 +28,7 @@ General Options: -t, --asset-type Specify asset type(s) to export + audio, video, mesh | all(default)> All - export all asset types, which are listed in the values *To specify multiple asset types, write them separated by ',' or ';' without spaces Examples: "-t sprite" or "-t all" or "-t tex2d,sprite,audio" or "-t tex2d;sprite;font" diff --git a/AssetStudioCLI/Studio.cs b/AssetStudioCLI/Studio.cs index 8bc6c63..c4414ab 100644 --- a/AssetStudioCLI/Studio.cs +++ b/AssetStudioCLI/Studio.cs @@ -105,6 +105,7 @@ namespace AssetStudioCLI assetItem.FullSize = asset.byteSize + m_VideoClip.m_ExternalResources.m_Size; assetItem.Text = m_VideoClip.m_Name; break; + case Mesh _: case MovieTexture _: case TextAsset _: case Font _: