diff --git a/Penumbra/Import/Models/Export/MeshExporter.cs b/Penumbra/Import/Models/Export/MeshExporter.cs index 06ca747b..7b51ca31 100644 --- a/Penumbra/Import/Models/Export/MeshExporter.cs +++ b/Penumbra/Import/Models/Export/MeshExporter.cs @@ -34,7 +34,6 @@ public class MeshExporter } } - // TODO: replace bonenamemap with a gltfskeleton public static Mesh Export(MdlFile mdl, byte lod, ushort meshIndex, GltfSkeleton? skeleton) { var self = new MeshExporter(mdl, lod, meshIndex, skeleton?.Names); @@ -74,7 +73,7 @@ public class MeshExporter private Dictionary BuildBoneIndexMap(Dictionary boneNameMap) { - // todo: BoneTableIndex of 255 means null? if so, it should probably feed into the attributes we assign... + // TODO: BoneTableIndex of 255 means null? if so, it should probably feed into the attributes we assign... var xivBoneTable = _mdl.BoneTables[XivMesh.BoneTableIndex]; var indexMap = new Dictionary(); @@ -97,20 +96,25 @@ public class MeshExporter var indices = BuildIndices(); var vertices = BuildVertices(); - // TODO: handle SubMeshCount = 0 + // NOTE: Index indices are specified relative to the LOD's 0, but we're reading chunks for each mesh, so we're specifying the index base relative to the mesh's base. + + if (XivMesh.SubMeshCount == 0) + return [BuildMesh(indices, vertices, 0, (int)XivMesh.IndexCount)]; return _mdl.SubMeshes .Skip(XivMesh.SubMeshIndex) .Take(XivMesh.SubMeshCount) - .Select(submesh => BuildSubMesh(submesh, indices, vertices)) + .Select(submesh => BuildMesh(indices, vertices, (int)(submesh.IndexOffset - XivMesh.StartIndex), (int)submesh.IndexCount)) .ToArray(); } - private IMeshBuilder BuildSubMesh(MdlStructs.SubmeshStruct submesh, IReadOnlyList indices, IReadOnlyList vertices) + private IMeshBuilder BuildMesh( + IReadOnlyList indices, + IReadOnlyList vertices, + int indexBase, + int indexCount + ) { - // Index indices are specified relative to the LOD's 0, but we're reading chunks for each mesh. - var startIndex = (int)(submesh.IndexOffset - XivMesh.StartIndex); - var meshBuilderType = typeof(MeshBuilder<,,,>).MakeGenericType( typeof(MaterialBuilder), _geometryType, @@ -131,12 +135,12 @@ public class MeshExporter var gltfIndices = new List(); // All XIV meshes use triangle lists. - for (var indexOffset = 0; indexOffset < submesh.IndexCount; indexOffset += 3) + for (var indexOffset = 0; indexOffset < indexCount; indexOffset += 3) { var (a, b, c) = primitiveBuilder.AddTriangle( - vertices[indices[indexOffset + startIndex + 0]], - vertices[indices[indexOffset + startIndex + 1]], - vertices[indices[indexOffset + startIndex + 2]] + vertices[indices[indexBase + indexOffset + 0]], + vertices[indices[indexBase + indexOffset + 1]], + vertices[indices[indexBase + indexOffset + 2]] ); gltfIndices.AddRange([a, b, c]); } @@ -157,8 +161,8 @@ public class MeshExporter .Take((int)shapeMesh.ShapeValueCount) ) .Where(shapeValue => - shapeValue.BaseIndicesIndex >= startIndex - && shapeValue.BaseIndicesIndex < startIndex + submesh.IndexCount + shapeValue.BaseIndicesIndex >= indexBase + && shapeValue.BaseIndicesIndex < indexBase + indexCount ) .ToList(); @@ -169,7 +173,7 @@ public class MeshExporter foreach (var shapeValue in shapeValues) morphBuilder.SetVertex( - primitiveVertices[gltfIndices[shapeValue.BaseIndicesIndex - startIndex]].GetGeometry(), + primitiveVertices[gltfIndices[shapeValue.BaseIndicesIndex - indexBase]].GetGeometry(), vertices[shapeValue.ReplacingVertexIndex].GetGeometry() ); } diff --git a/Penumbra/Import/Models/ModelManager.cs b/Penumbra/Import/Models/ModelManager.cs index a56d7168..4f761549 100644 --- a/Penumbra/Import/Models/ModelManager.cs +++ b/Penumbra/Import/Models/ModelManager.cs @@ -73,17 +73,21 @@ public sealed class ModelManager : SingleTaskQueue, IDisposable public void Execute(CancellationToken cancel) { + Penumbra.Log.Debug("Reading skeleton."); var xivSkeleton = BuildSkeleton(cancel); + + Penumbra.Log.Debug("Converting model."); var model = ModelExporter.Export(_mdl, xivSkeleton); + Penumbra.Log.Debug("Building scene."); var scene = new SceneBuilder(); model.AddToScene(scene); + Penumbra.Log.Debug("Saving."); var gltfModel = scene.ToGltf2(); gltfModel.SaveGLTF(_outputPath); } - // TODO: this should be moved to a seperate model converter or something private XivSkeleton? BuildSkeleton(CancellationToken cancel) { if (_sklb == null)