Scene Channels
Scene channels are a generic bitmask used to describe how runtime entities participate in scene-level behavior. They avoid hardcoding engine features around app-specific object names while still supporting exporter conventions such as the NM_ prefix.
Data Model
SceneChannel is an OptionSet backed by UInt64. Each entity can have an EntitySceneChannelsComponent containing one or more channels.
Current built-in channels:
| Channel | Meaning |
|---|---|
.contextGeometry |
Background scene geometry that can be hidden as a group |
.selectableGeometry |
Runtime entities intended for picking/interaction |
.preserveIdentity |
Entities that should remain separate and should not be static-batched |
.ghostGeometry |
Specific walls/structures selected for passthrough ghost rendering |
The bitmask design allows future channels to be added without changing the storage model.
Default Assignment
Runtime and streamed entities receive EntitySceneChannelsComponent during registration. The default mapping is:
| Source | Channels |
|---|---|
entity name starts with NM_ |
.selectableGeometry, .preserveIdentity |
renderable/streamed entity without NM_ |
.contextGeometry |
Explicit calls to setEntitySceneChannels(entityId:channels:) override the default mapping. The component tracks whether its value came from engine defaults so later name updates can refresh default channels without overwriting app-defined channels.
fallbackSceneChannels exists only as a temporary compatibility path for entities created outside the normal registration flow. It should be removed once all entity creation paths assign scene channels explicitly.
Rendering
Channel rendering is controlled globally. The compatibility visibility API maps to render modes:
setSceneChannelVisible(.contextGeometry, false) // .hidden
setSceneChannelVisible(.contextGeometry, true) // .normal
New code can set the render mode directly:
setSceneChannelRenderMode(.contextGeometry, .normal)
setSceneChannelRenderMode(.contextGeometry, .hidden)
setSceneChannelRenderMode(.contextGeometry, .wireframe)
setSceneChannel(.ghostGeometry, .renderMode(.passthroughGhost(opacity: 0.35)))
The render passes call shouldHideSceneEntity(entityId:) for individual entities. Hidden entities are skipped before draw encoding. This is different from opacity: no transparent draw is submitted, so the feature avoids transparency sorting issues.
Batched rendering filters BatchGroups through channel render-mode helpers. Hidden groups are skipped. Wireframe groups are skipped from solid opaque and shadow passes, then redrawn in the wireframe pass after transparency and before spatial debug overlays.
Passthrough ghost groups remain in the solid opaque path and continue to write depth. In mixed passthrough mode, the renderer lowers only the final scene-color alpha for those channels, allowing the real-world camera feed to show through while virtual geometry behind the ghosted surface remains occluded. Outside mixed passthrough mode, ghost channels render as normal opaque geometry.
Use .ghostGeometry for specific walls/structures that should ghost independently from the rest of .contextGeometry. Assigning .ghostGeometry to an entity updates static batching state so selected geometry can split into its own batch group.
For .untold assets, the exporter writes optional architectural edge index buffers for boundary and hard-angle edges. The runtime loader stores these on RuntimeMeshPrimitive, Mesh, and BatchGroup, and the wireframe pass draws them as line primitives when available. Meshes without edge buffers fall back to existing mesh and batch index buffers with Metal triangle line fill mode, which can display dense internal triangulation.
WireframeRenderParams controls visual density. distanceFadeEnabled, fadeStartDistance, fadeEndDistance, and minimumAlpha reduce line opacity for distant geometry without changing the scene-channel API. The fragment shader uses color.a as the near opacity and fades to color.a * minimumAlpha between fadeStartDistance and fadeEndDistance.
Batching
Scene channels affect batching in two ways:
- Entities with
.preserveIdentityare excluded as batch candidates. BatchBuildKeyincludes the channel mask, so entities in different channels do not merge into the same batch group.
This lets the renderer hide or wireframe-render .contextGeometry batches without rebuilding batch artifacts and without affecting .selectableGeometry entities.
Exporter Compatibility
The engine does not require object names to implement channels. However, the current Blender/exporter workflow uses NM_ as a compatibility convention:
NM_*objects are exported individually.- Their names survive into the
.untoldfile. - At runtime they default to
.selectableGeometryand.preserveIdentity. - Regular merged geometry defaults to
.contextGeometry.
This keeps the existing selectable-object workflow intact while moving the engine feature itself toward generic channels.