UntoldEngine still uses an out-of-core (OOC) geometry path, but it is now part of the tile streaming architecture, not a general public workflow for arbitrary standalone entities.
The public entry point for streamed geometry is:
setEntityStreamScene(entityId: sceneRoot, manifest: "city", withExtension: "json") { _ in }Inside that pipeline, large tiles may be classified as OCC/OOC during the internal setEntityMeshAsync(streamingPolicy: .auto) tile parse.
| System | Responsibility |
|---|---|
RegistrationSystem |
Parses the .untold tile payload and chooses immediate vs OCC registration |
ProgressiveAssetLoader |
Stores CPU-resident CPURuntimeEntry records keyed by OCC stub entity |
GeometryStreamingSystem |
Uploads and evicts tile-owned OCC stubs by distance and budget |
MeshResourceManager serves cache-backed .untold loads for non-OCC paths. OCC residency is driven by ProgressiveAssetLoader.
When a large tile is routed to the OOC path:
- The tile payload is parsed on the CPU.
- Child stub entities are created with
StreamingComponent(state: .unloaded). - Their
RuntimeAssetNodeCPU data is stored inProgressiveAssetLoader. GeometryStreamingSystemuploads those stubs incrementally as the camera approaches.- Evicted stubs can re-upload from the warm CPU registry without reparsing the file.
Those StreamingComponent stubs are valid only when they are descendants of a TileComponent entity. GeometryStreamingSystem.loadMesh(...) enforces that ownership rule.
The runtime still exposes MeshStreamingPolicy, but the architecture has moved:
setEntityMesh(...)is synchronous and always immediatesetEntityMeshAsync(...)defaults to.immediateand is for always-resident assetssetEntityMeshAsync(..., streamingPolicy: .immediate)forces full uploadsetEntityMeshAsync(..., streamingPolicy: .auto)is used by tile loading so the runtime can choose immediate vs OCCsetEntityStreamScene(...)is the supported public streaming pathStreamingComponentandenableStreaming(...)are internal tile/OOC mechanisms
That means the old pattern:
setEntityMeshAsync(..., streamingPolicy: .outOfCore)
enableStreaming(...)is no longer the recommended app-level workflow. The engine now expects streamed geometry to come from a tiled scene manifest.
loadTile(entityId:) resolves the tile URL, then calls:
setEntityMeshAsync(
entityId: meshEntityId,
filename: ...,
withExtension: ...,
streamingPolicy: .auto,
blockRenderLoop: false
)The asset admission/classification stage decides whether this tile becomes:
- a full-load tile: geometry is uploaded immediately
- an OOC tile: child stubs are registered and uploaded later
For an OOC tile, registerUntoldProgressiveStubEntity(...) creates one ECS stub per renderable RuntimeAssetNode:
- transform and bounds are registered immediately
StreamingComponentstarts as.unloaded- the stub is inserted into the octree
- no GPU buffers are created yet
- renderable nodes are always child entities, including single-node assets, so descendant tracking is consistent
Each stub stores a CPURuntimeEntry in ProgressiveAssetLoader, including:
- source
RuntimeAssetNode - source
.untoldURL - unique mesh name
- estimated GPU bytes
- original loading policy
This is the warm CPU copy used for re-upload.
On streaming ticks, GeometryStreamingSystem evaluates tile-owned OCC stubs:
- near-band stubs are serialized with
nearBandMaxConcurrentLoads - total mesh uploads are capped by
maxConcurrentLoads - geometry budget checks can trigger texture shedding and eviction before new uploads
Successful upload transitions the stub from .loading to .loaded, increments the parent tile's OCC-ready counters, and emits normal residency events for batching.
When the camera moves away or geometry pressure rises:
unloadMesh(entityId:)clearsRenderComponent.meshMemoryBudgetManagerunregisters the GPU allocation- the CPU entry remains warm unless the root asset is explicitly cooled
This is why a normal OOC re-approach can re-upload without a disk read.
OOC is just one representation inside the broader tile system:
- full tile for near field
- per-tile LOD for mid range
- HLOD for far range
- OOC child stubs for large tiles whose full geometry should not upload all at once
That is why the runtime documentation should describe OOC as an implementation detail of tile streaming rather than a separate public scene-loading mode.
- OOC still exists, but it is now subordinate to tile ownership.
ProgressiveAssetLoaderis the.untoldCPU runtime-node residency layer.GeometryStreamingSystemis the GPU residency scheduler.setEntityStreamScene(...)is the supported public streaming API surface.