Skip to content

threedim: new 3D asset, scene-graph and object processes (from #2109 stack)#2122

Open
jcelerier wants to merge 9 commits into
plane/interopfrom
planf/objects
Open

threedim: new 3D asset, scene-graph and object processes (from #2109 stack)#2122
jcelerier wants to merge 9 commits into
plane/interopfrom
planf/objects

Conversation

@jcelerier

Copy link
Copy Markdown
Member

The first cluster of new 3D objects from split/threedim, on top of the interop stack (#2121). These processes are cross-coupled (they share loader/scene headers, so intermediate subsets don't build) and therefore land as one coherent unit — the same way the scene rework did.

Stacked on #2121; retargets to master as the stack merges.

What it adds

  • Asset & geometry loaders: glTF/FBX import (via new fastgltf and ufbx submodules), unified AssetLoader, image/buffer/texture helpers, ObjLoaderGeometryLoader rename.
  • Cameras, lights, transforms: Camera, CameraArray, CameraSwitch, Light, Transform3D.
  • Scene-graph family: scene preprocessor, filters, switch/selector/group, duplicator, from-meshes, inspector, resource routing.
  • Buffer/texture inject & extract into/out of scene resources.
  • Materials & rendering: PBRMesh, MaterialOverride, ConfigurePrimitive, Instancer, shadow-cascade setup.
  • Animation: AnimationPlayer, humanoid retargeting, inverse kinematics.
  • Text: text-to-mesh and text-to-texture.

The existing ModelDisplay, RenderPipeline and Splat nodes keep their current scene-aware versions (the old Splat/ node is intentionally preserved). The point-cloud PrimitiveCloud family lands in a follow-up PR (it needs the spz/zstd submodules).

Validation

  • Builds cleanly against the stack (all plugins).
  • ctest: 17/17.
  • Process + device factory sweeps under ASAN + UBSan — the process sweep now constructs and round-trips all the new 3D process models (Camera/Light/Transform/AssetLoader/Scene*/Instancer/PBR/Animation/IK/Text/Inject/Extract): 0 memory errors, 0 undefined-behavior in score's own code, 0 crashes.

🤖 Generated with Claude Code

@jcelerier
jcelerier force-pushed the plane/interop branch 2 times, most recently from 07a445e to bc681f8 Compare July 17, 2026 14:10
jcelerier added a commit that referenced this pull request Jul 17, 2026
FIX-GLTF (GltfParser.cpp): validate every accessor's byte range against its
bufferView/buffer BEFORE extract_primitive dereferences it — a crafted glTF
with an out-of-range accessor offset/count read past the buffer (heap OOB).
Adds accessor_within_bounds / range_within_view / buffer_source_byte_size
guards + an all-accessors sweep in validate().

Test: test_regression_splat_reload (Splat ports stable across save/reload).

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_014rZgzE8JjWvHDtaVUhxpLE
jcelerier added a commit that referenced this pull request Jul 17, 2026
FIX-GLTF (GltfParser.cpp): validate every accessor's byte range against its
bufferView/buffer BEFORE extract_primitive dereferences it — a crafted glTF
with an out-of-range accessor offset/count read past the buffer (heap OOB).
Adds accessor_within_bounds / range_within_view / buffer_source_byte_size
guards + an all-accessors sweep in validate().

Test: test_regression_splat_reload (Splat ports stable across save/reload).

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_014rZgzE8JjWvHDtaVUhxpLE
jcelerier added a commit that referenced this pull request Jul 17, 2026
FIX-GLTF (GltfParser.cpp): validate every accessor's byte range against its
bufferView/buffer BEFORE extract_primitive dereferences it — a crafted glTF
with an out-of-range accessor offset/count read past the buffer (heap OOB).
Adds accessor_within_bounds / range_within_view / buffer_source_byte_size
guards + an all-accessors sweep in validate().

Test: test_regression_splat_reload (Splat ports stable across save/reload).

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_014rZgzE8JjWvHDtaVUhxpLE
jcelerier added a commit that referenced this pull request Jul 17, 2026
test_unit_image_loader (22 cases / 881 assertions): score::gfx
decodeImageFrom{Path,Memory} (gfx TextureLoader) + Threedim LDR ImageLoader +
ArrayToTexture, across PNG8/16, JPEG, BMP, TIFF8/16, WebP, GIF, TGA, PPM/PGM,
SVG, ICO — exact dimensions, exact/toleranced pixels, RGBA byte order, straight
alpha, top-left origin, 16-bit precision, and graceful rejection of truncated /
garbage / empty / wrong-MIME inputs (ASAN-clean).

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_014rZgzE8JjWvHDtaVUhxpLE
@jcelerier
jcelerier force-pushed the planf/objects branch 2 times, most recently from 7c5c25d to f79c9cc Compare July 18, 2026 13:37
@jcelerier
jcelerier force-pushed the planf/objects branch 2 times, most recently from 3fe10b1 to 5f1b3e3 Compare July 18, 2026 20:38
jcelerier and others added 9 commits July 18, 2026 23:11
(cherry picked from commit a012d1cbdc702366d16093fda112fb3bba4a78dd)
fastgltf's configure step downloads the simdjson single-header when no
simdjson::simdjson target or system package exists; network-isolated
builds (Flatpak, Nix) fail there. Vendor the pinned single-header copy
(v3.12.3, what fastgltf would download) so the build is self-contained.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_014rZgzE8JjWvHDtaVUhxpLE
Adds the new 3D processes that build on the scene pipeline: geometry and
asset loaders (glTF/FBX via fastgltf/ufbx, image and buffer helpers),
cameras, lights and transforms, the scene-graph family (preprocessor,
filters, switch/selector/group, duplicator, from-meshes, inspector),
buffer/texture inject and extract, PBR materials and instancing, animation
with humanoid retargeting and inverse kinematics, and text-to-mesh/texture.

These are cross-coupled (they share loader/scene headers), so they land as
one coherent unit. The existing ModelDisplay, RenderPipeline and Splat nodes
keep their current scene-aware versions.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_014rZgzE8JjWvHDtaVUhxpLE
Brings the new 3D objects up to their final state, folding in the bug
fixes made after they were first added: Instancer GPU use-after-free and
instance-count bounds, OBJ and glTF index bounds-checks, GPU-resource
release on partial-init failure, Camera stale transform-slot, extraction
buffer sizing and SRB layout, cubemap face sizing and UBO slots, the
spherical and triplanar projection shader fixes, animation speed and
skinned-mesh deformation, and the review-round corrections.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_014rZgzE8JjWvHDtaVUhxpLE
ObjectGallery --list [filter]     : print every registered process (name,
                                    uuid), optionally filtered by name.
ObjectGallery --filter <substr>   : open a window, instantiate each matching
              [--seconds N]         object, route its texture output to the
                                    window and play, so all the texture-
                                    producing objects can be watched at once.

Built on the MinimalGUIApplication + window-device path the gfx testers use,
so it drives the real engine. A handy way to try the whole object catalogue.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_014rZgzE8JjWvHDtaVUhxpLE
GltfParser.cpp: validate every accessor's byte range against its
bufferView/buffer BEFORE extract_primitive dereferences it — a crafted glTF
with an out-of-range accessor offset/count read past the buffer (heap OOB).
Adds accessor_within_bounds / range_within_view / buffer_source_byte_size
guards + an all-accessors sweep in validate().

Test: test_regression_splat_reload (Splat ports stable across save/reload).

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_014rZgzE8JjWvHDtaVUhxpLE
test_unit_image_loader (22 cases / 881 assertions): score::gfx
decodeImageFrom{Path,Memory} (gfx TextureLoader) + Threedim LDR ImageLoader +
ArrayToTexture, across PNG8/16, JPEG, BMP, TIFF8/16, WebP, GIF, TGA, PPM/PGM,
SVG, ICO — exact dimensions, exact/toleranced pixels, RGBA byte order, straight
alpha, top-left origin, 16-bit precision, and graceful rejection of truncated /
garbage / empty / wrong-MIME inputs (ASAN-clean).

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_014rZgzE8JjWvHDtaVUhxpLE
Deduplicates the raw QImage handling and picks up decodeImageFromMemory's
RGBA8888 canonicalization and footer-less TGA fallback.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_014rZgzE8JjWvHDtaVUhxpLE
On glibc < 2.40 there is no _Float16, so the R16F/RGBA16F case compiled to
nothing and the texture was uploaded with uninitialized bytes. Convert with
a software IEEE 754 binary16 (round-to-nearest-even) fallback instead.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_014rZgzE8JjWvHDtaVUhxpLE
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant