This commit is contained in:
Passive 2024-07-22 19:35:35 +10:00
parent 6a1f1988d9
commit 69a79131d0
3 changed files with 121 additions and 199 deletions

View file

@ -315,25 +315,10 @@ public class MeshExporter
MdlFile.VertexType.NByte4 => new Vector4(reader.ReadByte() / 255f, reader.ReadByte() / 255f, reader.ReadByte() / 255f, reader.ReadByte() / 255f), MdlFile.VertexType.NByte4 => new Vector4(reader.ReadByte() / 255f, reader.ReadByte() / 255f, reader.ReadByte() / 255f, reader.ReadByte() / 255f),
MdlFile.VertexType.Half2 => new Vector2((float)reader.ReadHalf(), (float)reader.ReadHalf()), MdlFile.VertexType.Half2 => new Vector2((float)reader.ReadHalf(), (float)reader.ReadHalf()),
MdlFile.VertexType.Half4 => new Vector4((float)reader.ReadHalf(), (float)reader.ReadHalf(), (float)reader.ReadHalf(), (float)reader.ReadHalf()), MdlFile.VertexType.Half4 => new Vector4((float)reader.ReadHalf(), (float)reader.ReadHalf(), (float)reader.ReadHalf(), (float)reader.ReadHalf()),
MdlFile.VertexType.UShort4 => ReadUShort4(reader), MdlFile.VertexType.UShort4 => reader.ReadBytes(8),
var other => throw _notifier.Exception<ArgumentOutOfRangeException>($"Unhandled vertex type {other}"), var other => throw _notifier.Exception<ArgumentOutOfRangeException>($"Unhandled vertex type {other}"),
}; };
} }
private byte[] ReadUShort4(BinaryReader reader)
{
var buffer = reader.ReadBytes(8);
var byteValues = new byte[8];
byteValues[0] = buffer[0];
byteValues[4] = buffer[1];
byteValues[1] = buffer[2];
byteValues[5] = buffer[3];
byteValues[2] = buffer[4];
byteValues[6] = buffer[5];
byteValues[3] = buffer[6];
byteValues[7] = buffer[7];
return byteValues;
}
/// <summary> Get the vertex geometry type for this mesh's vertex usages. </summary> /// <summary> Get the vertex geometry type for this mesh's vertex usages. </summary>
private Type GetGeometryType(IReadOnlyDictionary<MdlFile.VertexUsage, MdlFile.VertexType> usages) private Type GetGeometryType(IReadOnlyDictionary<MdlFile.VertexUsage, MdlFile.VertexType> usages)

View file

@ -196,7 +196,9 @@ public class MeshImporter(IEnumerable<Node> nodes, IoNotifier notifier)
// Per glTF specification, an asset with a skin MUST contain skinning attributes on its meshes. // Per glTF specification, an asset with a skin MUST contain skinning attributes on its meshes.
var joints0Accessor = primitive.GetVertexAccessor("JOINTS_0")?.AsVector4Array(); var joints0Accessor = primitive.GetVertexAccessor("JOINTS_0")?.AsVector4Array();
var weights0Accessor = primitive.GetVertexAccessor("WEIGHTS_0")?.AsVector4Array(); var weights0Accessor = primitive.GetVertexAccessor("WEIGHTS_0")?.AsVector4Array();
var joints1Accessor = primitive.GetVertexAccessor("JOINTS_1")?.AsVector4Array();
var weights1Accessor = primitive.GetVertexAccessor("WEIGHTS_1")?.AsVector4Array();
if (joints0Accessor == null || weights0Accessor == null) if (joints0Accessor == null || weights0Accessor == null)
throw notifier.Exception($"Primitive {primitiveIndex} is skinned but does not contain skinning vertex attributes."); throw notifier.Exception($"Primitive {primitiveIndex} is skinned but does not contain skinning vertex attributes.");
@ -205,6 +207,8 @@ public class MeshImporter(IEnumerable<Node> nodes, IoNotifier notifier)
{ {
var joints = joints0Accessor[i]; var joints = joints0Accessor[i];
var weights = weights0Accessor[i]; var weights = weights0Accessor[i];
var joints1 = joints1Accessor?[i];
var weights1 = weights1Accessor?[i];
for (var index = 0; index < 4; index++) for (var index = 0; index < 4; index++)
{ {
// If a joint has absolutely no weight, we omit the bone entirely. // If a joint has absolutely no weight, we omit the bone entirely.
@ -212,26 +216,11 @@ public class MeshImporter(IEnumerable<Node> nodes, IoNotifier notifier)
continue; continue;
usedJoints.Add((ushort)joints[index]); usedJoints.Add((ushort)joints[index]);
}
} if (joints1 != null && weights1 != null && weights1.Value[index] != 0)
{
var joints1Accessor = primitive.GetVertexAccessor("JOINTS_1")?.AsVector4Array(); usedJoints.Add((ushort)joints1.Value[index]);
var weights1Accessor = primitive.GetVertexAccessor("WEIGHTS_1")?.AsVector4Array(); }
if (joints1Accessor == null || weights1Accessor == null)
continue;
for (var i = 0; i < joints1Accessor.Count; i++)
{
var joints = joints1Accessor[i];
var weights = weights1Accessor[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

@ -132,72 +132,50 @@ public class VertexAttribute
{ {
if (!accessors.ContainsKey("JOINTS_1")) if (!accessors.ContainsKey("JOINTS_1"))
throw notifier.Exception("Mesh contained WEIGHTS_1 attribute but no corresponding JOINTS_1 attribute."); throw notifier.Exception("Mesh contained WEIGHTS_1 attribute but no corresponding JOINTS_1 attribute.");
var element = new MdlStructs.VertexElement()
{
Stream = 0,
Type = (byte)MdlFile.VertexType.UShort4,
Usage = (byte)MdlFile.VertexUsage.BlendWeights,
};
var weights0 = weights0Accessor.AsVector4Array();
var weights1 = weights1Accessor.AsVector4Array();
return new VertexAttribute(
element,
index => {
var weight0 = weights0[index];
var weight1 = weights1[index];
var originalData = BuildUshort4(weight0, weight1);
var byteValues = originalData.Select(x => (byte)Math.Round(x * 255f)).ToArray();
return AdjustByteArray(byteValues, originalData);
}
);
} }
else
var element = new MdlStructs.VertexElement()
{ {
var element = new MdlStructs.VertexElement() Stream = 0,
Type = (byte)MdlFile.VertexType.UShort4,
Usage = (byte)MdlFile.VertexUsage.BlendWeights,
};
var weights0 = weights0Accessor.AsVector4Array();
var weights1 = weights1Accessor?.AsVector4Array();
return new VertexAttribute(
element,
index => {
var weight0 = weights0[index];
var weight1 = weights1?[index];
var originalData = BuildUshort4(weight0, weight1 ?? Vector4.Zero);
var byteValues = originalData.Select(x => (byte)Math.Round(x * 255f)).ToArray();
return AdjustByteArray(byteValues, originalData);
}
);
/*var element = new MdlStructs.VertexElement()
{
Stream = 0,
Type = (byte)MdlFile.VertexType.NByte4,
Usage = (byte)MdlFile.VertexUsage.BlendWeights,
};
var weights0 = weights0Accessor.AsVector4Array();
return new VertexAttribute(
element,
index =>
{ {
Stream = 0, var weight0 = weights0[index];
Type = (byte)MdlFile.VertexType.UShort4, var originalData = new[] { weight0.X, weight0.Y, weight0.Z, weight0.W };
Usage = (byte)MdlFile.VertexUsage.BlendWeights, var byteValues = originalData.Select(x => (byte)Math.Round(x * 255f)).ToArray();
}; var newByteValues = AdjustByteArray(byteValues, originalData);
if (!newByteValues.SequenceEqual(byteValues))
var weights0 = weights0Accessor.AsVector4Array(); notifier.Warning("Adjusted blend weights to maintain precision.");
return newByteValues;
return new VertexAttribute( });*/
element,
index => {
var weight0 = weights0[index];
var weight1 = Vector4.Zero;
var originalData = BuildUshort4(weight0, weight1);
var byteValues = originalData.Select(x => (byte)Math.Round(x * 255f)).ToArray();
return AdjustByteArray(byteValues, originalData);
}
);
/*var element = new MdlStructs.VertexElement()
{
Stream = 0,
Type = (byte)MdlFile.VertexType.NByte4,
Usage = (byte)MdlFile.VertexUsage.BlendWeights,
};
var weights0 = weights0Accessor.AsVector4Array();
return new VertexAttribute(
element,
index =>
{
var weight0 = weights0[index];
var originalData = new[] { weight0.X, weight0.Y, weight0.Z, weight0.W };
var byteValues = originalData.Select(x => (byte)Math.Round(x * 255f)).ToArray();
var newByteValues = AdjustByteArray(byteValues, originalData);
if (!newByteValues.SequenceEqual(byteValues))
notifier.Warning("Adjusted blend weights to maintain precision.");
return newByteValues;
});*/
}
} }
private static byte[] AdjustByteArray(byte[] byteValues, float[] originalValues) private static byte[] AdjustByteArray(byte[] byteValues, float[] originalValues)
@ -241,100 +219,77 @@ public class VertexAttribute
if (boneMap == null) if (boneMap == null)
throw notifier.Exception("Mesh contained JOINTS_0 attribute but no bone mapping was created."); throw notifier.Exception("Mesh contained JOINTS_0 attribute but no bone mapping was created.");
var joints0 = joints0Accessor.AsVector4Array(); var joints0 = joints0Accessor.AsVector4Array();
var weights0 = weights0Accessor.AsVector4Array(); var weights0 = weights0Accessor.AsVector4Array();
accessors.TryGetValue("JOINTS_1", out var joints1Accessor);
if (accessors.TryGetValue("JOINTS_1", out var joints1Accessor)) accessors.TryGetValue("WEIGHTS_1", out var weights1Accessor);
var element = new MdlStructs.VertexElement
{ {
if (!accessors.TryGetValue("WEIGHTS_1", out var weights1Accessor)) Stream = 0,
throw notifier.Exception("Mesh contained JOINTS_1 attribute but no corresponding WEIGHTS_1 attribute."); Type = (byte)MdlFile.VertexType.UShort4,
Usage = (byte)MdlFile.VertexUsage.BlendIndices,
};
var element = new MdlStructs.VertexElement var joints1 = joints1Accessor?.AsVector4Array();
var weights1 = weights1Accessor?.AsVector4Array();
return new VertexAttribute(
element,
index =>
{ {
Stream = 0, var gltfIndices0 = joints0[index];
Type = (byte)MdlFile.VertexType.UShort4, var gltfWeights0 = weights0[index];
Usage = (byte)MdlFile.VertexUsage.BlendIndices, var gltfIndices1 = joints1?[index];
}; var gltfWeights1 = weights1?[index];
var v0 = new Vector4(
var joints1 = joints1Accessor.AsVector4Array(); gltfWeights0.X == 0 ? 0 : boneMap[(ushort)gltfIndices0.X],
var weights1 = weights1Accessor.AsVector4Array(); gltfWeights0.Y == 0 ? 0 : boneMap[(ushort)gltfIndices0.Y],
gltfWeights0.Z == 0 ? 0 : boneMap[(ushort)gltfIndices0.Z],
return new VertexAttribute( gltfWeights0.W == 0 ? 0 : boneMap[(ushort)gltfIndices0.W]
element, );
index =>
Vector4 v1;
if (gltfIndices1 != null && gltfWeights1 != null)
{ {
var gltfIndices0 = joints0[index]; v1 = new Vector4(
var gltfWeights0 = weights0[index]; gltfWeights1.Value.X == 0 ? 0 : boneMap[(ushort)gltfIndices1.Value.X],
var gltfIndices1 = joints1[index]; gltfWeights1.Value.Y == 0 ? 0 : boneMap[(ushort)gltfIndices1.Value.Y],
var gltfWeights1 = weights1[index]; gltfWeights1.Value.Z == 0 ? 0 : boneMap[(ushort)gltfIndices1.Value.Z],
var v0 = new Vector4( gltfWeights1.Value.W == 0 ? 0 : boneMap[(ushort)gltfIndices1.Value.W]
gltfWeights0.X == 0 ? 0 : boneMap[(ushort)gltfIndices0.X],
gltfWeights0.Y == 0 ? 0 : boneMap[(ushort)gltfIndices0.Y],
gltfWeights0.Z == 0 ? 0 : boneMap[(ushort)gltfIndices0.Z],
gltfWeights0.W == 0 ? 0 : boneMap[(ushort)gltfIndices0.W]
); );
var v1 = new Vector4(
gltfWeights1.X == 0 ? 0 : boneMap[(ushort)gltfIndices1.X],
gltfWeights1.Y == 0 ? 0 : boneMap[(ushort)gltfIndices1.Y],
gltfWeights1.Z == 0 ? 0 : boneMap[(ushort)gltfIndices1.Z],
gltfWeights1.W == 0 ? 0 : boneMap[(ushort)gltfIndices1.W]
);
var byteValues = BuildUshort4(v0, v1);
return byteValues.Select(x => (byte)x).ToArray();
} }
); else
} {
else v1 = Vector4.Zero;
}
var byteValues = BuildUshort4(v0, v1);
return byteValues.Select(x => (byte)x).ToArray();
}
);
/*var element = new MdlStructs.VertexElement()
{ {
var element = new MdlStructs.VertexElement Stream = 0,
{ Type = (byte)MdlFile.VertexType.UByte4,
Stream = 0, Usage = (byte)MdlFile.VertexUsage.BlendIndices,
Type = (byte)MdlFile.VertexType.UShort4, };
Usage = (byte)MdlFile.VertexUsage.BlendIndices,
};
return new VertexAttribute(
element,
index =>
{
var gltfIndices0 = joints0[index];
var gltfWeights0 = weights0[index];
var v0 = new Vector4(
gltfWeights0.X == 0 ? 0 : boneMap[(ushort)gltfIndices0.X],
gltfWeights0.Y == 0 ? 0 : boneMap[(ushort)gltfIndices0.Y],
gltfWeights0.Z == 0 ? 0 : boneMap[(ushort)gltfIndices0.Z],
gltfWeights0.W == 0 ? 0 : boneMap[(ushort)gltfIndices0.W]
);
var v1 = Vector4.Zero;
var byteValues = BuildUshort4(v0, v1);
return byteValues.Select(x => (byte)x).ToArray(); return new VertexAttribute(
} element,
); index =>
/*var element = new MdlStructs.VertexElement()
{ {
Stream = 0, var gltfIndices = joints0[index];
Type = (byte)MdlFile.VertexType.UByte4, var gltfWeights = weights0[index];
Usage = (byte)MdlFile.VertexUsage.BlendIndices, return BuildUByte4(new Vector4(
}; gltfWeights.X == 0 ? 0 : boneMap[(ushort)gltfIndices.X],
gltfWeights.Y == 0 ? 0 : boneMap[(ushort)gltfIndices.Y],
return new VertexAttribute( gltfWeights.Z == 0 ? 0 : boneMap[(ushort)gltfIndices.Z],
element, gltfWeights.W == 0 ? 0 : boneMap[(ushort)gltfIndices.W]
index => ));
{ }
var gltfIndices = joints0[index]; );*/
var gltfWeights = weights0[index];
return BuildUByte4(new Vector4(
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]
));
}
);*/
}
} }
public static VertexAttribute? Normal(Accessors accessors, IEnumerable<Accessors> morphAccessors) public static VertexAttribute? Normal(Accessors accessors, IEnumerable<Accessors> morphAccessors)
@ -620,18 +575,11 @@ public class VertexAttribute
(byte)Math.Round(input.Z * 255f), (byte)Math.Round(input.Z * 255f),
(byte)Math.Round(input.W * 255f), (byte)Math.Round(input.W * 255f),
]; ];
private static float[] BuildUshort4(Vector4 v0, Vector4 v1) private static float[] BuildUshort4(Vector4 v0, Vector4 v1) =>
{ new[]
var buf = new float[8]; {
buf[0] = v0.X; v0.X, v0.Y, v0.Z, v0.W,
buf[4] = v1.X; v1.X, v1.Y, v1.Z, v1.W,
buf[1] = v0.Y; };
buf[5] = v1.Y;
buf[2] = v0.Z;
buf[6] = v1.Z;
buf[3] = v0.W;
buf[7] = v1.W;
return buf;
}
} }