Skip to content

Commit 3bce41d

Browse files
committed
feat: ensure accurate texture coords in ao
While the arithmetics I've used are correct, small differences in operations have caused texture coordinates to occasionally differ ever-so-slightly from the original (we're talking one bit difference). Replacing it with something that more closely resembles calculations that the game is performing during asset loading seems to resolve it.
1 parent 5095bf0 commit 3bce41d

2 files changed

Lines changed: 22 additions & 15 deletions

File tree

Core/Conversion/Formats/ArtObjectConverter.cs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -83,7 +83,7 @@ private static ArtObject LoadFromTransmissionFormat(Stream modelStream)
8383
var entry = entries.First();
8484
var artObject = ConfiguredJsonSerializer.DeserializeFromNode<ArtObject>(entry.Extras) ?? new ArtObject();
8585
artObject.Geometry = entry.Geometry.WithReversedWindingIndices();
86-
FezGeometryUtil.RecalculateCubemapTexCoords(artObject.Geometry, artObject.Size);
86+
FezGeometryUtil.RecalculateCubemapTexCoords(artObject.Geometry, artObject.Size, true);
8787

8888
(Stream? albedo, Stream? emission) = GltfUtil.ExtractCubemapStreams(modelRoot);
8989
LoadCubemap(ref artObject, albedo, emission);
@@ -96,7 +96,7 @@ private static void AppendGeometryStream(ref ArtObject data, Stream geometryStre
9696
var geometries = WavefrontObjUtil.FromWavefrontObjStream<Matrix>(geometryStream);
9797
if (geometries.Count < 1) return;
9898
data.Geometry = geometries.First().Value.WithReversedWindingIndices();
99-
FezGeometryUtil.RecalculateCubemapTexCoords(data.Geometry, data.Size);
99+
FezGeometryUtil.RecalculateCubemapTexCoords(data.Geometry, data.Size, true);
100100
}
101101

102102
private static void LoadCubemap(ref ArtObject data, Stream? albedoStream, Stream? emissionStream)

Core/Helpers/FezGeometryUtil.cs

Lines changed: 20 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -8,26 +8,33 @@ internal static class FezGeometryUtil
88
{
99
/// Recalculates texture coordinates to match what game does with them during loading process.
1010
public static void RecalculateCubemapTexCoords<VertexType>(
11-
IndexedPrimitives<VertexInstance, VertexType> geometry, Vector3 geometryBounds
11+
IndexedPrimitives<VertexInstance, VertexType> geometry, Vector3 geometryBounds, bool widen
1212
) {
13+
// keeping arithmetics vaguely similar to the one in game to prevent number mismatch after conversion
1314
foreach (var vertex in geometry.Vertices)
1415
{
15-
(int textureOffset, Vector3 xAxis, Vector3 yAxis) = vertex.NormalByte switch
16+
(float textureOffset, Vector3 xAxis, Vector3 yAxis) = vertex.NormalByte switch
1617
{
17-
5 => (0, new Vector3(1, 0, 0), new Vector3(0, -1, 0)), // front
18-
3 => (1, new Vector3(0, 0, -1), new Vector3(0, -1, 0)), // right
19-
2 => (2, new Vector3(-1, 0, 0), new Vector3(0, -1, 0)), // back
20-
0 => (3, new Vector3(0, 0, 1), new Vector3(0, -1, 0)), // left
21-
4 => (4, new Vector3(1, 0, 0), new Vector3(0, 0, 1)), // top
22-
1 => (5, new Vector3(1, 0, 0), new Vector3(0, 0, -1)), // bottom
18+
5 => (0, new Vector3(1, 0, 0), new Vector3(0, 1, 0)), // front
19+
3 => (0.25f, new Vector3(0, 0, -1), new Vector3(0, 1, 0)), // right
20+
2 => (0.375f, new Vector3(-1, 0, 0), new Vector3(0, 1, 0)), // back
21+
0 => (0.375f, new Vector3(0, 0, 1), new Vector3(0, 1, 0)), // left
22+
4 => (0.5f, new Vector3(1, 0, 0), new Vector3(0, 0, 1)), // top
23+
1 => (0.625f, new Vector3(1, 0, 0), new Vector3(0, 0, 1)), // bottom
2324
_ => (0, new Vector3(), new Vector3())
2425
};
2526

26-
var texturePlanePosition = vertex.Position / geometryBounds;
27-
vertex.TextureCoordinate = new Vector2(
28-
(Vector3.Dot(texturePlanePosition, xAxis) + 0.5f + textureOffset) / 6.0f,
29-
Vector3.Dot(texturePlanePosition, yAxis) + 0.5f
30-
);
27+
var texturePlanePosition = (Vector3.One - vertex.Normal) * (vertex.Position / geometryBounds) * 2f + vertex.Normal;
28+
var texturePlanePositionNormalized = texturePlanePosition / 2f + new Vector3(0.5f, 0.5f, 0.5f);
29+
float uCoordinate = Vector3.Dot(xAxis, texturePlanePositionNormalized);
30+
float vCoordinate = Vector3.Dot(yAxis, texturePlanePositionNormalized);
31+
if (vertex.NormalByte != 4)
32+
{
33+
vCoordinate = 1.0f - vCoordinate;
34+
}
35+
36+
float finalUCoordinate = (textureOffset + uCoordinate / 8f) * (widen ? 1.3333334f : 1.0f);
37+
vertex.TextureCoordinate = new Vector2(finalUCoordinate, vCoordinate);
3138
}
3239
}
3340

0 commit comments

Comments
 (0)