pub struct FieldConfig {
pub resolution: u32,
pub world_extent: f32,
pub decay: f32,
pub blur: f32,
pub blur_iterations: u32,
pub field_type: FieldType,
pub custom_update: Option<String>,
}Expand description
Configuration for a 3D spatial field.
Fields are 3D grids that particles can read from and write to. Each frame, the field is processed: blur (diffusion), then decay. Optionally, custom WGSL code can replace the default blur/decay behavior.
Fields§
§resolution: u32Grid resolution per axis (total cells = resolution³). Higher = more detail but more memory. Typical: 32, 64, 128.
world_extent: f32World-space extent of the field (cube from -extent to +extent). Should match or exceed your simulation bounds.
decay: f32Per-frame decay multiplier (0.0-1.0). 0.98 = slow decay, 0.5 = fast decay, 1.0 = no decay.
blur: f32Blur strength per frame (0.0-1.0). Controls diffusion rate. 0.0 = no blur, 1.0 = max blur.
blur_iterations: u32Number of blur iterations per frame. More iterations = smoother but more expensive.
field_type: FieldTypeType of field (Scalar or Vector).
custom_update: Option<String>Custom WGSL code for field updates (replaces blur/decay if set).
Available variables:
cell_idx: u32- Linear index of current cellpos: vec3<u32>- Grid position (x, y, z)world_pos: vec3<f32>- World-space positionvalue: f32(scalar) orvalue: vec3<f32>(vector) - Current cell valueparams.resolution,params.extent,params.decay,params.bluruniforms.time,uniforms.delta_time
Helper functions:
read_neighbor(dx: i32, dy: i32, dz: i32) -> f32/vec3<f32>- Read neighbor cellidx_3d(x, y, z) -> u32- Convert 3D coords to linear index
Output: Write to new_value (same type as value)
Example (reaction-diffusion):
let lap = read_neighbor(-1,0,0) + read_neighbor(1,0,0)
+ read_neighbor(0,-1,0) + read_neighbor(0,1,0)
+ read_neighbor(0,0,-1) + read_neighbor(0,0,1) - 6.0 * value;
new_value = value + lap * 0.1 * uniforms.delta_time;Implementations§
Source§impl FieldConfig
impl FieldConfig
Sourcepub fn new_vector(resolution: u32) -> Self
pub fn new_vector(resolution: u32) -> Self
Create a vector field configuration.
Vector fields store a vec3<f32> per cell instead of a scalar.
Use for velocity fields, force fields, or flow visualization.
§Memory Usage (3x scalar fields)
- 32³ = 384KB
- 64³ = 3MB
- 128³ = 24MB
Sourcepub fn vector(self) -> Self
pub fn vector(self) -> Self
Convert this field to a vector field.
Vector fields store vec3<f32> per cell for velocity/force data.
Sourcepub fn with_extent(self, extent: f32) -> Self
pub fn with_extent(self, extent: f32) -> Self
Set the world-space extent of the field.
The field covers a cube from -extent to +extent on all axes.
Should match or exceed your simulation bounds.
Sourcepub fn with_decay(self, decay: f32) -> Self
pub fn with_decay(self, decay: f32) -> Self
Set the decay rate (0.0-1.0).
Applied each frame: field *= decay
- 1.0 = no decay (field persists forever)
- 0.99 = slow decay
- 0.9 = fast decay
- 0.0 = instant decay (field clears each frame)
Sourcepub fn with_blur(self, blur: f32) -> Self
pub fn with_blur(self, blur: f32) -> Self
Set the blur/diffusion strength (0.0-1.0).
Controls how much values spread to neighboring cells each frame.
- 0.0 = no diffusion
- 0.1 = light spread
- 0.5 = heavy spread
- 1.0 = maximum diffusion
Sourcepub fn with_blur_iterations(self, iterations: u32) -> Self
pub fn with_blur_iterations(self, iterations: u32) -> Self
Set the number of blur iterations per frame.
More iterations = smoother diffusion but more expensive. Usually 1-3 is sufficient.
Sourcepub fn with_custom_update(self, code: impl Into<String>) -> Self
pub fn with_custom_update(self, code: impl Into<String>) -> Self
Set custom WGSL code for field updates.
When set, replaces the default blur/decay behavior with custom logic.
See FieldConfig::custom_update for available variables and helpers.
§Example
FieldConfig::new(64)
.with_custom_update(r#"
// Simple diffusion with custom decay
let lap = read_neighbor(-1,0,0) + read_neighbor(1,0,0)
+ read_neighbor(0,-1,0) + read_neighbor(0,1,0)
+ read_neighbor(0,0,-1) + read_neighbor(0,0,1) - 6.0 * value;
new_value = (value + lap * 0.2) * 0.99;
"#)Sourcepub fn has_custom_update(&self) -> bool
pub fn has_custom_update(&self) -> bool
Check if this field has custom update logic.
Sourcepub fn total_cells(&self) -> u32
pub fn total_cells(&self) -> u32
Total number of cells in the field.
Sourcepub fn memory_size(&self) -> usize
pub fn memory_size(&self) -> usize
Memory size in bytes (for the main field buffer).
Trait Implementations§
Source§impl Clone for FieldConfig
impl Clone for FieldConfig
Source§fn clone(&self) -> FieldConfig
fn clone(&self) -> FieldConfig
1.0.0 · Source§fn clone_from(&mut self, source: &Self)
fn clone_from(&mut self, source: &Self)
source. Read moreSource§impl Debug for FieldConfig
impl Debug for FieldConfig
Auto Trait Implementations§
impl Freeze for FieldConfig
impl RefUnwindSafe for FieldConfig
impl Send for FieldConfig
impl Sync for FieldConfig
impl Unpin for FieldConfig
impl UnwindSafe for FieldConfig
Blanket Implementations§
Source§impl<T> BorrowMut<T> for Twhere
T: ?Sized,
impl<T> BorrowMut<T> for Twhere
T: ?Sized,
Source§fn borrow_mut(&mut self) -> &mut T
fn borrow_mut(&mut self) -> &mut T
Source§impl<T> CloneToUninit for Twhere
T: Clone,
impl<T> CloneToUninit for Twhere
T: Clone,
Source§impl<T> Downcast for Twhere
T: Any,
impl<T> Downcast for Twhere
T: Any,
Source§fn into_any(self: Box<T>) -> Box<dyn Any>
fn into_any(self: Box<T>) -> Box<dyn Any>
Box<dyn Trait> (where Trait: Downcast) to Box<dyn Any>. Box<dyn Any> can
then be further downcast into Box<ConcreteType> where ConcreteType implements Trait.Source§fn into_any_rc(self: Rc<T>) -> Rc<dyn Any>
fn into_any_rc(self: Rc<T>) -> Rc<dyn Any>
Rc<Trait> (where Trait: Downcast) to Rc<Any>. Rc<Any> can then be
further downcast into Rc<ConcreteType> where ConcreteType implements Trait.Source§fn as_any(&self) -> &(dyn Any + 'static)
fn as_any(&self) -> &(dyn Any + 'static)
&Trait (where Trait: Downcast) to &Any. This is needed since Rust cannot
generate &Any’s vtable from &Trait’s.Source§fn as_any_mut(&mut self) -> &mut (dyn Any + 'static)
fn as_any_mut(&mut self) -> &mut (dyn Any + 'static)
&mut Trait (where Trait: Downcast) to &Any. This is needed since Rust cannot
generate &mut Any’s vtable from &mut Trait’s.