Add tfrag LOD selection, morph weights and parent linkage
The block header's float at +0x08 gives L and the switch distances are [D0, D1, D2] = [6L, 4L, 2L] world units -- 192/128/64 on every level measured. The distance test uses the patch's bounding sphere truncated to integers against trunc(D * 1024), not the sphere's centre, so a patch straddling a threshold takes the coarser mode. Six modes result: LOD 2, LOD 1 collapse, LOD 1 morph, LOD 0 collapse, LOD 0 morph, LOD 0. A morph weight runs 0 to 1 across its tier's band. Past the far edge an entry is not blended but replaced by its first parent -- a collapse. The tested property is that distance never moves back to a finer mode, swept across the whole range, because that is what keeps terrain from popping as the camera moves. The four V4_8 parent arrays are classified by VU address and an unrecognised address is now an error, which is a real check: all 18,102 patches still parse. Every recorded parent resolves to real vertex info and real positions, and no common entry claims a parent. That is as far as it goes, and the limit is a finding rather than a rounding error. The addresses are not unique: on level 0 patch 1, unk_indices_2_lod_01_addr == parent_indices_lod_0_addr == 291, with unk_06 and unk_0a both zero, so nothing but unpacking order separates them. Across all 27 levels 57,782 of 374,349 LOD entries resolve, and 316,548 unresolved LOD-0 entries against 28,739 resolved is far too lopsided to be genuine -- either the arrays are misassigned where addresses collide, or RAC2's positions_lod_0_count means something other than RAC1's. Only 3,274 of 18,102 patches carry enough V4_8 bytes to cover positions_lod_01_count + positions_lod_0_count + extras. The vertex-info tiers themselves are confirmed: the addresses at +9 and +11 match the observed V4_16 unpacks and the three tier counts sum to vert_count on every patch, so the header layout is right and it is specifically the parent arrays that are open. Ruled out so far: address-only classification (collides) and one-parent-per-position (fails on 15,000 patches). Not yet tried: ordering by VU address instead of by declaration, and using unk_06/unk_0a to suppress an empty tier before falling through. Written up in plan/level-assets.md.
This commit is contained in:
+12
-2
@@ -20,7 +20,7 @@ early, while they are still cheap to retire.
|
||||
header, and the `data` extent is parsed as a container of byte ranges. The
|
||||
geometry decompresses: level 0 yields 16,969,296 bytes of level content
|
||||
from a 9.7 MB stream.
|
||||
- [ ] Next: tfrag LOD selection and morphing, then the first drawable frame.
|
||||
- [ ] Next: tfrag parent indices, then the first drawable frame.
|
||||
|
||||
The disc being the exact build the reference projects pin is the single
|
||||
biggest favourable fact so far: no disc conversion, no regional timing work,
|
||||
@@ -141,7 +141,17 @@ Phase 1 hands over the extents; this phase works out what each one contains.
|
||||
96.3% with real detail. Verified visually via the new
|
||||
`gc-extract dump-texture`, because a wrong lookup still yields a
|
||||
well-formed image of the wrong thing.
|
||||
- [ ] tfrag LOD selection: the switch and morph rules in `TfragProc`.
|
||||
- [x] **tfrag LOD selection.** Switch distances scale as `[6L, 4L, 2L]` from the
|
||||
block header's float; six draw modes result from testing the bounding
|
||||
sphere against `trunc(D * 1024)`, so a patch straddling a threshold takes
|
||||
the coarser mode and distance never moves back to finer detail. Morph
|
||||
weights run 0..1 across each tier's band, and collapse replaces an entry
|
||||
with its first parent rather than blending it.
|
||||
- [ ] tfrag parent indices: the four V4_8 arrays are classified by VU address,
|
||||
but the addresses collide (`unk_06` and `unk_0a` are zero, so an absent
|
||||
tier shares the next one's address). 57,782 of 374,349 LOD entries
|
||||
resolve; the 316,548 unresolved LOD-0 entries are far too lopsided to be
|
||||
genuine. Tried and ruled out in `plan/level-assets.md`.
|
||||
- [ ] `gameplay` — begins `WAD` + a per-level byte, and does *not* decode with
|
||||
the WAD LZ77 decoder. All 27 levels fail identically, so the input is
|
||||
wrong rather than the decoder. Ruled out: bit order, header length, the
|
||||
|
||||
Reference in New Issue
Block a user