-
Notifications
You must be signed in to change notification settings - Fork 113
max2gltf_plan
title: Max → glTF/Blend Conversion and Assimp-Route Parity — Plan description: Whole-max-file conversion to glTF (and .blend via Blender import), plus expanding the assimp exporter to match the direct-from-max route's coverage and fidelity — differential-gated against the existing corpus published: true date: 2026-07-14T00:00:00.000Z tags: editor: markdown dateCreated: 2026-07-14T00:00:00.000Z
Plan agreed 2026-07-14 (Kaetemi). Two deliverables, one architecture:
-
max2gltf: whole-
.max-file conversion to glTF 2.0 withnel_*extras, as a newpipeline_max_export_gltftool. max2blend is a derivative, not a sibling:.blendis not writable externally in practice, so the .blend deliverable is a headlessblender --background --pythonpass that imports our glTF (optionally interpretingnel_*extras into Blender-native constructs) and saves. Build glTF once, get both targets. -
Assimp-route parity: expand
mesh_export/mesh_utilsuntil, for every asset class the direct route exports,max → glTF → assimp route → artifactmatchesmax → direct route → artifactunder the existing corpus comparators.
- Asset liberation: the recovered .max corpus (8634 files) becomes editable in living tools for the first time since the Nevrax artist PCs were sold. Max-under-Wine leaves the loop.
- Role inversion: the direct-from-max route (corpus-gated, byte/floateq tiers) becomes the frozen reference validator; Blender/glTF becomes the living authoring path. New content and edits flow through the assimp route; the legacy corpus proves that route faithful.
-
Downstream alignment: the tutorial/WebGL work (tutorial_roadmap) authors in Blender/glTF; the lightmapper's missing producer (c) (
.lmscenefrom assimp, §11-lm) falls out of parity work for free.
-
Branch at the pre-build model, never re-decode.
pipeline_max_export_gltfshares the same T1 parse andpipeline_max_export_commonextraction as the direct exporters: glTF geometry buffers are written from the sameCMeshBuild-level dataexport_shapeconsumes, tracks from the same decoded dataexport_animconsumes. glTF buffers are raw IEEE float32, so values survive byte-exact. Fidelity testing then measures format loss only, not decode drift. (Same move as the.lmsceneintermediate, in an interoperable container.) -
NeL semantics ride in
extras, per the established convention (NeL-Specific glTF Extras): per-key scalars,%.9gforced-decimal floats, readers prefer extras and fall back to standard glTF fields. Extras (not a vendor extension) because Blender maps extras to custom properties and round-trips them — artists see and can edit NeL appdata (LOD settings, collision/SWT flags, lightmap params) as plain custom props. The skeleton pipeline already does exactly this (pipeline_max_export_skel --gltf→mesh_utilsexportSkels(), bit-exact TRS vianel_t*/r*/s*keys) — it is the beachhead and the pattern to copy. -
Assimp handles geometry/skins/nodes only; NeL extras are parsed from the glTF JSON directly. Assimp's aiMetadata plumbing is version-fragile; we control both ends of the file, so a small JSON pass for
nel_*keys is more robust. Pin the assimp version; keep aiProcess post-processing at zero (no tangent generation, no node collapsing, no unit scaling — every one is a fidelity leak).
| Subsystem | glTF carrier | Fidelity class |
|---|---|---|
| Meshes (pos/normal/UV/vcolor), hierarchy | standard glTF buffers | lossless (float32 verbatim) |
| Materials incl. UV-scroll (waterfalls) | PBR + KHR_texture_transform + nel_* extras for NeL-specific params |
lossless via extras |
| Skinning | glTF skins (NeL's 4-weight limit fits) | lossless |
| Skeletons | done today (extras TRS) | lossless (proven) |
| Animations | sampled curves for interop plus exact NeL track data as an extras blob | dual: sampled view lossy, blob lossless; Blender edits invalidate the blob (documented, detectable) |
| PatchMesh (zones, patch props) | stays direct-route (optionally opaque extras blob + tessellated viewing proxy later) | out of scope for parity |
| Appdata (LOD, collision, SWT, lightmap params) |
nel_* extras per node/material |
lossless |
Animation is the honest problem case: glTF has no Bezier/TCB keys, and the tangent semantics were hard-won (anim-export corpus). Sampled curves serve Blender authoring; the extras blob serves corpus round-tripping. Zones stay native — with the improvised ligo heightmap the zone sources are a direct-route concern regardless (see §10z-ring).
For every corpus file and every asset class: export via the direct route AND via max → glTF → mesh_export, compare artifacts with the existing field-level comparators (shape floateq tiers, skel, anim, ig). New ctest pipeline_max_gltf_corpus in the *_corpus.py shape, self-skipping without the corpus, budgeted like the other gates. This is the strongest available correctness story and it is cheap — every tier already exists.
mesh_utils today: static meshes (position/normal/UV, materials via assimp_material, scene_meta) and bit-exact skeletons. Declared TODOs in assimp_shape.cpp: multi-LOD/MRM builds, water shapes, particle systems, remanence, flare, pacs prim. No animations, no IG, no .lmscene.
-
max2gltf: static meshes + materials + node hierarchy + IG placement, differential-gated against the shape/ig corpora. (Largest asset volume, no open questions.) — DONE 2026-07-14 (design doc §13-gltf): full corpus differential green, every co-produced .shape (2230) and .ig byte-identical; ctest
pipeline_max_gltf_corpus. Staged import skips: multilod assembly, MRM morph targets. - Skinned meshes (skeletons already done) — skel/shape gates.
-
Animations: sampled tier +
nel_*track blob; anim corpus gate on the blob path, tolerance tier on the sampled path. -
.lmsceneemission from the assimp route — closes lightmapper producer (c) (§11-lm). -
Blender post-pass (
max2blend): headless import + save, plus optional bpy interpretation of extras; visual spot-checks, not gated. - Later/optional: PatchMesh extras blob + viewing proxy; particle systems and the other
assimp_shape.cppTODO classes as needed.
- No zone/landscape production through glTF.
- No "improving" exported values in the converter — it emits what the direct route's extraction produced, verbatim.
- No reliance on assimp preserving extras — extras always read from the glTF JSON directly.
See also: Pipeline Max — Design and Coherency Contract (§11-lm lightmapper architecture, §9 shape corpus tiers), NeL-Specific glTF Extras, Tutorial Tech Tree.