|
| 1 | +# FMA torso gaussian splat — real BodyParts3D geometry, two cockpit pages |
| 2 | + |
| 3 | +> 2026-06-24 · status: in progress |
| 4 | +> The `/fma` heart slice (PR #51) renders the FMA partonomy with *synthesized* |
| 5 | +> 8:8-HHTL layout because FMA itself has **zero geometry**. This adds a **torso** |
| 6 | +> rendered from **real anatomical meshes** — BodyParts3D, which keys 3D meshes |
| 7 | +> directly on FMA concept IDs — across two new cockpit pages. |
| 8 | +
|
| 9 | +## The convergence |
| 10 | + |
| 11 | +- **FMA partonomy** (`part_of`) = mereotopological containment in BodyParts3D |
| 12 | + (NAR 2009, Table 1: `A part_of B` ⟺ `A° ⊂ B°`, coveredBy). So the HHTL |
| 13 | + `[container:identity]` cascade *is* the spatial nesting. |
| 14 | +- **BodyParts3D** (DBCLS, CC-BY 4.0) realizes FMA concepts as OBJ meshes in one |
| 15 | + shared whole-body frame. `concept id` column **is** the FMA id. |
| 16 | +- Z-Anatomy / the Unity app are curated atlases on the same data; we use the raw |
| 17 | + FMA-keyed OBJ (no Blender needed). |
| 18 | + |
| 19 | +## Data (measured) |
| 20 | + |
| 21 | +- Root `FMA7181 trunk` → **178 concepts, 577 OBJ meshes, ~694K verts**, all present. |
| 22 | + Regions: thoracic segment (548 meshes), body wall (81), abdominal (24), perineum (4). |
| 23 | + The heart (PR #51) nests inside (`trunk → … → content of middle mediastinum → heart`). |
| 24 | +- Source (external, NOT committed): `dbarchive.biosciencedbc.jp/.../partof_BP3D_4.0_obj_99.zip` |
| 25 | + + `partof_inclusion_relation_list.txt` / `partof_element_parts.txt` / `partof_parts_list_e.txt`. |
| 26 | +- License: **CC-BY 4.0** — attribution: "BodyParts3D, © The Database Center for |
| 27 | + Life Science licensed under CC Attribution 4.0 International". |
| 28 | + |
| 29 | +## Pipeline |
| 30 | + |
| 31 | +``` |
| 32 | +BodyParts3D (FMA partof tree + FJ OBJ meshes) |
| 33 | + → tools/bake_torso_splat.py (BFS FMA7181 → concepts → FJ meshes → vertices, |
| 34 | + recenter/normalize, region-colour, downsample) |
| 35 | + → cockpit/public/torso.splat (SPL1 binary: real positions + rgb + opacity) |
| 36 | + → /torso-live three.js orbit (reads SPL1; the "live orbit") |
| 37 | + → torso.ply (Inria) → ndarray splat3d_flex → frames → /torso (the "splat", CPU) |
| 38 | +``` |
| 39 | + |
| 40 | +`splat3d` (ndarray, CPU-SIMD, no GPU) renders bake-side via its own 1.95 toolchain |
| 41 | +(q2 stays clean of the ndarray dep). Both pages read ONE asset → identical geometry. |
| 42 | + |
| 43 | +## Checklist |
| 44 | + |
| 45 | +- [x] `tools/bake_torso_splat.py` — BodyParts3D → SPL1 gaussian asset + manifest |
| 46 | + (231K gaussians, 577 meshes, 102 structures; muted pastel per-structure hues) |
| 47 | +- [x] `cockpit/public/torso.splat` (3.7 MB) + `torso.manifest.json` (attribution/legend) |
| 48 | +- [x] SPL1 TS decoder + `/torso-live` three.js orbit page + route |
| 49 | +- [x] `/torso` splat3d CPU render: scratchpad `torso-render` driver reads SPL1 → |
| 50 | + `Gaussian3D` → ndarray::hpc::splat3d turntable (no Inria .ply needed) → |
| 51 | + 20 JPEG frames in `cockpit/public/torso-frames/` → `/torso` viewer page + route |
| 52 | +- [x] attribution surfaced in-UI; tsc clean |
| 53 | +- [ ] PR |
| 54 | + |
| 55 | +Notes: |
| 56 | +- The CPU render runs under ndarray's own 1.95 toolchain (scratchpad project, |
| 57 | + path-dep on ../ndarray) — q2's workspace stays free of the ndarray dep. |
| 58 | + ~6.6 s/frame on the scalar path (no AVX target-cpu in the scratchpad project); |
| 59 | + correctness verified by viewing the rendered frames. |
| 60 | +- Colours: golden-angle hue per structure at S=0.34 V=0.78 (muted, per request). |
0 commit comments