simvx.core.clustered_lighting¶
Forward+ clustered lighting — CPU-side data model and light-to-cluster assignment.
Divides the camera view frustum into a 3D grid of clusters (tiles_x * tiles_y * depth_slices). Each cluster stores the indices of lights that overlap it. The graphics backend dispatches compute shaders using the output buffers; this module provides the data model and assignment logic.
Depth slices use exponential distribution (log-space) matching the non-linear depth buffer, giving more resolution near the camera where it matters most.
Module Contents¶
Classes¶
Configuration for the cluster grid dimensions. |
|
A single cluster cell in the 3D grid. Holds indices of overlapping lights. |
|
3D grid of clusters dividing the view frustum. |
Functions¶
Assign lights to clusters based on camera view and projection. |
Data¶
API¶
- simvx.core.clustered_lighting.__all__¶
[‘ClusterGrid’, ‘LightCluster’, ‘assign_lights’, ‘ClusterConfig’]
- class simvx.core.clustered_lighting.ClusterConfig[source]¶
Configuration for the cluster grid dimensions.
- tiles_x: int¶
16
- tiles_y: int¶
9
- depth_slices: int¶
24
- max_lights_per_cluster: int¶
256
- class simvx.core.clustered_lighting.LightCluster[source]¶
A single cluster cell in the 3D grid. Holds indices of overlapping lights.
- light_indices: list[int]¶
‘field(…)’
- property light_count: int¶
- class simvx.core.clustered_lighting.ClusterGrid(config: simvx.core.clustered_lighting.ClusterConfig | None = None)[source]¶
3D grid of clusters dividing the view frustum.
The grid is addressed as
(tile_x, tile_y, slice_z)where:tile_x/tile_ysubdivide the screen in pixel-spaceslice_zsubdivides the depth range in log-space
Attributes: config: Grid dimensions and limits. clusters: Flat array of
LightClusterobjects (x-major order). slice_boundaries: Precomputed view-space Z boundaries per depth slice.Initialization
- __slots__¶
(‘config’, ‘clusters’, ‘slice_boundaries’, ‘_total’)
- index(tx: int, ty: int, sz: int) int[source]¶
Flat index from 3D grid coordinates (x-major: x + y * tiles_x + z * tiles_x * tiles_y).
- cluster_at(tx: int, ty: int, sz: int) simvx.core.clustered_lighting.LightCluster[source]¶
Return the cluster at grid coordinates.
- rebuild(near: float, far: float) None[source]¶
Recompute depth slice boundaries for the given clip planes.
Uses exponential (log-space) distribution::
depth[i] = near * (far / near) ** (i / num_slices)
This concentrates slices near the camera, matching perspective depth precision.
- depth_slice(view_z: float) int[source]¶
Return the depth slice index for a view-space Z value (positive = in front of camera).
Returns -1 if outside the frustum range.
- to_light_index_buffer() numpy.ndarray[source]¶
Pack all cluster light indices into a flat uint32 array for GPU upload.
Returns concatenated light index lists for all clusters.
- to_tile_buffer() numpy.ndarray[source]¶
Pack cluster metadata into an (N, 2) uint32 array:
(offset, count)per cluster.
- property total_clusters: int¶
- simvx.core.clustered_lighting.assign_lights(lights: list, view_matrix: numpy.ndarray, projection_matrix: numpy.ndarray, viewport_size: tuple[int, int], grid: simvx.core.clustered_lighting.ClusterGrid) simvx.core.clustered_lighting.ClusterGrid[source]¶
Assign lights to clusters based on camera view and projection.
This is the CPU-side culling pass. For each light, it determines which clusters the light’s bounding volume overlaps and records the light index in those clusters.
Args: lights: List of
Light3Dnodes (PointLight3D, SpotLight3D, DirectionalLight3D). view_matrix: 4x4 camera view matrix (row-major numpy array). projection_matrix: 4x4 camera projection matrix (row-major numpy array). viewport_size:(width, height)in pixels. grid:ClusterGridto populate (will be cleared first).Returns: The same
gridinstance, populated with light assignments.