Class GltfModel
MeshData), metallic-roughness materials, and encoded texture images.
GltfLoader produces it without touching the GPU or decoding images, so
it is fully headless-testable. toScene3D() then uploads everything
(via Graphics3D/Images) and builds a retained Scene3D;
call it inside a render frame, with a backend running.
Getting to a scene is two costs, and only one of them needs the frame. Decoding the embedded
PNG/JPEG textures is plain CPU work on bytes this object already holds (tens of milliseconds for
a single 2048² base-colour map), while the GPU uploads need the render thread with the
context current. decodeTextures() is the first half on its own, decodeTexturesAsync() runs it on the worker pool, and toScene3D(DecodedTextures)
uploads what it produced. Use those three when the model is loaded while a window is live;
toScene3D() does both halves in the frame and is for setup code that can afford it.
-
Nested Class Summary
Nested ClassesModifier and TypeClassDescriptionstatic final classThe model's texture images decoded to pixels, ready to upload: the CPU half oftoScene3D(), separated so it can be done off the UI thread.static final recordAn encoded image (PNG/JPEG bytes), left encoded untildecodeTextures().static final recordMetallic-roughness material; texture fields indextextures()(-1= none).static final recordstatic final recordstatic final recordOne drawable range of a mesh with its material index (-1= default).static final recordA glTF sampler, kept as the file's GL enums;-1= unspecified.static final record -
Method Summary
Modifier and TypeMethodDescriptionDecodes every texture image some material references, on the calling thread, and returns them fortoScene3D(DecodedTextures)to upload.Decodes the referenced texture images on theUiworker pool, delivering them toonSuccesson the UI thread: the asynchronous form ofdecodeTextures().images()The images the textures sample, still in their file encoding.Materials, indexed as the glTF file numbers them.meshes()Meshes, indexed as the glTF file numbers them.nodes()Every node in the file, flat; the hierarchy is in each node's child indices.intTotal primitives across all meshes (a mesh may have several).int[]Indices intonodes()of the scene's roots, where traversal starts.samplers()Samplers: filtering and wrap modes referenced by textures.textures()Textures, each pairing an image with a sampler.Decodes the textures and uploads everything, then instantiates the node hierarchy as a retainedScene3D:decodeTextures()followed bytoScene3D(DecodedTextures), for setup code that can afford both in one frame.toScene3D(GltfModel.DecodedTextures decoded) Uploadsdecodedand the meshes, and instantiates the node hierarchy as a retainedScene3D: the GPU half oftoScene3D(), for a caller that has already decoded the textures elsewhere.
-
Method Details
-
meshes
Meshes, indexed as the glTF file numbers them. -
materials
Materials, indexed as the glTF file numbers them. -
textures
Textures, each pairing an image with a sampler. -
samplers
Samplers: filtering and wrap modes referenced by textures. -
images
The images the textures sample, still in their file encoding. -
nodes
Every node in the file, flat; the hierarchy is in each node's child indices. -
rootNodes
public int[] rootNodes()Indices intonodes()of the scene's roots, where traversal starts. -
primitiveCount
public int primitiveCount()Total primitives across all meshes (a mesh may have several). -
decodeTextures
Decodes every texture image some material references, on the calling thread, and returns them fortoScene3D(DecodedTextures)to upload. Pure CPU work on bytes this model already holds (no GPU, no frame, no UI thread), so it is safe on a worker, which is where a model loaded while a window is live should do it.Textures no material references are skipped, exactly as
toScene3D()skips them: glTF files commonly carry normal/ORM/emissive maps this renderer does not sample yet, and decoding one costs the same as decoding a map that gets drawn. An image two textures share is decoded once and shared between them.- Returns:
- the decoded images, tied to this model
- Throws:
IllegalStateException- if no backend is running (there is no image decoder installed)
-
decodeTexturesAsync
Decodes the referenced texture images on theUiworker pool, delivering them toonSuccesson the UI thread: the asynchronous form ofdecodeTextures().decoding = model.decodeTexturesAsync() .onSuccess(decoded -> this.pending = decoded) // upload in the next frame .deliverIf(viewport::isShowing) .start();Returned unstarted: register handlers, then call
start(). A job cancelled while it runs stops between images. No disposer is registered and none is needed: the result is decoded pixels and nothing else.What it produces still has to be uploaded, and that half cannot leave the render thread: pass it to
toScene3D(DecodedTextures)from inside a frame.- Throws:
IllegalStateException- if no backend is running (there is no worker pool to use)
-
toScene3D
Decodes the textures and uploads everything, then instantiates the node hierarchy as a retainedScene3D:decodeTextures()followed bytoScene3D(DecodedTextures), for setup code that can afford both in one frame. Lights and camera are the caller's to set on the scene.Must run inside a render frame with a backend installed, and the texture decode it does first runs there too: a model with large base-colour maps stalls that frame for tens of milliseconds per map. Split the two when that matters.
The returned scene owns the uploaded GPU resources: release them with
Scene3D.dispose()once it is no longer drawn (each call to this method uploads a fresh copy). -
toScene3D
Uploadsdecodedand the meshes, and instantiates the node hierarchy as a retainedScene3D: the GPU half oftoScene3D(), for a caller that has already decoded the textures elsewhere.Must run inside a render frame with a backend installed; there is no asynchronous form, because every call it makes needs the GL context current on the render thread. What can be moved off the frame is the decode, and
decodeTexturesAsync()is where that lives.The returned scene owns the uploaded GPU resources: release them with
Scene3D.dispose()once it is no longer drawn (each call uploads a fresh copy, so onedecodedmay build several scenes and each disposes independently).- Parameters:
decoded- textures fromdecodeTextures()ordecodeTexturesAsync()on this model- Throws:
IllegalArgumentException- ifdecodedcame from a different model, whose texture numbering would silently mismatch this one's
-