Avoid inclusion of zero-weighted bones in name mapping

This commit is contained in:
ackwell 2024-04-20 20:02:43 +10:00
parent ceb3d39a9a
commit 4a6d94f0fb
2 changed files with 25 additions and 12 deletions

View file

@ -189,15 +189,25 @@ public class MeshImporter(IEnumerable<Node> nodes, IoNotifier notifier)
foreach (var (primitive, primitiveIndex) in node.Mesh.Primitives.WithIndex())
{
// Per glTF specification, an asset with a skin MUST contain skinning attributes on its meshes.
var jointsAccessor = primitive.GetVertexAccessor("JOINTS_0")
?? throw notifier.Exception($"Primitive {primitiveIndex} is skinned but does not contain skinning vertex attributes.");
var jointsAccessor = primitive.GetVertexAccessor("JOINTS_0")?.AsVector4Array();
var weightsAccessor = primitive.GetVertexAccessor("WEIGHTS_0")?.AsVector4Array();
if (jointsAccessor == null || weightsAccessor == null)
throw notifier.Exception($"Primitive {primitiveIndex} is skinned but does not contain skinning vertex attributes.");
// Build a set of joints that are referenced by this mesh.
// TODO: Would be neat to omit 0-weighted joints here, but doing so will require some further work on bone mapping behavior to ensure the unweighted joints can still be resolved to valid bone indices during vertex data construction.
foreach (var joints in jointsAccessor.AsVector4Array())
for (var i = 0; i < jointsAccessor.Count; i++)
{
var joints = jointsAccessor[i];
var weights = weightsAccessor[i];
for (var index = 0; index < 4; index++)
{
// If a joint has absolutely no weight, we omit the bone entirely.
if (weights[index] == 0)
continue;
usedJoints.Add((ushort)joints[index]);
}
}
}

View file

@ -144,10 +144,10 @@ public class VertexAttribute
public static VertexAttribute? BlendIndex(Accessors accessors, IDictionary<ushort, ushort>? boneMap, IoNotifier notifier)
{
if (!accessors.TryGetValue("JOINTS_0", out var accessor))
if (!accessors.TryGetValue("JOINTS_0", out var jointsAccessor))
return null;
if (!accessors.ContainsKey("WEIGHTS_0"))
if (!accessors.TryGetValue("WEIGHTS_0", out var weightsAccessor))
throw notifier.Exception("Mesh contained JOINTS_0 attribute but no corresponding WEIGHTS_0 attribute.");
if (boneMap == null)
@ -160,18 +160,21 @@ public class VertexAttribute
Usage = (byte)MdlFile.VertexUsage.BlendIndices,
};
var values = accessor.AsVector4Array();
var joints = jointsAccessor.AsVector4Array();
var weights = weightsAccessor.AsVector4Array();
return new VertexAttribute(
element,
index =>
{
var gltfIndices = values[index];
var gltfIndices = joints[index];
var gltfWeights = weights[index];
return BuildUByte4(new Vector4(
boneMap[(ushort)gltfIndices.X],
boneMap[(ushort)gltfIndices.Y],
boneMap[(ushort)gltfIndices.Z],
boneMap[(ushort)gltfIndices.W]
gltfWeights.X == 0 ? 0 : boneMap[(ushort)gltfIndices.X],
gltfWeights.Y == 0 ? 0 : boneMap[(ushort)gltfIndices.Y],
gltfWeights.Z == 0 ? 0 : boneMap[(ushort)gltfIndices.Z],
gltfWeights.W == 0 ? 0 : boneMap[(ushort)gltfIndices.W]
));
}
);