Level of Detail — the whole feature, in five phases
Mesh objects can now carry cheaper stand-in geometry. LOD0 stays SceneObject::mesh; the extra levels live in a new lods list, each with the relative screen height below which it takes over. Screen height rather than distance was deliberate — the same 30 m can't mean the same thing for a pebble and a cathedral, or for a 60° and a 90° FOV (core/Lod.h). Pieces that landed:
- Data + selection math: real world-space bounding spheres (the old
boundRadius()never looked at the mesh at all), a purelodPick()with a hysteresis dead band so an object sitting on a boundary can't flicker, andbias/maxLevelquality knobs. - Renderer: one resolve pass per frame feeds both the skinning pre-count and the draw builder, so all eight scene passes agree on which level they're looking at. Skinned meshes have an explicit fallback rule.
- Inspector: a draggable band ruler with a live needle, per-level mesh + threshold rows, triangle deltas, four warning classes, read-only when prefab-sealed, plus a LOD Preview toggle that shows the switching live in the viewport.
- Import:
_LOD1,_LOD2… suffixed nodes in FBX/GLB/glTF are grouped into one object automatically (validated on synthetic node trees and a real.gltffixture). - Project-wide settings: a Level of Detail section in Game Settings, a player-side
lodBiaspreference, andSet / Get LOD Biasscript nodes.
Performance: the hierarchy stopped being quadratic
Object identity is a string and lookup was a linear scan — on the 709-object Gomenstein3D scene that came to 2.66 million string comparisons per frame. Two fixes, neither of which asks anything of the ~100 places that mutate objects_: a validate-on-read id → index accelerator (99.97% hit rate; a stale entry costs a scan, never a wrong answer), and a one-pass first-child/next-sibling chain for the Hierarchy tree.
Two-column Project browser
The bottom Project tab is now a folder tree │ folder contents │ asset inspector layout: breadcrumb, search-scope chips (whole project vs. this folder), list/grid view with an icon-size slider, draggable splitter, F2 rename, reveal-an-asset, Alt+click recursive expand. Folders are scanned lazily — only what's open. It moved out of AppUI.cpp into its own AppProjectPanel.cpp with the path/geometry rules as testable free functions.
Editor & runtime odds and ends
- Add > Mesh now groups imported meshes into submenus by source file — otherwise a LOD-heavy project turns the menu into a wall of near-identical names.
- Post-FX effects can be switched off per effect: it stays configured on the scene but is compiled out of the chain entirely — no pipeline, no pass, no cost, in editor preview, play and builds alike.
- Hierarchy: multi-object drag, Shift+click range select over visible rows, and one undo step per gesture instead of one per touched object.
- Camera Preview can look through the avatar's eye in Prefab Mode, which is what makes a viewmodel prefab placeable — the stage origin is the eye the weapon hangs off.
- Player abilities:
Can Run/Can Jumpswitches on the FPS Avatar, plusSet Can Run/Set Can Jump/Player Abilitiesnodes — take an ability away for a cutscene or exhaustion and Stop restores the authored values. - Screen Size node (width / height / aspect) in both the shader graph and post-FX codegen — pixel grids and letterboxing now survive a window resize.
- Sprite Atlas: a per-object UV0 sub-rect (
spriteCols × spriteRows, row-majorspriteFrame) reaching the GPU throughScenePC::uvST. It's a renderer property, not a material one, so one shared sheet serves every enemy while each keeps its own frame. - Level Modeller maps: the
.lmmapimporter reads multi-page lightmap atlases (bakedPages), with the page joining (texture, colour) as part of the material slot key. Old single-page maps load unchanged.
