simvx.graphics.renderer.particle_compute¶
GPU compute shader particle simulation.
Dispatches a compute shader to update particle positions, velocities, lifetimes, and visual properties entirely on the GPU: avoiding per-frame CPU-to-GPU uploads for particle data.
Mirrors the web backend’s GPUParticlePass (gpu_particle_pass.js): each
GPUParticles3D / GPUParticles2D emitter owns a persistent SSBO keyed by
a stable emitter_id (the truncated id(node) minted in
scene_adapter.py). Multiple emitters in the same scene render
independently; an emitter that leaves the tree has its SSBO and descriptor
pool released via :meth:prune_inactive.
Module Contents¶
Classes¶
GPU-based particle simulation via Vulkan compute shader. |
Data¶
API¶
- simvx.graphics.renderer.particle_compute.__all__¶
[‘ParticleCompute’]
- simvx.graphics.renderer.particle_compute.log¶
‘getLogger(…)’
- class simvx.graphics.renderer.particle_compute.ParticleCompute(engine: Any)¶
GPU-based particle simulation via Vulkan compute shader.
Owns one compute pipeline (shared across emitters) and N per-emitter SSBOs. Mirrors the web
GPUParticlePasslifecycle:dispatch()lazy-creates a slot for an unseenemitter_id;prune_inactive()releases slots whose ids are no longer in the scene tree.Initialization
- setup() None¶
Create the shared compute pipeline.
Per-emitter SSBOs are allocated lazily on first
dispatch()for each uniqueemitter_id.
- begin_frame() None¶
Bump the per-frame stamp used to decide which emitters render.
- prune_inactive(active_ids: set[int]) None¶
Release GPU resources for emitters not in
active_ids.Called once per frame after every emitter has been submitted, so slots whose
GPUParticles*node has left the tree get cleaned up. Mirrors :func:GPUParticlePass.pruneInactiveon the web side. The slot’s buffer and descriptor pools are retired, not freed on the spot: the frames still in flight may reference them.
- dispatch(cmd: Any, dt: float, emitter_id: int, emitter_config: dict) None¶
Dispatch the compute shader for one emitter.
Args: cmd: Active command buffer (must be outside a render pass). dt: Delta time in seconds. emitter_id: Stable per-node identifier (
id(node) & 0xFFFFFFFF). emitter_config: See :meth:GPUParticles3D.emitter_config.
- render(cmd: Any, particle_pass: Any, view_proj: numpy.ndarray, camera_right: numpy.ndarray, camera_up: numpy.ndarray, extent: tuple[int, int]) None¶
Draw every active emitter’s particles using the shared billboard pipeline.
Iterates the slots whose
last_active_framematches the current frame counter (i.e. were dispatched this frame). The compute-owned SSBO is bound through a per-slot descriptor set built againstParticlePass._ssbo_layout: no per-frame upload.
- get_particle_ssbo(emitter_id: int) Any¶
Return the SSBO for
emitter_id(orNoneif no slot exists).
- upload_initial_particles(emitter_id: int, particles: numpy.ndarray) None¶
Seed a specific emitter’s GPU buffer with CPU-generated particle data.
Used by tests and tools that want a deterministic starting state.
len(particles)must not exceed the slot’smax_particles.
- emitter_count() int¶
Number of active per-emitter slots (for tests / debugging).
- has_emitter(emitter_id: int) bool¶
True if the given emitter has an allocated slot.
- property ready: bool¶
- cleanup() None¶
Destroy every per-emitter slot and the shared compute pipeline.