Cleanup, fix tangent/normal mixup.

This commit is contained in:
Ottermandias 2024-01-16 16:34:57 +01:00
parent 47e6e70272
commit da1b9e9e90
3 changed files with 29 additions and 31 deletions

View file

@ -23,7 +23,7 @@ public class MeshExporter
? scene.AddSkinnedMesh(data.Mesh, Matrix4x4.Identity, joints) ? scene.AddSkinnedMesh(data.Mesh, Matrix4x4.Identity, joints)
: scene.AddRigidMesh(data.Mesh, Matrix4x4.Identity); : scene.AddRigidMesh(data.Mesh, Matrix4x4.Identity);
var extras = new Dictionary<string, object>(); var extras = new Dictionary<string, object>(data.Attributes.Length);
foreach (var attribute in data.Attributes) foreach (var attribute in data.Attributes)
extras.Add(attribute, true); extras.Add(attribute, true);

View file

@ -140,7 +140,7 @@ public class SubMeshImporter
private void BuildIndices() private void BuildIndices()
{ {
// TODO: glTF supports a bunch of primitive types, ref. Schema2.PrimitiveType. All this code is currently assuming that it's using plain triangles (4). It should probably be generalised to other formats - I _suspect_ we should be able to get away with evaulating the indices to triangles with GetTriangleIndices, but will need investigation. // TODO: glTF supports a bunch of primitive types, ref. Schema2.PrimitiveType. All this code is currently assuming that it's using plain triangles (4). It should probably be generalised to other formats - I _suspect_ we should be able to get away with evaluating the indices to triangles with GetTriangleIndices, but will need investigation.
_indices = _primitive.GetIndices().Select(idx => (ushort)idx).ToArray(); _indices = _primitive.GetIndices().Select(idx => (ushort)idx).ToArray();
} }

View file

@ -261,7 +261,7 @@ public class VertexAttribute
return null; return null;
} }
var element = new MdlStructs.VertexElement() var element = new MdlStructs.VertexElement
{ {
Stream = 1, Stream = 1,
Type = (byte)MdlFile.VertexType.ByteFloat4, Type = (byte)MdlFile.VertexType.ByteFloat4,
@ -269,13 +269,10 @@ public class VertexAttribute
}; };
// Per glTF specification, TANGENT morph values are stored as vec3, with the W component always considered to be 0. // Per glTF specification, TANGENT morph values are stored as vec3, with the W component always considered to be 0.
var tangentMorphValues = morphAccessors var morphValues = morphAccessors
.Select(a => a.GetValueOrDefault("TANGENT")?.AsVector3Array()) .Select(a => (Tangent: a.GetValueOrDefault("TANGENT")?.AsVector3Array(),
.ToArray(); Normal: a.GetValueOrDefault("NORMAL")?.AsVector3Array()))
.ToList();
var normalMorphValues = morphAccessors
.Select(a => a.GetValueOrDefault("TANGENT")?.AsVector3Array())
.ToArray();
return new VertexAttribute( return new VertexAttribute(
element, element,
@ -283,12 +280,12 @@ public class VertexAttribute
buildMorph: (morphIndex, vertexIndex) => buildMorph: (morphIndex, vertexIndex) =>
{ {
var tangent = tangents[vertexIndex]; var tangent = tangents[vertexIndex];
var tangentDelta = tangentMorphValues[morphIndex]?[vertexIndex]; var tangentDelta = morphValues[morphIndex].Tangent?[vertexIndex];
if (tangentDelta != null) if (tangentDelta != null)
tangent += new Vector4(tangentDelta.Value, 0); tangent += new Vector4(tangentDelta.Value, 0);
var normal = normals[vertexIndex]; var normal = normals[vertexIndex];
var normalDelta = normalMorphValues[morphIndex]?[vertexIndex]; var normalDelta = morphValues[morphIndex].Normal?[vertexIndex];
if (normalDelta != null) if (normalDelta != null)
normal += normalDelta.Value; normal += normalDelta.Value;
@ -297,7 +294,7 @@ public class VertexAttribute
); );
} }
/// <summary> Build a byte array representing bitagent data computed from the provided tangent and normal. </summary> /// <summary> Build a byte array representing bitangent data computed from the provided tangent and normal. </summary>
/// <remarks> XIV primarily stores bitangents, rather than tangents as with most other software, so we calculate on import. </remarks> /// <remarks> XIV primarily stores bitangents, rather than tangents as with most other software, so we calculate on import. </remarks>
private static byte[] BuildBitangent(Vector4 tangent, Vector3 normal) private static byte[] BuildBitangent(Vector4 tangent, Vector3 normal)
{ {
@ -322,7 +319,8 @@ public class VertexAttribute
var uvs = uvAccessor.AsVector2Array(); var uvs = uvAccessor.AsVector2Array();
// TODO: Surface this in the UI. // TODO: Surface this in the UI.
Penumbra.Log.Warning("Calculating tangents, this may result in degraded light interaction. For best results, ensure tangents are caculated or retained during export from 3D modelling tools."); Penumbra.Log.Warning(
"Calculating tangents, this may result in degraded light interaction. For best results, ensure tangents are caculated or retained during export from 3D modelling tools.");
var vertexCount = positions.Count; var vertexCount = positions.Count;
@ -344,16 +342,16 @@ public class VertexAttribute
var position2 = positions[vertexIndex2]; var position2 = positions[vertexIndex2];
var position3 = positions[vertexIndex3]; var position3 = positions[vertexIndex3];
var texcoord1 = uvs[vertexIndex1]; var texCoord1 = uvs[vertexIndex1];
var texcoord2 = uvs[vertexIndex2]; var texCoord2 = uvs[vertexIndex2];
var texcoord3 = uvs[vertexIndex3]; var texCoord3 = uvs[vertexIndex3];
// Calculate deltas for the position XYZ, and texcoord UV. // Calculate deltas for the position XYZ, and texcoord UV.
var edge1 = position2 - position1; var edge1 = position2 - position1;
var edge2 = position3 - position1; var edge2 = position3 - position1;
var uv1 = texcoord2 - texcoord1; var uv1 = texCoord2 - texCoord1;
var uv2 = texcoord3 - texcoord1; var uv2 = texCoord3 - texCoord1;
// Solve. // Solve.
var r = 1.0f / (uv1.X * uv2.Y - uv1.Y * uv2.X); var r = 1.0f / (uv1.X * uv2.Y - uv1.Y * uv2.X);
@ -378,7 +376,7 @@ public class VertexAttribute
bitangents[vertexIndex3] += bitangent; bitangents[vertexIndex3] += bitangent;
} }
// All the triangles have been calcualted, normalise the results for each vertex. // All the triangles have been calculated, normalise the results for each vertex.
var result = new Vector4[vertexCount]; var result = new Vector4[vertexCount];
for (var vertexIndex = 0; vertexIndex < vertexCount; vertexIndex++) for (var vertexIndex = 0; vertexIndex < vertexCount; vertexIndex++)
{ {