diff --git a/Penumbra/Import/Models/Export/MeshExporter.cs b/Penumbra/Import/Models/Export/MeshExporter.cs index 75283732..5f67114d 100644 --- a/Penumbra/Import/Models/Export/MeshExporter.cs +++ b/Penumbra/Import/Models/Export/MeshExporter.cs @@ -63,8 +63,10 @@ public class MeshExporter _boneIndexMap = BuildBoneIndexMap(boneNameMap); var usages = _mdl.VertexDeclarations[_meshIndex].VertexElements - .Select(element => (MdlFile.VertexUsage)element.Usage) - .ToImmutableHashSet(); + .ToImmutableDictionary( + element => (MdlFile.VertexUsage)element.Usage, + element => (MdlFile.VertexType)element.Type + ); _geometryType = GetGeometryType(usages); _materialType = GetMaterialType(usages); @@ -263,15 +265,15 @@ public class MeshExporter } /// Get the vertex geometry type for this mesh's vertex usages. - private Type GetGeometryType(IReadOnlySet usages) + private Type GetGeometryType(IReadOnlyDictionary usages) { - if (!usages.Contains(MdlFile.VertexUsage.Position)) + if (!usages.ContainsKey(MdlFile.VertexUsage.Position)) throw new Exception("Mesh does not contain position vertex elements."); - if (!usages.Contains(MdlFile.VertexUsage.Normal)) + if (!usages.ContainsKey(MdlFile.VertexUsage.Normal)) return typeof(VertexPosition); - if (!usages.Contains(MdlFile.VertexUsage.Tangent1)) + if (!usages.ContainsKey(MdlFile.VertexUsage.Tangent1)) return typeof(VertexPositionNormal); return typeof(VertexPositionNormalTangent); @@ -302,20 +304,32 @@ public class MeshExporter } /// Get the vertex material type for this mesh's vertex usages. - private Type GetMaterialType(IReadOnlySet usages) + private Type GetMaterialType(IReadOnlyDictionary usages) { - // TODO: IIUC, xiv's uv2 is usually represented as the second two components of a vec4 uv attribute - add support. + var uvCount = 0; + if (usages.TryGetValue(MdlFile.VertexUsage.UV, out var type)) + uvCount = type switch + { + MdlFile.VertexType.Half2 => 1, + MdlFile.VertexType.Half4 => 2, + _ => throw new Exception($"Unexpected UV vertex type {type}.") + }; + var materialUsages = ( - usages.Contains(MdlFile.VertexUsage.UV), - usages.Contains(MdlFile.VertexUsage.Color) + uvCount, + usages.ContainsKey(MdlFile.VertexUsage.Color) ); return materialUsages switch { - (true, true) => typeof(VertexColor1Texture1), - (true, false) => typeof(VertexTexture1), - (false, true) => typeof(VertexColor1), - (false, false) => typeof(VertexEmpty), + (2, true) => typeof(VertexColor1Texture2), + (2, false) => typeof(VertexTexture2), + (1, true) => typeof(VertexColor1Texture1), + (1, false) => typeof(VertexTexture1), + (0, true) => typeof(VertexColor1), + (0, false) => typeof(VertexEmpty), + + _ => throw new Exception("Unreachable."), }; } @@ -337,13 +351,34 @@ public class MeshExporter ToVector2(attributes[MdlFile.VertexUsage.UV]) ); + // XIV packs two UVs into a single vec4 attribute. + + if (_materialType == typeof(VertexTexture2)) + { + var uv = ToVector4(attributes[MdlFile.VertexUsage.UV]); + return new VertexTexture2( + new Vector2(uv.X, uv.Y), + new Vector2(uv.Z, uv.W) + ); + } + + if (_materialType == typeof(VertexColor1Texture2)) + { + var uv = ToVector4(attributes[MdlFile.VertexUsage.UV]); + return new VertexColor1Texture2( + ToVector4(attributes[MdlFile.VertexUsage.Color]), + new Vector2(uv.X, uv.Y), + new Vector2(uv.Z, uv.W) + ); + } + throw new Exception($"Unknown material type {_skinningType}"); } /// Get the vertex skinning type for this mesh's vertex usages. - private Type GetSkinningType(IReadOnlySet usages) + private Type GetSkinningType(IReadOnlyDictionary usages) { - if (usages.Contains(MdlFile.VertexUsage.BlendWeights) && usages.Contains(MdlFile.VertexUsage.BlendIndices)) + if (usages.ContainsKey(MdlFile.VertexUsage.BlendWeights) && usages.ContainsKey(MdlFile.VertexUsage.BlendIndices)) return typeof(VertexJoints4); return typeof(VertexEmpty);