Skip to content

Compile a root's declared position and orientation; repair --fix-tangents for zero-length tangents - #110

Merged
plenarius merged 1 commit into
mainfrom
fix/root-transform
Oct 21, 2026
Merged

plenarius merged 1 commit into
mainfrom
fix/root-transform

Conversation

@plenarius

Copy link
Copy Markdown
Owner

Follow-ups to #109 from layonara/nwn-module#476 and #55.

Root transform.

  • The compiler never wrote position or orientation controllers on the model root. The game's compiler writes each when the ASCII declares it (explicit zeros too), and nothing otherwise.
  • New engine fixtures zcm_rootpos, zcm_rootzero and zcm_rootnone are the game's compiles of those three cases. The compile now matches all three, and they fail without the fix.
  • Layonara's ttr01_z01_01 (root at z −1.75) moved up 1.75 m in a round trip. Of the game's ASCII models, only dag_chest declares a root transform.

Zero-length tangents.

  • The game draws a mesh's tangents as given, and on a normal-mapped mesh a zero-length one shows as a white streak. That's Layonara's Center Craft Hall: tin01_l16_06 had 7 to 57 per mesh, from its source file and from values the parser could not read.
  • compile keeps them, as the game does, with a warning.
  • check's tangent_validation reports them, and drops them with --fix.
  • repair --fix-tangents, part of --all, drops a mesh's tangents when any has zero length, so the compiler computes them from the geometry. That's what the game does for a mesh without tangents; on tin01_l16_06 the computed ones have none of zero length.
  • Binaries were already safe: the decompiler drops a tangent stream that isn't unit length unless the header asks for tangents.

parity_compile --cli passes --force when the CLI has it. Since #109 the CLI refuses to write a binary whose render lists the mutations damaged, while the library compiles it, and that comparison is about the bytes. The fixture-only CI run doesn't use --cli, which is how #109 missed it.

Testing.

  • In game: tin01_l16_06 as it was before haks PR fix(compiler): don't split skin vertices at material boundaries #23 (with the zero tangents), repaired with --fix-tangents and compiled: no white strips in the Center Craft Hall.
  • Corpus parity on the game's models passes: decompile (25,597), parse (7,235 plus mutations) and compile (32,832, also through the CLI).
  • New tests: the three root fixtures, TestZeroLengthTangents (compile warning, drop, recompute) and TestTangentValidationZeroLength.

Ported to python/: the root rule, the declared keywords and the compile warning. README lists --fix-tangents and --force.
Qt: plenarius/cleanmodels-qt (feat/fix-tangents). Spec: plenarius/nwn-mdl-spec (spec/root-controllers).

…ents for zero-length tangents

Root transform: the compiler never wrote position or orientation controllers
on the model root. The game's compiler writes each when the ASCII declares
it (explicit zeros too) and nothing otherwise: engine compiles of the new
fixtures zcm_rootpos, zcm_rootzero and zcm_rootnone, which the compile now
matches. Layonara's ttr01_z01_01 (root at z -1.75) moved up 1.75 m in a
round trip; of the game's ASCII models only dag_chest declares one.

Zero-length tangents: the game draws a mesh's tangents as given, and on a
normal-mapped mesh a zero-length one shows as a white streak (Layonara's
Center Craft Hall, tin01_l16_06: 7 to 57 per mesh, from its source file and
from values the parser could not read). Compile keeps them, as the game does,
with a warning; check's tangent_validation reports them (and drops them with
--fix); repair --fix-tangents, part of --all, drops a mesh's tangents when any
has zero length, so the compiler computes them from the geometry, as the game
does for a mesh without them. The computed ones on tin01_l16_06 have none of
zero length. Binaries were already safe: the decompiler drops a tangent stream
that is not unit length unless the header asks for tangents.

parity_compile --cli passes --force when the CLI has it: since the merged
render lists change (#109) the CLI refuses a damaged binary the mutations
make, which the library compiles; the comparison is about the bytes.

Ported to python/ (compiler root rule, declared keywords, compile warning).
@plenarius
plenarius merged commit 42f71b3 into main Oct 21, 2026
9 checks passed
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