1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116
//! Modifiers to manipulate a particle's attributes.
//!
//! Attribute modifiers initialize or update during simulation the attributes of
//! all particles of an effect. The provide the core functionality for
//! per-particle diversity / randomness, as attributes are the only quantities
//! stored per particle.
use bevy::prelude::*;
use serde::{Deserialize, Serialize};
use crate::{
graph::{EvalContext, ExprError},
Attribute, BoxedModifier, ExprHandle, Modifier, ModifierContext, Module, ShaderWriter,
};
/// A modifier to assign a value to a particle attribute.
///
/// This modifier sets the value of an [`Attribute`] of the particle of a system
/// to a given graph expression, either when the particle spawns (if used as an
/// init modifier) or each frame when the particle is simulated (if used as an
/// update modifier).
///
/// This is a basic building block to create any complex effect. Most other init
/// modifiers are convenience helpers to achieve a behavior which can otherwise
/// be produced, more verbosely, by setting the individual attributes of a
/// particle with instances of this modifier.
///
/// # Example
///
/// ```
/// # use bevy::math::Vec3;
/// # use bevy_hanabi::*;
/// let mut module = Module::default();
///
/// // Set the position of the particle to (0,0,0) on spawn.
/// let pos = module.lit(Vec3::ZERO);
/// let init_pos = SetAttributeModifier::new(Attribute::POSITION, pos);
///
/// // Each frame, assign the value of the "my_velocity" property to the velocity
/// // of the particle. The property is assigned from CPU, and uploaded to GPU
/// // automatically when its value changed.
/// let my_velocity = module.add_property("my_velocity", Vec3::ZERO.into());
/// let vel = module.prop(my_velocity);
/// let update_vel = SetAttributeModifier::new(Attribute::VELOCITY, vel);
/// ```
///
/// # Warning
///
/// At the minute there is no validation that the type of the value is the same
/// as the type of the attribute. Users are advised to be careful, until more
/// safeguards are added.
///
/// # Attributes
///
/// This modifier requires the attribute specified in the `attribute` field.
#[derive(Debug, Clone, Copy, Reflect, Serialize, Deserialize)]
pub struct SetAttributeModifier {
/// The attribute to initialize.
///
/// See [`Attribute`] for the list of available attributes.
pub attribute: Attribute,
/// The initial value of the attribute.
///
/// Expression type: same as the attribute.
pub value: ExprHandle,
}
impl SetAttributeModifier {
/// Create a new instance of a [`SetAttributeModifier`].
///
/// # Example
///
/// ```
/// # use bevy::math::Vec3;
/// # use bevy_hanabi::*;
/// let mut module = Module::default();
/// let pos = module.lit(Vec3::ZERO);
/// let init_pos = SetAttributeModifier::new(Attribute::POSITION, pos);
/// ```
pub fn new(attribute: Attribute, value: ExprHandle) -> Self {
Self { attribute, value }
}
fn eval(
&self,
module: &mut Module,
context: &mut dyn EvalContext,
) -> Result<String, ExprError> {
assert!(module.get(self.value).is_some());
let attr = module.attr(self.attribute);
let attr = context.eval(module, attr)?;
let expr = context.eval(module, self.value)?;
Ok(format!("{} = {};\n", attr, expr))
}
}
#[typetag::serde]
impl Modifier for SetAttributeModifier {
fn context(&self) -> ModifierContext {
ModifierContext::Init | ModifierContext::Update
}
fn attributes(&self) -> &[Attribute] {
std::slice::from_ref(&self.attribute)
}
fn boxed_clone(&self) -> BoxedModifier {
Box::new(*self)
}
fn apply(&self, module: &mut Module, context: &mut ShaderWriter) -> Result<(), ExprError> {
let code = self.eval(module, context)?;
context.main_code += &code;
Ok(())
}
}