re: MCOL's 0x5C block is bounding spheres at stride 16 -- the 0.75 was 12/16
The unexplained ~0.75 ratio left at the end of the last iteration was my own
stride. I had read the block as 12-byte points because REGN's vertex section
is 12 bytes, and never checked it: len(0x5C) is not a multiple of 12 in 5 of
the 11 objects, so that stride was never arithmetically possible.
At stride 16 the relation is exact in 11/11 -- max u16 == len(0x5C)/16 - 1 --
and the record reads as {centre f32[3], radius f32}. Powered test, since a
u16 is reached through a specific grid cell: the sphere it names reaches that
cell in 18 559/18 577 = 99.90%, against a 12.02% random-sphere control. Both
fields carry signal (centre alone 26.75%, radius shuffled 70.19%).
The converse -- is the list *exactly* the intersecting set? -- is 0.38%, which
is the expected direction: a bounding sphere is conservative, so membership
implies overlap but not the reverse. The tighter geometry is in 0x54/0x58,
still undecoded. 18 entries (0.10%) go the wrong way and are recorded as open.
tools/re-capture/regn_decode.py is copied unchanged from auto/regn-reader so
the probe's POF0 reader is the known-good one rather than a second copy.
This commit is contained in:
@@ -229,7 +229,7 @@ evidence.)
|
||||
|
||||
position → cell → A record {cell index, count 1, →B, bounding sphere}
|
||||
→ B record {count n, →u16[n]}
|
||||
→ n indices into the 0x5C point block
|
||||
→ n indices into the 0x5C point block ← wrong, see below
|
||||
|
||||
which is the same shape as `REGN`'s `cell → item → refs → geometry`, as the two
|
||||
formats' shared header and shared count-1 convention already suggested.
|
||||
@@ -282,4 +282,96 @@ confident and false statement about `MCOL`'s geometry.
|
||||
|
||||
❔ What the `u16`s index is open. A datum for the next attempt: the maximum
|
||||
`u16` is consistently ≈ **0.75 ×** the point count (923/1 232, 1 019/1 360,
|
||||
1 163/1 552, 59/80) — too consistent to be coincidence, and not explained.
|
||||
1 163/1 552, 59/80) — too consistent to be coincidence, and not explained.
|
||||
|
||||
> **Resolved in the next section.** 0.75 is `12 / 16`: "the point count" was
|
||||
> computed with an assumed 12-byte stride that the block lengths refute. The
|
||||
> `u16`s *do* index this block — at stride 16. Both this test and the 100 %
|
||||
> bound-check above were reading the block wrongly; only the powered one could
|
||||
> say so.
|
||||
## ✅ The `0x5C` block is **bounding spheres at stride 16** — and that explains the 0.75
|
||||
|
||||
**2026-08-26.** The unexplained ≈0.75 ratio left at the end of the section above
|
||||
was **12 / 16**: my own stride. I had been reading the `0x5C` block as 12-byte
|
||||
points because `REGN`'s vertex section is 12 bytes, and never checked the
|
||||
assumption.
|
||||
|
||||
It does not survive the cheapest possible check — **`len(0x5C)` is not a
|
||||
multiple of 12** in 5 of the 11 objects, so a 12-byte stride was never
|
||||
arithmetically possible:
|
||||
|
||||
| object | `len(0x5C)` | ÷12 | ÷16 | max `u16` |
|
||||
|---|---|---|---|---|
|
||||
| `2cf7eb47` | 960 | 80.00 | 60 | 59 |
|
||||
| `cbb99d34` | 192 | 16.00 | 12 | 11 |
|
||||
| `d84a95fb` | 3 488 | 290.67 ❌ | 218 | 217 |
|
||||
| `db066592` | 12 640 | 1 053.33 ❌ | 790 | 789 |
|
||||
| `db61c506` | 2 144 | 178.67 ❌ | 134 | 133 |
|
||||
| `dc44fe0c` | 2 784 | 232.00 | 174 | 173 |
|
||||
| `dc4b0896` | 14 784 | 1 232.00 | 924 | 923 |
|
||||
| `dd89a110` | 18 624 | 1 552.00 | 1 164 | 1 163 |
|
||||
| `df4628c2` | 4 160 | 346.67 ❌ | 260 | 259 |
|
||||
| `e084c13c` | 192 | 16.00 | 12 | 11 |
|
||||
| `e16460cf` | 16 320 | 1 360.00 | 1 020 | 1 019 |
|
||||
|
||||
At stride 16 the relation is not "≈0.75×" but **exact, in 11 / 11 objects**:
|
||||
|
||||
max u16 == len(0x5C) / 16 − 1
|
||||
|
||||
The `u16` array indexes the `0x5C` block at stride 16, and *covers it fully* —
|
||||
the largest index is always the last element.
|
||||
|
||||
### The record is `{ centre f32[3], radius f32 }`
|
||||
|
||||
Read at stride 16, the first three floats lie inside the object's own bounding
|
||||
box in **every record of every object**, and are never unit-length, so this is a
|
||||
position and not a plane normal. The fourth float is a positive scalar which is
|
||||
**not** `|centre|`.
|
||||
|
||||
The powered test is the one the previous section said was needed: a `u16` is
|
||||
reached *through a specific cell*, so the thing it names should be present in
|
||||
that cell. Treating the record as a sphere and the cell as its grid box:
|
||||
|
||||
| | |
|
||||
|---|---|
|
||||
| **referenced sphere intersects the cell that reached it** | **18 559 / 18 577 = 99.90 %** |
|
||||
| a random sphere from the same object (control) | 2 233 / 18 577 = 12.02 % |
|
||||
|
||||
And both halves of the record are load-bearing — ablating either one costs most
|
||||
of the signal:
|
||||
|
||||
| | |
|
||||
|---|---|
|
||||
| centre + radius | **99.90 %** |
|
||||
| centre alone, radius treated as 0 | 26.75 % |
|
||||
| centre kept, radius shuffled within the object | 70.19 % |
|
||||
| radius kept, centre shuffled within the object | 23.74 % |
|
||||
|
||||
So the `0x5C` block is a **broad-phase bounding-sphere array**, and each grid
|
||||
cell's `u16` list names the primitives that reach into that cell — the standard
|
||||
shape for a collision mesh, and the sibling of `REGN`'s `cell → tetrahedra`.
|
||||
|
||||
### The list is a *subset* of what the spheres allow, which is the expected direction
|
||||
|
||||
Testing the converse — is the `u16` set **exactly** the set of spheres that
|
||||
intersect the cell? — gives **17 / 4 488 cells (0.38 %)**, with 46 525 spheres
|
||||
intersecting a cell but absent from its list. That is the right direction and
|
||||
not a problem: a bounding sphere is a conservative bound on the primitive inside
|
||||
it, so "sphere overlaps cell" must be implied by membership but cannot imply it.
|
||||
The tighter true geometry lives in the `0x54` / `0x58` blocks, still undecoded.
|
||||
|
||||
❔ **18 exceptions (0.10 %)** go the wrong way — listed, but the sphere misses
|
||||
the cell, by `dist / radius` of 1.004 to 1.129. They are spread over 7 of the 11
|
||||
objects with no object dominating, so this looks like a small build-time margin
|
||||
rather than a decode error, but it is **not explained** and is recorded as open.
|
||||
|
||||
### The chain, corrected
|
||||
|
||||
position → cell → A record {cell index (x,y,z,1), count 1, →B at +8, bounding sphere}
|
||||
→ B record {u32 count, →u16[n] at +4}
|
||||
→ n indices into the 0x5C array of 16-byte bounding spheres
|
||||
|
||||
❔ Still open: the `0x54` and `0x58` blocks — the actual collision geometry that
|
||||
these spheres bound. Their lengths are **not** a constant multiple of the sphere
|
||||
count (`0x58 / n` is ≈6.0 for the large objects but 6.13 and 6.67 for the two
|
||||
smallest), so at least one of them is variable-stride or has its own count.
|
||||
|
||||
Reference in New Issue
Block a user