simvx.core.irradiance_volume¶
IrradianceVolume3D: baked diffuse global-illumination probe grid.
A box-shaped grid of irradiance probes. Each probe stores the low-frequency diffuse lighting reaching its position as spherical-harmonic L1 coefficients (12 floats). At shade time a fragment inside the volume trilinearly blends the eight surrounding probes and evaluates their SH for the surface normal, so a dynamic object moving through the volume picks up soft, direction-dependent indirect light baked from the surrounding (e.g. coloured) walls.
The volume is axis-aligned and centred on the node’s world_position; the
node’s rotation is intentionally ignored for the grid (standard for irradiance
volumes: the probes sample the world, not the node’s local frame).
Example::
vol = IrradianceVolume3D(extents=(6, 4, 6), spacing=2.0)
room.add_child(vol)
Capture reuses the reflection-probe cubemap machinery (a small radiance cube per
probe) reduced to SH by a compute pass; update_budget probes are baked per
frame so a large grid amortises over several frames. bake_mode “once”
bakes the grid a single time (the common case for static level lighting);
“always” re-bakes round-robin for dynamic scenes; “disabled” leaves the volume
inert (feature-off, byte-identical to a scene with no volume).
Module Contents¶
Classes¶
A box of baked irradiance probes that gives dynamic objects indirect light. |
Data¶
API¶
- simvx.core.irradiance_volume.log¶
‘getLogger(…)’
- simvx.core.irradiance_volume.MAX_PROBES¶
256
- simvx.core.irradiance_volume.__all__¶
[‘IrradianceVolume3D’, ‘MAX_PROBES’]
- class simvx.core.irradiance_volume.IrradianceVolume3D(extents=None, spacing=None, **kwargs)[source]¶
Bases:
simvx.core.nodes_3d.node3d.Node3DA box of baked irradiance probes that gives dynamic objects indirect light.
Each probe stores the low-frequency diffuse lighting reaching its position as spherical-harmonic L1 coefficients (12 floats). At shade time a fragment inside the volume trilinearly blends the eight surrounding probes and evaluates their SH for its surface normal, so a character walking through a red-walled room picks up a soft red bounce that flat or sky ambient cannot produce. Outside the box, shading falls back to the ambient the
WorldEnvironmentwould give it, and the transition cross-fades.The box is axis-aligned and centred on the node’s
world_position. The node’s rotation is deliberately ignored for the grid: probes sample the world, not the node’s local frame.extentsare half-extents, so a volume covering a 12 x 8 x 12 room isextents=(6, 4, 6).Probe count per axis is
floor(2 * half / spacing) + 1, capped in total atMAX_PROBES: a grid that would exceed the cap is coarsened (the effective spacing is raised) so the volume still spans its full extents rather than being clipped. Halvingspacingcosts roughly eight times the probes, so tune it against :meth:probe_count.Baking is amortised at
update_budgetprobes per frame.bake_mode"once"(default) bakes the grid a single time, which is what static level lighting wants;"always"re-bakes round-robin for scenes whose lighting changes;"disabled"leaves the volume inert. Call- Meth:
request_updateafter moving the volume or changing the lighting to force a fresh bake.
Example::
vol = IrradianceVolume3D(extents=(6, 4, 6), spacing=2.0) room.add_child(vol)
Initialization
- extents¶
‘Property(…)’
- spacing¶
‘Property(…)’
- intensity¶
‘Property(…)’
- bake_mode¶
‘Property(…)’
- update_budget¶
‘Property(…)’
- grid_dims() tuple[int, int, int][source]¶
Probe counts per axis, coarsened so the total stays within MAX_PROBES.
Each axis gets
floor(2*half / spacing) + 1probes (>= 1). If the product exceeds MAX_PROBES the spacing is effectively raised (counts scaled down) so the volume keeps spanning its full extents.
- bounds_world() tuple[simvx.core.math.types.Vec3, simvx.core.math.types.Vec3][source]¶
World AABB of the probe centres (probe (0,0,0) .. probe (nx-1,ny-1,nz-1)).
- probe_positions() numpy.ndarray[source]¶
World positions of every probe, shape (N, 3), index = x + nx*(y + ny*z).
- get_gizmo_lines() list[tuple[simvx.core.math.types.Vec3, simvx.core.math.types.Vec3]][source]¶
Wireframe box for the volume extents (12 edges).
- position¶
‘_SpatialVecProperty(…)’
- rotation¶
‘Property(…)’
- scale¶
‘_SpatialVecProperty(…)’
- render_layer¶
‘Property(…)’
- property rotation_degrees: simvx.core.math.types.Vec3¶
- property world_position: simvx.core.math.types.Vec3¶
- property world_rotation: simvx.core.math.types.Quat¶
- property world_scale: simvx.core.math.types.Vec3¶
- property forward: simvx.core.math.types.Vec3¶
- property right: simvx.core.math.types.Vec3¶
- property up: simvx.core.math.types.Vec3¶
- translate(offset: tuple[float, float, float] | numpy.ndarray)¶
- translate_global(offset: tuple[float, float, float] | numpy.ndarray)¶
- rotate(axis: tuple[float, float, float] | numpy.ndarray, angle: float)¶
- rotate_x(angle: float)¶
- rotate_y(angle: float)¶
- rotate_z(angle: float)¶
- look_at(target: tuple[float, float, float] | numpy.ndarray, up=None)¶
- face_along(forward: tuple[float, float, float] | numpy.ndarray, up: tuple[float, float, float] | numpy.ndarray | None = None) None¶
- set_render_layer(index: int, enabled: bool = True) None¶
- is_on_render_layer(index: int) bool¶
- wrap_bounds(bounds: tuple[float, float, float] | numpy.ndarray, margin: float = 1.0)¶
- strict_errors: ClassVar[bool]¶
True
- dev_checks: ClassVar[bool]¶
None
- script_error_raised¶
‘Signal(…)’
- dynamic: bool¶
False
- visible¶
‘Property(…)’
- update_mode¶
‘Property(…)’
- __properties__: ClassVar[dict[str, simvx.core.descriptors.Property]]¶
None
- classmethod __init_subclass__(**kwargs)¶
- property name: str¶
- property visible_in_tree: bool¶
- reset_error() None¶
- add_child(node: simvx.core.node.T) simvx.core.node.T¶
- remove_child(node: simvx.core.node.Node) None¶
- reparent(new_parent: simvx.core.node.Node)¶
- node_at(path, default=_NO_DEFAULT)¶
- find(target, *, direct: bool = False)¶
- find_all(target, *, direct: bool = False)¶
- expect(target, *, direct: bool = False)¶
- ancestor(target)¶
- walk(*, include_self: bool = True) collections.abc.Iterator[simvx.core.node.Node]¶
- property path: str¶
- property is_scene_root: bool¶
- add_to_group(group: str)¶
- remove_from_group(group: str)¶
- is_in_group(group: str) bool¶
- on_ready() None¶
- on_enter_tree() None¶
- on_exit_tree() None¶
- on_update(dt: float) None¶
- on_fixed_update(dt: float) None¶
- on_draw(renderer) None¶
- on_picked(event: simvx.core.events.InputEvent) None¶
- on_unhandled_input(event: simvx.core.events.TreeInputEvent) None¶
- start_coroutine(gen: simvx.core.descriptors.Coroutine) simvx.core.descriptors.CoroutineHandle¶
- stop_coroutine(gen_or_handle)¶
- queue_redraw() None¶
- property render_dirty: bool¶
- clear_children()¶
- destroy()¶
- property destroying: bool¶
- call_deferred(method: collections.abc.Callable[..., Any], *args: Any) None¶
- property app¶
- property tree: simvx.core.scene_tree.SceneTree¶
- property physics¶
- property physics_2d¶
- __getitem__(key: str)¶
- classmethod get_properties() dict[str, simvx.core.descriptors.Property]¶
- __repr__()¶