Go to file
2024-01-27 22:29:18 +01:00
src init: specs 2024-01-27 21:21:10 +01:00
.gitignore init: specs 2024-01-27 21:21:10 +01:00
Cargo.toml init: specs 2024-01-27 21:21:10 +01:00
README.md fix: edit the specs 2024-01-27 22:29:18 +01:00

A particles generator in rust for laser shows

Philosophy

This library should allow users to define their own particle behaviours

  • how many particles at start? min/max at any time? how many to add at any time?
  • how do particles behave? Are there different types? Different shapes?
  • how do particles react with real world? To audio? To a controller?

Constraints

  • Render as lists of points in the form [x,y,color] with color encoded as 12 bits (r,g,b)
    • i.e. it doesn't speak to the laser directly, we use a middleware for that part (see. xxx)
    • it can output to STDOUT or send to redis
  • Obviously be as fast as possible
  • Use a physics engine as a tool for collision detection, velocity and more
  • Be easy to use: good defaults for everything
  • Handle bounding and drawing boxes
  • Handle user custom particle properties (ex: decay, frequency, personality, etc.)
  • Handle additional drawings for the current frame due to custom events (ex: random edge between two particles)

Questions

Working with the Physics engine

- Q: how do we enable custom behaviours (ex: reacting to audio)
- Q: how do we map physics engine object (ex: ball, square) for users as concept
- Q: how do we convert the physics engine objets to 2D points
- Q: how do we handle 3D? On by default? 

How to use in a project

  1. Clone lj_rust_template and edit draw.rs
  2. add lj_particle library crate
  3. edit the draw function
  4. compile

Fundamental Features

  • Use a 3D physics engine
  • Provide hooks to create and update the simulation (onInit, onTick, onCollide, etc.)
  • Render using box clipping for out of bound particles points
  • Use an out-of-simulation list of additional points
  • Render to STDOUT or Redis

Future Features

  • Use a 2D physics engine
  • Use attractors/repulsors objects
  • Use OSC to update configuration

Library struct/objects

Particle
- PhysicsBody
- Shape : Square, Triangle, Circle, 3DSphere 
- UserData // custom ex: life decay, seed, created_at, frequency
- Group 

PhysicsEngine
PhysicsEngineConfig

RenderEngine
RenderEngineConfig


Config
- ParticlesGroups: vec<<Particle>
- RedisConfig
- PhysicsEngineConfig
- RenderEngineConfig

// future feature
OSCConfig
- OSCCache
- OSCServer <IP,Port>

API example


/***
  An idea of the crate API
***/

use LJParticleSystem as ParticleSystem;
use LJRedilysis as Redilysis;
use Rapier as PhysicsEngine;

// Configure 
let boundingbox  = BoundingBox();
let clipping_box = ClippingBox();

let particle_system = ParticleSystem( ParticleSystemConfig, PhysicsEngine, ClippingBox, BoundingBox );
let redilysis  = Redilysis ( RedilysisConfig( file_path ) );


// by default, equiprobability to generate a particle from any group
particle_system.new_particle( lambda() => { ... }) 

// some way to init the particles 
world.init();

particle_system.tick = lambda(){

    // Configuration update if read via OSC 
    current_config = self->getConfig();

    // Retrieve bandwidth/bpm/rms info (with caching)
    analysis = redilysis.update();

    // Manage 
    self.boundingBox();

    self.physicsEngine();

    for( particle in self.getParticles() ) {

         


    }


    n_particles = current_config.particles_amount;

    return self.clippingBox();


}

pub fn draw() -> Result<Vec<Point>, Box<dyn std::error::Error>> {
    let mut v: Vec<Point> = vec![];
    v.push( particle_system.tick() );
    Ok(v)
}

OSC CONFIG

S Server = (LJ) OSC Server and client eventual config channel 1 : IP channel X : IP

R Rust = (LJ Particle) OSC Server and Client

U User Interface = (Tablet) HTML Interface

c Program Channel = configurable, uint ex: 1 n Programe name = configurable, string ex: particle_foo_square

Sequence Diagram

# Prerequisite : S is running and available and U is connected to S
# R starts
# R: Do you have my config already ?
R -> S "/program/$c/$n/configure" 

# C needs to stock which program is currently used for $n channel and its parameters

# If no, C manifests the need to init the configuration
C -> R "/program/$c/$n/no-config"

# If no-config, R sends its default config for C to store
R -> C "/program/$c/$n/var1 default_value1" # etc.

# In any case, C sends to R the current config
C -> R "/program/$c/$n/var1 value1" # etc.

# C creates an event for the User to change  
C -> U "/program/$c/$n" 

# U can change the program configuration 
U -> C "/program/$c/$n"