simvx.core.gpu_particles

GPU-accelerated particle emitter nodes (2D and 3D).

Scene-node wrappers for GPU compute-shader particle simulation. Particle state lives entirely on the GPU – positions, velocities, colours, and lifetimes are updated each frame by a compute dispatch, avoiding per-frame CPU-to-GPU uploads.

Both GPUParticles2D and GPUParticles3D expose Property descriptors so the editor inspector can tweak parameters at design time. At runtime the graphics backend reads emitter_config each frame and feeds it into the compute shader push constants.

Module Contents

Classes

GPUParticles2D

GPU-accelerated 2D particle emitter.

GPUParticles3D

GPU-accelerated 3D particle emitter.

Data

API

simvx.core.gpu_particles.log

‘getLogger(…)’

simvx.core.gpu_particles.__all__

[‘GPUParticles2D’, ‘GPUParticles3D’]

class simvx.core.gpu_particles.GPUParticles2D(**kwargs)[source]

Bases: simvx.core.gpu_particles._GPUParticlesBase, simvx.core.nodes_2d.node2d.Node2D

GPU-accelerated 2D particle emitter.

Particle simulation runs entirely on the GPU via a compute shader. The node exposes editor-visible Property descriptors for all emitter parameters (amount, lifetime, speed, colours, etc.).

The graphics backend collects GPUParticles2D nodes during scene traversal, reads emitter_config, and dispatches the compute shader each frame.

Example::

particles = GPUParticles2D(
    amount=2048,
    lifetime=1.5,
    speed=8.0,
    start_colour=(1.0, 0.8, 0.2, 1.0),
    end_colour=(1.0, 0.0, 0.0, 0.0),
)
scene.add_child(particles)

Initialization

property emitter_config: dict[source]

The shared config, carried through the node’s transform.

direction, the emission radius and the particle size are given in the emitter’s own space, so the launch velocity turns with its world rotation and the radius and size grow with its world scale (to the larger axis: grains are round).

property world_position[source]

Return 3D position for the compute shader (z=0 for 2D).

on_update(dt: float)[source]
amount

‘Property(…)’

lifetime

‘Property(…)’

emitting

‘Property(…)’

one_shot

‘Property(…)’

speed

‘Property(…)’

speed_variance

‘Property(…)’

direction

‘Property(…)’

spread

‘Property(…)’

spread_pattern

‘Property(…)’

spread_points

‘Property(…)’

gravity

‘Property(…)’

damping

‘Property(…)’

emission_shape

‘Property(…)’

emission_radius

‘Property(…)’

emission_box

‘Property(…)’

start_colour

‘Colour(…)’

end_colour

‘Colour(…)’

start_scale

‘Property(…)’

end_scale

‘Property(…)’

streak

‘Property(…)’

near_fade

‘Property(…)’

explosiveness

‘Property(…)’

randomness

‘Property(…)’

fixed_fps

‘Property(…)’

preprocess

‘Property(…)’

local_coords

‘Property(…)’

finished

‘Signal(…)’

restart()
position

‘_SpatialVecProperty(…)’

rotation

‘Property(…)’

scale

‘_SpatialVecProperty(…)’

top_level

‘Property(…)’

z_index

‘Property(…)’

z_as_relative

‘Property(…)’

render_layer

‘Property(…)’

set_render_layer(index: int, enabled: bool = True) → None
is_on_render_layer(index: int) → bool
property absolute_z_index: int
property rotation_degrees: float
property world_rotation: float
property world_scale: simvx.core.math.types.Vec2
property world_transform: tuple[simvx.core.math.types.Vec2, simvx.core.math.types.Vec2, float]
property forward: simvx.core.math.types.Vec2
property right: simvx.core.math.types.Vec2
translate(offset: tuple[float, float] | numpy.ndarray)
rotate(radians: float)
rotate_deg(degrees: float)
look_at(target: tuple[float, float] | numpy.ndarray)
to_global(point) → simvx.core.math.types.Vec2
to_local(point) → simvx.core.math.types.Vec2
transform_points(points: list[simvx.core.math.types.Vec2]) → list[simvx.core.math.types.Vec2]
wrap_screen(margin: float = 20)
post_processed

‘Property(…)’

property transform_render_dirty: bool
strict_errors: ClassVar[bool]

True

dev_checks: ClassVar[bool]

None

dev_warnings: ClassVar[bool]

None

freeze_check_interval: ClassVar[float]

1.0

dynamic: bool

False

visible

‘Property(…)’

update_mode

‘Property(…)’

focus_mode

‘Property(…)’

drag_threshold

‘Property(…)’

focus_entered

‘Signal(…)’

focus_exited

‘Signal(…)’

__properties__: ClassVar[dict[str, simvx.core.descriptors.Property]]

None

classmethod __init_subclass__(**kwargs)
property name: str
property visible_in_tree: bool
property input_player: simvx.core.input.players.InputPlayer
property input_context: simvx.core.input.contexts.InputContext | None
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_fixed_update(dt: float) → None
on_draw(canvas) → None
on_draw_3d(gizmos) → None
on_picked(event: simvx.core.input.events.PickEvent) → bool | None
on_gui_input(event: simvx.core.input.events.GuiInputEvent) → bool | None
start_coroutine(gen: simvx.core.descriptors.Coroutine) → simvx.core.descriptors.CoroutineHandle
stop_coroutine(gen_or_handle)
property focused: bool
property focus_rect: tuple[float, float, float, float] | None
drag_threshold_for(pointer_type: simvx.core.input.enums.PointerType | str) → float
grab_focus() → None
release_focus() → None
capture_pointer(pointer_id: int | None = None) → None
release_pointer(pointer_id: int | None = None) → None
queue_redraw() → None
property render_dirty: bool
clear_children()
destroy()
property destroying: bool
property destroyed: bool
call_deferred(method: collections.abc.Callable[..., Any], *args: Any) → None
property app
property tree: simvx.core.scene_tree.SceneTree
property viewport_size: simvx.core.math.types.Vec2
property viewport_insets: tuple[float, float, float, float]
property physics
property physics_2d
__getitem__(key: str)
classmethod get_properties() → dict[str, simvx.core.descriptors.Property]
__repr__()
class simvx.core.gpu_particles.GPUParticles3D(**kwargs)[source]

Bases: simvx.core.gpu_particles._GPUParticlesBase, simvx.core.nodes_3d.node3d.Node3D

GPU-accelerated 3D particle emitter.

Particle simulation runs entirely on the GPU via a compute shader. The node exposes editor-visible Property descriptors for all emitter parameters (amount, lifetime, speed, colours, etc.).

The graphics backend collects GPUParticles3D nodes during scene traversal, reads emitter_config, and dispatches the compute shader each frame.

Example::

particles = GPUParticles3D(
    amount=4096,
    lifetime=2.0,
    speed=10.0,
    gravity=(0.0, -9.8, 0.0),
    start_colour=(0.2, 0.6, 1.0, 1.0),
    end_colour=(0.0, 0.2, 0.8, 0.0),
)
scene.add_child(particles)

Initialization

on_update(dt: float)[source]
amount

‘Property(…)’

lifetime

‘Property(…)’

emitting

‘Property(…)’

one_shot

‘Property(…)’

speed

‘Property(…)’

speed_variance

‘Property(…)’

direction

‘Property(…)’

spread

‘Property(…)’

spread_pattern

‘Property(…)’

spread_points

‘Property(…)’

gravity

‘Property(…)’

damping

‘Property(…)’

emission_shape

‘Property(…)’

emission_radius

‘Property(…)’

emission_box

‘Property(…)’

start_colour

‘Colour(…)’

end_colour

‘Colour(…)’

start_scale

‘Property(…)’

end_scale

‘Property(…)’

streak

‘Property(…)’

near_fade

‘Property(…)’

explosiveness

‘Property(…)’

randomness

‘Property(…)’

fixed_fps

‘Property(…)’

preprocess

‘Property(…)’

local_coords

‘Property(…)’

finished

‘Signal(…)’

property emitter_config: dict
restart()
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

dev_warnings: ClassVar[bool]

None

freeze_check_interval: ClassVar[float]

1.0

dynamic: bool

False

visible

‘Property(…)’

update_mode

‘Property(…)’

focus_mode

‘Property(…)’

drag_threshold

‘Property(…)’

focus_entered

‘Signal(…)’

focus_exited

‘Signal(…)’

__properties__: ClassVar[dict[str, simvx.core.descriptors.Property]]

None

classmethod __init_subclass__(**kwargs)
property name: str
property visible_in_tree: bool
property input_player: simvx.core.input.players.InputPlayer
property input_context: simvx.core.input.contexts.InputContext | None
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_fixed_update(dt: float) → None
on_draw(canvas) → None
on_draw_3d(gizmos) → None
on_picked(event: simvx.core.input.events.PickEvent) → bool | None
on_gui_input(event: simvx.core.input.events.GuiInputEvent) → bool | None
start_coroutine(gen: simvx.core.descriptors.Coroutine) → simvx.core.descriptors.CoroutineHandle
stop_coroutine(gen_or_handle)
property focused: bool
property focus_rect: tuple[float, float, float, float] | None
drag_threshold_for(pointer_type: simvx.core.input.enums.PointerType | str) → float
grab_focus() → None
release_focus() → None
capture_pointer(pointer_id: int | None = None) → None
release_pointer(pointer_id: int | None = None) → None
queue_redraw() → None
property render_dirty: bool
clear_children()
destroy()
property destroying: bool
property destroyed: bool
call_deferred(method: collections.abc.Callable[..., Any], *args: Any) → None
property app
property tree: simvx.core.scene_tree.SceneTree
property viewport_size: simvx.core.math.types.Vec2
property viewport_insets: tuple[float, float, float, float]
property physics
property physics_2d
__getitem__(key: str)
classmethod get_properties() → dict[str, simvx.core.descriptors.Property]
__repr__()