pub fn try_export_glb_streaming_bounded(
content: &[u8],
opts: &GltfOptions,
) -> Result<(Vec<u8>, GltfStats), ExportError>Expand description
Bounded-memory single-GLB export: two passes over the deterministic mesh
stream (retain_emitted_meshes: false, peak input = one batch).
Pass 1 ([plan_bounded_glb]) records per-mesh METADATA only (counts, local
bbox, colour, ids, content-hash) plus the world AABB; the complete glTF JSON
is then built and the final GLB Vec is preallocated at its exact container
size. Pass 2 ([write_bounded_glb]) re-streams the same meshes and bakes
their bytes straight into the output at precomputed offsets. Peak memory = the
final artifact + one batch + metadata — never the whole model’s MeshData,
never a growing three-run scratch, and never a second full copy from a final
concatenation.
Fail-closed on both ends, decided after pass 1 so neither costs the second
meshing pass or the output allocation: an empty visible set returns
ExportError::NoRenderGeometry (see try_export_glb for why a zero-mesh
GLB is not a valid artifact, #4685), and a projected GLB over the glTF 4 GiB
limit returns ExportError::TooLarge carrying the projected byte size
(#1516). project_glb_size decides the size question up front.
Tradeoffs vs the in-memory assembler (build_gltf):
- rep-identity instancing is done here too, under the same policy
collate_refsapplies. The vertex data needs every occurrence co-resident; the grouping decision does not, so it is made from the plan. Quantized, the dequant rides a child node under the placement node, as inbuild_gltf. - content-hash dedup is kept (the hash is computed batch-locally on pass 1).
- the model is meshed twice (the price of bounded memory).
- the #3666 reconstruction check does not run here. The in-memory
assembler reconstructs each exact-tier occurrence from its template and
relative transform and compares it against that occurrence’s own baked
vertices, so a
rep_identityCOLLISION between unrelated geometry falls back to flat. This path holds a plan, not geometry, so it has no occurrence vertices to compare; its guard remains vertex/index counts, which a same-shaped colliding pair passes. The returnedGltfStats::unverified_instance_groupscounts the groups shipped on that weaker guard (always 0 from the in-memory path).
Supports both the f32 and the KHR_mesh_quantization layouts; the quantized
accessor min/max come from the local bbox in closed form (the quantize map is
monotone per axis). Caveat: a NaN vertex coordinate quantizes to 0 in the
byte stream on both paths, but only the in-memory fold lets that 0 into the
accessor min/max hint; clean meshes are byte-identical.