Skip to content

fix(MeshHelper): compressed mesh bone weights and UV sets - #390

Open
nichinichisou0609 wants to merge 2 commits into
K0lb3:masterfrom
nichinichisou0609:fix/compressed-mesh
Open

nichinichisou0609 wants to merge 2 commits into
K0lb3:masterfrom
nichinichisou0609:fix/compressed-mesh

Conversation

@nichinichisou0609

Copy link
Copy Markdown
Contributor

Meshes imported with Mesh Compression store their vertex data in m_CompressedMesh. Two values decoded from it are wrong; one commit each, and each commit adds a regression test that fails on its parent and passes with the fix.

  • Implied fourth bone weight. A compressed mesh stores up to three 5-bit weights per vertex and implies the fourth when they do not add up to 31. Since MeshHandler: Fix weightsData dequantization error #338 the running sum counts 5-bit units, but the implied weight is still computed as 1 - sum, so weights 10, 10, 5 give a fourth weight of -24 and every skinned vertex with four influences gets a negative weight. It is now (31 - sum) / 31, the same formula as AssetStudio's DecompressCompressedMesh, and the four weights of a vertex add up to 1.
  • Third and later UV sets. With m_UVInfo set, the UV sets are stored back to back in m_UV. The read offset was assigned the size of the current set instead of advancing by it, so every set after the second one was read from the position of the second set and returned a copy of it. The offset now accumulates, as in AssetStudio.

tests/test_compressed_mesh.py (new) decodes a synthetic CompressedMesh: one vertex whose fourth weight is implied and one with a single full weight, and three UV sets with 2, 3 and 2 components in channels 0, 1 and 3.

Validation on Windows x86_64, CPython 3.11.13, pytest 9.1.1. The compiled path uses the UnityPyBoost extension of the 1.25.4 wheel; UnityPyBoost/ has no changes between 1.25.4 and 417d595.

Check Result
New tests against unmodified 417d595 2 failed
Each commit's test against its parent commit fails before, passes after, with and without the extension
Complete suite, with / without the extension 50 passed / 50 passed
ruff check and ruff format --check Passed
python -m pytest -q tests/test_compressed_mesh.py
python -m pytest -q tests

Compressed meshes store up to three 5-bit weights per vertex and imply
the fourth one when they do not add up to 31. The running sum counts
5-bit units since K0lb3#338, but the implied weight was still computed as
1 - sum, which gives a negative weight (-24 for weights 10, 10, 5).
It is now (31 - sum) / 31, so the four weights of a vertex add up to 1.

tests/test_compressed_mesh.py decodes a synthetic CompressedMesh with
one vertex that needs the implied weight and one with a single full
weight.
With m_UVInfo set, a compressed mesh stores its texture coordinate sets
back to back in m_UV. The read offset was assigned the size of the
current set instead of advancing by it, so every set after the second
one was read from the position of the second set and came back as a
copy of it. The offset now accumulates, as the sets are stored.

tests/test_compressed_mesh.py decodes three sets with 2, 3 and 2
components (sets 0, 1 and 3) from a synthetic CompressedMesh.

This branch has not been deployed

No deployments
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant