Export attributes

This commit is contained in:
ackwell 2024-01-11 00:34:18 +11:00
parent 64aed56f7c
commit 182550ce15

View file

@ -13,20 +13,31 @@ namespace Penumbra.Import.Models.Export;
public class MeshExporter public class MeshExporter
{ {
public class Mesh(IEnumerable<IMeshBuilder<MaterialBuilder>> meshes, NodeBuilder[]? joints) public class Mesh(IEnumerable<MeshData> meshes, NodeBuilder[]? joints)
{ {
public void AddToScene(SceneBuilder scene) public void AddToScene(SceneBuilder scene)
{ {
foreach (var mesh in meshes) foreach (var data in meshes)
{ {
if (joints == null) var instance = joints != null
scene.AddRigidMesh(mesh, Matrix4x4.Identity); ? scene.AddSkinnedMesh(data.Mesh, Matrix4x4.Identity, joints)
else : scene.AddRigidMesh(data.Mesh, Matrix4x4.Identity);
scene.AddSkinnedMesh(mesh, Matrix4x4.Identity, joints);
var extras = new Dictionary<string, object>();
foreach (var attribute in data.Attributes)
extras.Add(attribute, true);
instance.WithExtras(JsonContent.CreateFrom(extras));
} }
} }
} }
public struct MeshData
{
public IMeshBuilder<MaterialBuilder> Mesh;
public string[] Attributes;
}
public static Mesh Export(MdlFile mdl, byte lod, ushort meshIndex, MaterialBuilder[] materials, GltfSkeleton? skeleton) public static Mesh Export(MdlFile mdl, byte lod, ushort meshIndex, MaterialBuilder[] materials, GltfSkeleton? skeleton)
{ {
var self = new MeshExporter(mdl, lod, meshIndex, materials, skeleton?.Names); var self = new MeshExporter(mdl, lod, meshIndex, materials, skeleton?.Names);
@ -103,31 +114,33 @@ public class MeshExporter
} }
/// <summary> Build glTF meshes for this XIV mesh. </summary> /// <summary> Build glTF meshes for this XIV mesh. </summary>
private IMeshBuilder<MaterialBuilder>[] BuildMeshes() private MeshData[] BuildMeshes()
{ {
var indices = BuildIndices(); var indices = BuildIndices();
var vertices = BuildVertices(); var vertices = BuildVertices();
// 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. // 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) if (XivMesh.SubMeshCount == 0)
return [BuildMesh($"mesh {_meshIndex}", indices, vertices, 0, (int)XivMesh.IndexCount)]; return [BuildMesh($"mesh {_meshIndex}", indices, vertices, 0, (int)XivMesh.IndexCount, 0)];
return _mdl.SubMeshes return _mdl.SubMeshes
.Skip(XivMesh.SubMeshIndex) .Skip(XivMesh.SubMeshIndex)
.Take(XivMesh.SubMeshCount) .Take(XivMesh.SubMeshCount)
.WithIndex() .WithIndex()
.Select(subMesh => BuildMesh($"mesh {_meshIndex}.{subMesh.Index}", indices, vertices, .Select(subMesh => BuildMesh($"mesh {_meshIndex}.{subMesh.Index}", indices, vertices,
(int)(subMesh.Value.IndexOffset - XivMesh.StartIndex), (int)subMesh.Value.IndexCount)) (int)(subMesh.Value.IndexOffset - XivMesh.StartIndex), (int)subMesh.Value.IndexCount,
subMesh.Value.AttributeIndexMask))
.ToArray(); .ToArray();
} }
/// <summary> Build a mesh from the provided indices and vertices. A subset of the full indices may be built by providing an index base and count. </summary> /// <summary> Build a mesh from the provided indices and vertices. A subset of the full indices may be built by providing an index base and count. </summary>
private IMeshBuilder<MaterialBuilder> BuildMesh( private MeshData BuildMesh(
string name, string name,
IReadOnlyList<ushort> indices, IReadOnlyList<ushort> indices,
IReadOnlyList<IVertexBuilder> vertices, IReadOnlyList<IVertexBuilder> vertices,
int indexBase, int indexBase,
int indexCount int indexCount,
uint attributeMask
) )
{ {
var meshBuilderType = typeof(MeshBuilder<,,,>).MakeGenericType( var meshBuilderType = typeof(MeshBuilder<,,,>).MakeGenericType(
@ -190,12 +203,23 @@ public class MeshExporter
} }
} }
// Named morph targets aren't part of the specification, however `MESH.extras.targetNames`
// is a commonly-accepted means of providing the data.
meshBuilder.Extras = JsonContent.CreateFrom(new Dictionary<string, object>() meshBuilder.Extras = JsonContent.CreateFrom(new Dictionary<string, object>()
{ {
{ "targetNames", shapeNames }, { "targetNames", shapeNames },
}); });
return meshBuilder; var attributes = Enumerable.Range(0, 32)
.Where(index => ((attributeMask >> index) & 1) == 1)
.Select(index => _mdl.Attributes[index])
.ToArray();
return new MeshData
{
Mesh = meshBuilder,
Attributes = attributes,
};
} }
/// <summary> Read in the indices for this mesh. </summary> /// <summary> Read in the indices for this mesh. </summary>