Salva Fluid Simulation Engine

repository·master·Indexed 20 days ago

https://github.com/dimforge/salva

A 2D and 3D particle-based fluid simulation engine for games and animations. Salva features advanced pressure resolution (DFSPH, IISPH), viscosity models, surface tension, and elasticity. It uses nalgebra for mathematics, supports WASM for web deployment, and provides optional two-way coupling with the Rapier physics engine via the FluidsPipeline to enable interactions between fluids and rigid, multibody, or deformable bodies.

Tokens
13.3K
Snippets
42
Records
50
Agent score
71%

What's inside Salva

  1. Overview of Salva fluid simulation engine

    master

    Salva is a 2D and 3D particle-based fluid simulation engine designed for games and animations. It provides high-fidelity fluid dynamics through various pressure resolution and viscosity models.

    Key technical details:

    • Math Library: Uses nalgebra for vector and matrix mathematics.
    • Physics Coupling: Can optionally interface with rapier to enable two-way coupling between fluids and rigid bodies, multibodies, or deformable bodies.
    • Dimensionality: Supports both 2D and 3D simulations using a largely shared codebase.
    • Platform Support: Includes WASM support, making it suitable for web-based applications.
  2. Salva simulation features

    master

    Salva implements several advanced fluid simulation techniques:

    • Pressure Resolution: Supports DFSPH and IISPH.
    • Viscosity Models: Includes DFSPH viscosity, Artificial viscosity, and XSPH viscosity.
    • Surface Tension: Implements WCSPH surface tension, as well as methods from He et al. 2014 and Akinci et al. 2013.
    • Elasticity: Implements the method from Becker et al. 2009.
    • Multiphase Fluids: Allows mixing multiple fluids with different characteristics (e.g., varying densities and viscosities).
    • Two-way Coupling: Optional integration with rapier for interaction with physics bodies.
    • WASM Support: Optimized for web deployment.
  3. Run Salva 2D and 3D examples

    master

    You can run the provided examples for both 2D and 3D simulations using cargo. The examples are located in the examples2d and examples3d directories and are designed to work with WASM and WebGL 1.0.

    cargo run --release -p examples2d --bin all_examples2
    cargo run --release -p examples3d --bin all_examples3
  4. What is Salva?

    master
    Salva is a 2D and 3D particle-based fluid simulation engine designed for games and animations. It supports various pressure resolution methods (DFSPH, IISPH), viscosity models (DFSPH, Artificial, XSPH), surface tension, elasticity, and multiphase fluids. It can optionally interface with the Rapier physics engine for two-way coupling between fluids and rigid/deformable bodies. The engine is built on nalgebra and supports WASM for web-based execution.
  5. Configure `FluidsRenderingMode`

    master

    The FluidsRenderingMode enum determines how fluid particles are visually represented in the testbed. You can set this using FluidsTestbedPlugin::set_fluid_rendering_mode.

    Available modes:

    • StaticColor: Renders particles using a plain color (either the assigned fluid color or the default).
    • VelocityColor { min, max }: Renders particles with a red tint based on their velocity. Particles with velocity $\le$ min have no red tint; particles with velocity $\ge$ max are completely red.
    • VelocityArrows { min, max }: Renders particles as arrows indicating the direction and magnitude of velocity, with the same red tinting logic as VelocityColor.
    // Example: Velocity-based coloring
    plugin.set_fluid_rendering_mode(FluidsRenderingMode::VelocityColor {
        min: 0.0,
        max: 50.0,
    });
  6. How interaction groups work in Salva

    master

    Salva uses InteractionGroups to perform pairwise filtering between elements (like particles). This allows you to specify which elements should interact and which should ignore each other using bitmasks.

    An interaction between two objects a and b is permitted if:

    1. The memberships of a share at least one bit with the filter of b.
    2. OR the memberships of b share at least one bit with the filter of a.

    This logic is implemented via the test method. If neither condition is met, the objects will ignore each other.

    // Example logic for interaction:
    // (a.memberships & b.filter) != 0 || (b.memberships & a.filter) != 0
  7. Configure ColliderSampling methods

    master

    When registering a coupling, you must specify a ColliderSampling method to determine how the fluid perceives the collider's shape:

    • StaticSampling(Vec<math::Vector<math::Real>>): Approximates the collider using a fixed set of sample points in local space. It is recommended that these points are separated by a distance $\le$ twice the particle radius.
    • DynamicContactSampling: Approximates the shape using a dynamic set of points automatically computed based on actual contacts with fluid particles. This is more computationally efficient for complex shapes as it only samples where interaction occurs.
    // Example: Static sampling with specific points
    let points = vec![math::Vector::new(0.0, 1.0, 0.0), math::Vector::new(0.0, -1.0, 0.0)];
    let sampling = ColliderSampling::StaticSampling(points);
    
    // Example: Dynamic sampling
    let sampling = ColliderSampling::DynamicContactSampling;
  8. Manage multiple boundaries with BoundarySet

    master

    A BoundarySet is a collection of Boundary objects managed via a ContiguousArena. It uses BoundaryHandle as the key to access specific boundaries.

    // BoundarySet is a type alias for ContiguousArena<BoundaryHandle, Boundary>
    // Use it to store and retrieve Boundary objects using their handles.
  9. Use FluidsPipeline to couple Salva with Rapier

    master

    The FluidsPipeline is the primary entry point for integrating particle-based fluid simulations with the Rapier physics engine. It manages both the LiquidWorld (the fluid simulation) and a ColliderCouplingSet (the interaction between fluids and Rapier rigid bodies).

    To use it, you initialize the pipeline with particle properties and then call step during your physics loop. Note that step applies forces to rigid bodies but does not integrate them; you must use Rapier's own physics pipeline to integrate those forces into motion.

    // Example initialization and stepping
    let mut pipeline = FluidsPipeline::new(particle_radius, smoothing_factor);
    
    // In your simulation loop:
    pipeline.step(&gravity, dt, &colliders, &mut bodies);
  10. Use Salva's math module for dimension-agnostic types

    master

    Salva provides a math module that exposes type aliases for common mathematical structures (vectors, matrices, rotations, isometries) based on the enabled compilation features (dim2 or dim3 and f32 or f64). This allows you to write code that adapts to the simulation's dimensionality and precision.

    Key concepts in the math module:

    • Real: The scalar type (either f32 or f64).
    • Vector<Real>: The standard spatial vector type.
    • Isometry<Real>: The transformation type (combining rotation and translation).
    • SpatialVector<Real>: A vector representing both rotation and translation (dimension is SPATIAL_DIM).
    • gcross_matrix(v): Returns the cross-product matrix for a given vector, specialized for 2D or 3D.
    use salva::math::{Vector, Real, gcross_matrix};
    
    let v: Vector<Real> = Vector::new(1.0, 0.0, 0.0);
    let m = gcross_matrix(&v);
  11. Use `ContiguousArena` for efficient object management

    master

    A ContiguousArena<Idx, T> is a collection that stores elements contiguously in a Vec while providing unique, generational identifiers (Idx) for each element. This structure is ideal when you need the cache locality and performance of a contiguous array but require stable handles that remain valid even as elements are removed and the underlying array is reordered (via swap-remove).

    Key characteristics:

    • Contiguous Storage: Elements are stored in a Vec<T>, allowing for efficient slice access and iteration.
    • Generational Handles: Uses Idx (which must implement From<ContiguousArenaIndex> and Into<ContiguousArenaIndex>) to provide safe, unique access to elements.
    • Efficient Removal: Uses swap_remove to maintain contiguity, which is an $O(1)$ operation but changes the index of the last element in the array.
    use generational_arena::Index;
    // Assuming ContiguousArena is imported
    let mut arena: ContiguousArena<Index, i32> = ContiguousArena::new();
    let handle = arena.insert(123);
    let value = arena.get(handle);
  12. Manage Fluid objects with FluidSet and FluidHandle

    master

    When managing multiple fluid objects, Salva uses a FluidSet (which is a ContiguousArena) and FluidHandles to provide efficient access and identification.

    • FluidHandle: A unique identifier for a fluid object. It can be converted to and from a ContiguousArenaIndex.
    • FluidSet: A collection of all fluid objects in the simulation.
    // FluidHandle is a wrapper around ContiguousArenaIndex
    // FluidSet is a type alias for ContiguousArena<FluidHandle, Fluid>