Render¶
The rendering backend turns scenes and visuals into pixels, coordinating slicing requests and per-canvas state.
Managers¶
cellier.render.RenderManager ¶
Single top-level render-layer object.
Owns the scene registry, canvas registry, shared async slicer, and slice coordinator. Exposes three reslicing entry points that cover the common triggers: all scenes, one scene, or one visual.
Construction is parameter-free; scenes, canvases, and visuals are
registered via the add_* methods.
config
property
¶
config: RenderManagerConfig
Current rendering performance configuration.
Reflects live state: mutations via temporal_alpha and
temporal_enabled setters are visible here immediately.
temporal_alpha
property
writable
¶
temporal_alpha: float
EMA floor weight for temporal accumulation.
temporal_enabled
property
writable
¶
temporal_enabled: bool
Whether the temporal accumulation pass is active.
connect_event_bus ¶
Subscribe internal components to event_bus.
Must be called before the caller registers its own DimsChangedEvent handler so the SliceCoordinator invalidates stale 2D caches first.
add_scene ¶
add_scene(scene_id: UUID, lighting: str = 'none') -> SceneManager
Create and register a new scene.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
scene_id
|
UUID
|
Unique identifier for the scene. |
required |
lighting
|
str
|
|
'none'
|
Returns:
| Type | Description |
|---|---|
SceneManager
|
The newly created scene manager. |
scene_has_lighting ¶
Return True if scene_id was created with lighting enabled.
add_canvas ¶
add_canvas(canvas_id: UUID, scene_id: UUID, parent: QWidget | None = None, **canvas_view_kwargs) -> CanvasView
Create a CanvasView, register it, and return it.
The caller embeds canvas_view.widget in their Qt layout.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
canvas_id
|
UUID
|
Unique identifier for this canvas. |
required |
scene_id
|
UUID
|
ID of the scene this canvas should render. |
required |
parent
|
QWidget or None
|
Parent widget for the underlying |
None
|
**canvas_view_kwargs
|
Additional keyword arguments forwarded to |
{}
|
Returns:
| Type | Description |
|---|---|
CanvasView
|
The newly created canvas view. |
add_visual ¶
add_visual(scene_id: UUID, visual: _GFXVisual, data_store: BaseDataStore, displayed_axes: tuple[int, ...]) -> None
Register a visual with a scene and its associated data store.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
scene_id
|
UUID
|
ID of the scene to add the visual to. |
required |
visual
|
_GFXVisual
|
The render-layer visual object. |
required |
data_store
|
BaseDataStore
|
The data store that will serve chunk data for this visual. |
required |
displayed_axes
|
tuple[int, ...]
|
Current displayed axes from the scene's dims selection. Passed to
|
required |
add_canvas_overlay ¶
add_canvas_overlay(canvas_id: UUID, gfx_overlay: GFXCanvasOverlay) -> None
Attach a pre-built GFX overlay to canvas_id.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
canvas_id
|
UUID
|
ID of the canvas that should receive the overlay. |
required |
gfx_overlay
|
GFXCanvasOverlay
|
The fully-constructed render-layer overlay. |
required |
Raises:
| Type | Description |
|---|---|
KeyError
|
If canvas_id is not registered. |
set_pick_details_enabled ¶
Enable or disable element-level pick extraction for one canvas.
When disabled (the default), pointer events still carry
hit_visual_id but pick_details is left None so non-picking
consumers do not pay for the per-type dispatch.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
canvas_id
|
UUID
|
The canvas whose extraction state should change. |
required |
enabled
|
bool
|
True to extract typed |
required |
remove_visual ¶
remove_visual(visual_id: UUID) -> None
Remove a visual from its scene and deregister it.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
visual_id
|
UUID
|
ID of the visual to remove. |
required |
remove_scene ¶
remove_scene(scene_id: UUID) -> None
Remove a scene and all its visuals and canvases.
Visuals are released by dropping references (pygfx has no explicit
destroy API), but each canvas is closed explicitly -- see
:meth:CanvasView.close, which GC alone cannot substitute for.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
scene_id
|
UUID
|
ID of the scene to remove. |
required |
close ¶
Close every registered canvas and drop the render references.
Safe to call more than once.
get_scene ¶
get_scene(scene_id: UUID) -> Scene
Return the pygfx Scene for scene_id.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
scene_id
|
UUID
|
ID of the scene to retrieve. |
required |
Returns:
| Type | Description |
|---|---|
Scene
|
|
reslice_scene ¶
reslice_scene(scene_id: UUID, dims_state: DimsState, visual_configs: dict[UUID, VisualRenderConfig] | None = None, target_visual_ids: frozenset[UUID] | None = None) -> None
Reslice all visuals in one scene.
One reslicing request is submitted per registered canvas so that each canvas uses its own camera state for LOD and frustum-culling decisions.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
scene_id
|
UUID
|
ID of the scene to reslice. |
required |
dims_state
|
DimsState
|
Current dimension display state. |
required |
visual_configs
|
dict[UUID, VisualRenderConfig] or None
|
Per-visual render configuration. |
None
|
target_visual_ids
|
frozenset[UUID] or None
|
|
None
|
reslice_visual ¶
reslice_visual(visual_id: UUID, dims_state: DimsState, visual_config: VisualRenderConfig | None = None) -> None
Reslice one visual.
Looks up which scene owns visual_id, then submits one
ReslicingRequest per registered canvas so that each canvas uses
its own camera state.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
visual_id
|
UUID
|
ID of the visual to reslice. |
required |
dims_state
|
DimsState
|
Current dimension display state. |
required |
visual_config
|
VisualRenderConfig or None
|
Render configuration for this visual. |
None
|
look_at_visual ¶
look_at_visual(visual_id: UUID, canvas_id: UUID, view_direction: tuple[float, float, float] = (-1, -1, -1), up: tuple[float, float, float] = (0, 0, 1)) -> None
Fit a canvas camera to a visual's bounding box.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
visual_id
|
UUID
|
ID of the target visual. |
required |
canvas_id
|
UUID
|
ID of the canvas whose camera should be fitted. |
required |
view_direction
|
tuple[float, float, float]
|
Camera look direction vector (need not be normalized). |
(-1, -1, -1)
|
up
|
tuple[float, float, float]
|
Camera up vector. |
(0, 0, 1)
|
set_camera_depth_range ¶
cellier.render.SceneManager ¶
Owns one pygfx gfx.Scene and the registry of visuals attached to it.
Which node (2D or 3D) is active is determined at runtime from the
dims_state carried by each ReslicingRequest, not fixed at
construction time.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
scene_id
|
UUID
|
Unique identifier for this scene. |
required |
add_visual ¶
Register a visual and add its initial node to the scene graph.
Calls visual.get_node_for_dims(displayed_axes) to select the
correct node, then stores it in _active_nodes and adds it to
the pygfx scene.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
visual
|
_GFXVisual
|
The GFX visual to register. |
required |
displayed_axes
|
tuple[int, ...]
|
Current displayed axes from the scene's dims selection. |
required |
Raises:
| Type | Description |
|---|---|
ValueError
|
If |
get_active_node ¶
get_active_node(visual_id: UUID) -> WorldObject | None
Return the node currently active in the scene for visual_id.
Returns None if the visual has not yet been registered or if its
active node is None.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
visual_id
|
UUID
|
ID of the visual to query. |
required |
swap_node ¶
swap_node(visual_id: UUID, new_node: WorldObject | None) -> None
Replace the active scene-graph node for visual_id.
Removes the previously active node and adds new_node. If
old_node is new_node (single-node visuals such as mesh and
lines), the scene graph is not touched — the node stays in the
scene and the subsequent reslice updates its content.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
visual_id
|
UUID
|
ID of the visual whose node is being swapped. |
required |
new_node
|
WorldObject or None
|
The node that should be active after this call. |
required |
remove_visual ¶
remove_visual(visual_id: UUID) -> None
Unregister a visual and remove its node from the scene graph.
Uses _active_nodes to identify which node is currently in the
scene and removes only that one. Dropping the visual from
_visuals releases references to both node_3d and node_2d
so GC can collect both nodes' GPU resources (pygfx has no explicit
destroy API).
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
visual_id
|
UUID
|
ID of the visual to remove. |
required |
get_visual_id_for_node ¶
get_visual_id_for_node(node: WorldObject) -> UUID | None
Return the visual_id whose active scene-graph node is node.
The pick buffer returns leaf nodes (e.g. gfx.Image inside a
gfx.Group), while _active_nodes stores the top-level group.
This method walks up the parent chain of node until it finds a
registered active node, then returns its visual_id. Returns None
if no ancestor belongs to any registered visual.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
node
|
WorldObject
|
The pygfx object returned by the pick buffer. |
required |
build_slice_requests ¶
build_slice_requests(request: ReslicingRequest, visual_configs: dict[UUID, VisualRenderConfig]) -> dict[UUID, list[ChunkRequest]]
Collect ChunkRequests from all (or targeted) registered visuals.
Dispatches to the 2D or 3D planning path based on scene dimensionality.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
request
|
ReslicingRequest
|
The reslicing request. |
required |
visual_configs
|
dict[UUID, VisualRenderConfig]
|
Per-visual render configuration. |
required |
Returns:
| Type | Description |
|---|---|
dict[UUID, list[ChunkRequest]]
|
Mapping of |
cellier.render.SliceCoordinator ¶
Thin orchestrator owned by RenderManager.
Given a ReslicingRequest, it looks up the target SceneManager,
runs the synchronous planning phase, cancels in-flight tasks for the
affected visuals, and submits new async load tasks.
One AsyncSlicer task maps to one (scene_id, canvas_id, visual_id)
triple. A dict keyed by this triple tracks active slice IDs so that
per-visual cancellation can cancel only the affected task while leaving
other visuals — and other canvases — in the same scene running.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
scenes
|
dict[UUID, SceneManager]
|
Shared scene registry from |
required |
slicer
|
AsyncSlicer
|
Shared async slicer instance. |
required |
data_stores
|
dict[UUID, MultiscaleZarrDataStore]
|
Mapping of |
required |
submit ¶
submit(request: ReslicingRequest, visual_configs: dict[UUID, VisualRenderConfig]) -> None
Execute the full reslicing cycle for the scene in request.scene_id.
Cancels in-flight tasks for visuals that will be re-submitted, subject
to each visual's cancellable property. Visuals with
cancellable = False are never cancelled; their tasks run to
completion so every intermediate position reaches the GPU. This is the
case for the static-geometry in-memory visuals (mesh, lines, points).
The image and label visuals -- both in-memory
(GFXImageMemoryVisual, GFXLabelMemoryVisual) and multiscale
(GFXMultiscaleImageVisual, GFXMultiscaleLabelVisual) -- default
to cancellable = True, so a superseding reslice cancels their
in-flight reads. All render-layer visual classes must expose
cancellable as part of their public API; an AttributeError
indicates a missing implementation.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
request
|
ReslicingRequest
|
The reslicing request to process. |
required |
visual_configs
|
dict[UUID, VisualRenderConfig]
|
Per-visual render configuration. |
required |
cancel_scene ¶
cancel_scene(scene_id: UUID) -> None
Cancel all in-flight tasks for a scene.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
scene_id
|
UUID
|
ID of the scene whose tasks should be cancelled. |
required |
cancel_visual ¶
Cancel the in-flight task for one visual on one canvas.
Also calls visual.cancel_pending() or cancel_pending_2d()
to release any GPU slots reserved during the last planning phase
that were never committed.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
scene_id
|
UUID
|
ID of the scene containing the visual. |
required |
canvas_id
|
UUID
|
ID of the canvas whose request should be cancelled. |
required |
visual_id
|
UUID
|
ID of the visual to cancel. |
required |
cellier.render.CanvasView ¶
Owns one rendered canvas: widget, renderer, camera, and controller.
Responsible for rendering one scene from one camera viewpoint.
CanvasView does not hold a direct reference to the scene graph;
instead it receives a get_scene_fn callable that is invoked each
frame so ownership of the scene stays with SceneManager.
Camera change detection is implemented by comparing a cached
CameraState snapshot each frame in _draw_frame. The
_applying_model_state flag suppresses detection during
programmatic camera updates to prevent feedback loops.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
canvas_id
|
UUID
|
Unique identifier for this canvas. |
required |
scene_id
|
UUID
|
ID of the scene this canvas renders. |
required |
get_scene_fn
|
Callable[[UUID], Scene]
|
Called each frame to retrieve the current scene. Provided by
|
required |
dim
|
str
|
Scene dimensionality: |
'3d'
|
parent
|
QWidget or None
|
Parent widget for the underlying |
None
|
fov
|
float
|
Vertical field of view in degrees (3D perspective only). |
70.0
|
depth_range
|
tuple[float, float]
|
Near and far clip distances |
(1.0, 8000.0)
|
widget
property
¶
widget: object
The render canvas element to embed in the application layout.
A QRenderWidget for the Qt backend or an AnywidgetRenderCanvas
for the anywidget backend.
close ¶
Close the canvas, stopping its draw loop and releasing the GPU.
Dropping the last Python reference to a CanvasView is not enough
to reclaim it. The canvas is a parentless (top-level) render widget,
so the backend owns it and keeps it alive; through its draw callback
and event filter it in turn pins this view, the WgpuRenderer, and
the whole object graph they reach. Closing the canvas is what breaks
that chain, after which normal refcounting reclaims everything.
Safe to call more than once, and safe when the GUI backend has already destroyed the canvas itself (e.g. the user closed the window).
capture_reslicing_request ¶
capture_reslicing_request(dims_state: DimsState, target_visual_ids: frozenset[UUID] | None = None) -> ReslicingRequest
Snapshot the current camera state into a ReslicingRequest.
All array fields are copied. Screen size is read from the canvas at call time and baked into the returned request.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
dims_state
|
DimsState
|
Current dimension display state. |
required |
target_visual_ids
|
frozenset[UUID] or None
|
|
None
|
Returns:
| Type | Description |
|---|---|
ReslicingRequest
|
Fully populated snapshot with independent array copies. |
set_depth_range ¶
set_depth_range_for_dim ¶
Set the near/far clip distances on the 2D or 3D camera.
Unlike :meth:set_depth_range, this targets a specific camera
regardless of which is currently active. Both the 2D orthographic
and 3D perspective cameras are created up front (see __init__),
so the reserve camera must have its depth range set independently —
otherwise it keeps the active camera's range, which for a 2D->3D
toggle leaves the perspective camera with an invalid (e.g. negative)
near plane and renders nothing.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
dim
|
str
|
|
required |
depth_range
|
tuple[float, float]
|
|
required |
show_object ¶
Fit the camera to the scene bounding box and mark this dim as fitted.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
scene
|
Scene
|
The scene to fit the camera to. |
required |
add_overlay ¶
Attach a screen-space overlay to this canvas.
The overlay is rendered as an additional post-pass on top of the main scene each frame. Multiple overlays are rendered in insertion order.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
overlay
|
GFXCanvasOverlay
|
The render-layer overlay to attach. |
required |
apply_camera_state ¶
apply_camera_state(request: ReslicingRequest) -> None
Apply a camera snapshot from the model layer (programmatic move).
The _applying_model_state guard prevents the resulting camera
setter calls from firing _on_controller_event, which would
otherwise cause a feedback loop: model change -> apply to pygfx ->
controller event -> model change -> ...
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
request
|
ReslicingRequest
|
Camera snapshot to apply. |
required |
set_controller_enabled ¶
set_controller_enabled(enabled: bool) -> None
Enable or disable the active camera controller for this canvas.
self._controller already points to the currently active
controller (_controller_2d or _controller_3d depending on
the canvas dim), so this correctly targets whichever type is in use.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
enabled
|
bool
|
False disables the controller (paint mode active). True restores normal camera interaction. |
required |
switch_dim ¶
Switch the canvas between "2d" and "3d" rendering modes.
Disables the current controller and enables the one for new_dim.
Camera pose is preserved across toggles.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
new_dim
|
str
|
|
required |
Returns:
| Type | Description |
|---|---|
bool
|
|
capture_camera_state ¶
Snapshot the current pygfx camera into a CameraState NamedTuple.
Config¶
cellier.render.CameraConfig
pydantic-model
¶
Bases: BaseModel
Configuration for camera-driven automatic reslicing.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
reslice_enabled
|
bool
|
When |
required |
settle_threshold_s
|
float
|
Seconds of camera stillness required before a reslice is triggered. Lower values give more responsive LOD updates; higher values reduce redundant I/O during fast panning. |
required |
Fields:
cellier.render.RenderManagerConfig
pydantic-model
¶
Bases: BaseModel
Top-level rendering performance configuration.
Pass an instance to CellierController(render_config=...) at
construction time. The live state is always accessible and
serializable via render_manager.config.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
slicing
|
SlicingConfig
|
Async chunk-slicing pipeline settings. |
required |
temporal
|
TemporalAccumulationConfig
|
Temporal accumulation pass settings. |
required |
camera
|
CameraConfig
|
Camera-driven reslicing settings. |
required |
Examples:
Construct with custom settings and serialize:
>>> config = RenderManagerConfig(
... slicing=SlicingConfig(batch_size=32, render_every=4),
... temporal=TemporalAccumulationConfig(alpha=0.05),
... camera=CameraConfig(settle_threshold_s=0.5),
... )
>>> json_str = config.model_dump_json()
>>> config2 = RenderManagerConfig.model_validate_json(json_str)
Fields:
-
slicing(SlicingConfig) -
temporal(TemporalAccumulationConfig) -
camera(CameraConfig)
cellier.render.SlicingConfig
pydantic-model
¶
Bases: BaseModel
Configuration for the async chunk-slicing pipeline.
These parameters are construction-time only. Changing them after
RenderManager is created has no effect.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
batch_size
|
int
|
Number of chunks fetched concurrently in each async batch. Higher values increase throughput but raise peak memory pressure. |
required |
render_every
|
int
|
Number of completed batches between progressive redraws. 1 = redraw after every batch (lowest latency to first pixels); higher values reduce GPU upload overhead on fast I/O. |
required |
Fields:
cellier.render.TemporalAccumulationConfig
pydantic-model
¶
Bases: BaseModel
Configuration for the temporal accumulation post-processing pass.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
enabled
|
bool
|
When |
required |
alpha
|
float
|
Minimum EMA blend weight for the current frame. During warm-up
the weight is |
required |
Fields:
Requests¶
cellier.render.DimsState ¶
cellier.render.ReslicingRequest ¶
Bases: NamedTuple
Frozen snapshot driving a complete reslicing cycle.
Constructed by CanvasView.capture_reslicing_request() and consumed
by SliceCoordinator. All array fields must be .copy()d by the
caller — the NamedTuple does not enforce this.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
camera_type
|
str
|
|
required |
camera_pos
|
(ndarray, shape(3))
|
World-space camera position, copy. |
required |
frustum_corners
|
(ndarray, shape(2, 4, 3))
|
World-space frustum corners, copy. For orthographic cameras this
is set to |
required |
fov_y_rad
|
float
|
Vertical field of view in radians. |
required |
screen_size_px
|
tuple[float, float]
|
Logical |
required |
world_extent
|
tuple[float, float]
|
Visible |
required |
dims_state
|
DimsState
|
Current dimension display state. |
required |
request_id
|
UUID
|
Unique identifier per trigger; used for cancellation. |
required |
scene_id
|
UUID
|
Which scene this camera belongs to. |
required |
canvas_id
|
UUID
|
Which canvas produced this request. Used by |
required |
target_visual_ids
|
frozenset[UUID] or None
|
|
required |
Scene config¶
cellier.render.VisualRenderConfig
dataclass
¶
Mutable render settings for one visual.
Passed through the call stack at reslice time. When a visual's ID is
absent from the visual_configs dict supplied to
SceneManager.build_slice_requests, a default instance is used.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
lod_bias
|
float
|
Multiplier applied to LOD distance thresholds. Values greater
than 1.0 favour finer (higher-resolution) levels at a given
camera distance; values less than 1.0 favour coarser levels.
Default |
1.0
|
force_level
|
int or None
|
When set, all bricks are assigned this 1-based LOD level,
bypassing distance-based selection entirely. |
None
|
frustum_cull
|
bool
|
When |
True
|
Temporal accumulation¶
cellier.render.TemporalAccumulationPass ¶
Bases: EffectPass
Post-processing pass that accumulates jittered frames over time.
Insert as the first entry in renderer.effect_passes so it
operates on the raw raymarched output before anti-aliasing.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
alpha
|
float
|
Minimum blend weight for the current frame. During warm-up the
weight is |
0.1
|
alpha
property
writable
¶
alpha: float
Minimum blend weight for the current frame (EMA floor).
Lower values give smoother steady-state at the cost of slower convergence after a reset.
reset ¶
Discard accumulated history.
The next frame's blend weight becomes 1.0, so history is immediately overwritten. No GPU memory is freed or cleared.