Skip to content

Commit e24d32b

Browse files
authored
Add missing clamp and vec3 expressions (#504)
- Add missing `clamp(x, lo, hi)` expression. - Expose `vec3(x, y, z)` to `Module`; it was only available in `WriterExpr` by mistake. - Same for `vec4_xyz_w(xyz, w)`. - Add tests for those.
1 parent c237dae commit e24d32b

File tree

2 files changed

+107
-31
lines changed

2 files changed

+107
-31
lines changed

src/graph/expr.rs

Lines changed: 105 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -545,6 +545,7 @@ impl Module {
545545
impl_module_binary!(uniform, UniformRand);
546546
impl_module_binary!(normal, NormalRand);
547547
impl_module_binary!(vec2, Vec2);
548+
impl_module_binary!(vec4_xyz_w, Vec4XyzW);
548549

549550
/// Build a ternary expression and append it to the module.
550551
///
@@ -581,7 +582,9 @@ impl Module {
581582
}
582583

583584
impl_module_ternary!(mix, Mix);
585+
impl_module_ternary!(clamp, Clamp);
584586
impl_module_ternary!(smoothstep, SmoothStep);
587+
impl_module_ternary!(vec3, Vec3);
585588

586589
/// Build a cast expression and append it to the module.
587590
///
@@ -2187,6 +2190,17 @@ pub enum TernaryOperator {
21872190
/// (1 - t) + y * t`.
21882191
Mix,
21892192

2193+
/// Clamp operator.
2194+
///
2195+
/// Returns the first argument clamped to the range defined by the second
2196+
/// and third arguments. If the operands are vectors, they must be of
2197+
/// the same rank, and the result is a vector of that rank
2198+
/// and same element scalar type.
2199+
///
2200+
/// The expression `clamp(x, low, high)` is equivalent to `min(max(x, low),
2201+
/// high)`.
2202+
Clamp,
2203+
21902204
/// Smooth stepping operator.
21912205
///
21922206
/// Returns the smooth Hermitian interpolation between the first and second
@@ -2212,6 +2226,7 @@ impl ToWgslString for TernaryOperator {
22122226
fn to_wgsl_string(&self) -> String {
22132227
match *self {
22142228
TernaryOperator::Mix => "mix".to_string(),
2229+
TernaryOperator::Clamp => "clamp".to_string(),
22152230
TernaryOperator::SmoothStep => "smoothstep".to_string(),
22162231
TernaryOperator::Vec3 => "vec3".to_string(),
22172232
}
@@ -3600,6 +3615,35 @@ impl WriterExpr {
36003615
self.binary_op(other, BinaryOperator::Mul)
36013616
}
36023617

3618+
/// Apply the logical operator "normal" to this expression and another
3619+
/// expression.
3620+
///
3621+
/// This is a binary operator, which applies component-wise to vector
3622+
/// operand expressions. That is, for vectors, this produces a vector of
3623+
/// random values where each component is normally distributed with a mean
3624+
/// of the corresponding component of the first operand and a standard
3625+
/// deviation of the corresponding component of the second operand.
3626+
///
3627+
/// # Example
3628+
///
3629+
/// ```
3630+
/// # use bevy_hanabi::*;
3631+
/// # use bevy::math::Vec3;
3632+
/// # let mut w = ExprWriter::new();
3633+
/// // A literal expression `x = vec3<f32>(3., -2., 7.);`.
3634+
/// let x = w.lit(Vec3::new(3., -2., 7.));
3635+
///
3636+
/// // Another literal expression `y = vec3<f32>(1., 5., 7.);`.
3637+
/// let y = w.lit(Vec3::new(1., 5., 7.));
3638+
///
3639+
/// // A random variable normally distributed in [1:3]x[-2:5]x[7:7].
3640+
/// let z = x.normal(y);
3641+
/// ```
3642+
#[inline]
3643+
pub fn normal(self, other: Self) -> Self {
3644+
self.binary_op(other, BinaryOperator::NormalRand)
3645+
}
3646+
36033647
/// Calculate the remainder of the division of the current expression by
36043648
/// another expression.
36053649
///
@@ -3712,35 +3756,6 @@ impl WriterExpr {
37123756
self.binary_op(other, BinaryOperator::UniformRand)
37133757
}
37143758

3715-
/// Apply the logical operator "normal" to this expression and another
3716-
/// expression.
3717-
///
3718-
/// This is a binary operator, which applies component-wise to vector
3719-
/// operand expressions. That is, for vectors, this produces a vector of
3720-
/// random values where each component is normally distributed with a mean
3721-
/// of the corresponding component of the first operand and a standard
3722-
/// deviation of the corresponding component of the second operand.
3723-
///
3724-
/// # Example
3725-
///
3726-
/// ```
3727-
/// # use bevy_hanabi::*;
3728-
/// # use bevy::math::Vec3;
3729-
/// # let mut w = ExprWriter::new();
3730-
/// // A literal expression `x = vec3<f32>(3., -2., 7.);`.
3731-
/// let x = w.lit(Vec3::new(3., -2., 7.));
3732-
///
3733-
/// // Another literal expression `y = vec3<f32>(1., 5., 7.);`.
3734-
/// let y = w.lit(Vec3::new(1., 5., 7.));
3735-
///
3736-
/// // A random variable normally distributed in [1:3]x[-2:5]x[7:7].
3737-
/// let z = x.normal(y);
3738-
/// ```
3739-
#[inline]
3740-
pub fn normal(self, other: Self) -> Self {
3741-
self.binary_op(other, BinaryOperator::NormalRand)
3742-
}
3743-
37443759
fn ternary_op(self, second: Self, third: Self, op: TernaryOperator) -> Self {
37453760
assert_eq!(self.module, second.module);
37463761
assert_eq!(self.module, third.module);
@@ -3788,6 +3803,34 @@ impl WriterExpr {
37883803
self.ternary_op(other, fraction, TernaryOperator::Mix)
37893804
}
37903805

3806+
/// Clamp an expression between the bounds defined by two other expressions.
3807+
///
3808+
/// This is a ternary operator, which applies component-wise to vector
3809+
/// operand expressions.
3810+
///
3811+
/// # Example
3812+
///
3813+
/// ```
3814+
/// # use bevy_hanabi::*;
3815+
/// # use bevy::math::Vec2;
3816+
/// # let mut w = ExprWriter::new();
3817+
/// // A literal expression `x = vec2<f32>(1., -2.);`.
3818+
/// let x = w.lit(Vec2::new(1., -2.));
3819+
///
3820+
/// // A literal expression `lo = vec2<f32>(3., -3.);`.
3821+
/// let lo = w.lit(Vec2::new(3., -3.));
3822+
///
3823+
/// // A literal expression `hi = vec2<f32>(5., 1.);`.
3824+
/// let hi = w.lit(Vec2::new(5., 1.));
3825+
///
3826+
/// // Clamp x in [lo:hi]
3827+
/// let z = x.clamp(lo, hi); // == vec2<f32>(3., -2.)
3828+
/// ```
3829+
#[inline]
3830+
pub fn clamp(self, lo: Self, hi: Self) -> Self {
3831+
self.ternary_op(lo, hi, TernaryOperator::Clamp)
3832+
}
3833+
37913834
/// Calculate the smooth Hermite interpolation in \[0:1\] of the current
37923835
/// value taken between the given bounds.
37933836
///
@@ -4326,6 +4369,7 @@ mod tests {
43264369

43274370
let x = m.attr(Attribute::POSITION);
43284371
let y = m.lit(Vec3::ONE);
4372+
let z = m.lit(1.45);
43294373

43304374
let atan2 = m.atan2(x, y);
43314375
let cross = m.cross(x, y);
@@ -4334,6 +4378,7 @@ mod tests {
43344378
let min = m.min(x, y);
43354379
let max = m.max(x, y);
43364380
let step = m.step(x, y);
4381+
let vec4_xyz_w = m.vec4_xyz_w(x, z);
43374382

43384383
let property_layout = PropertyLayout::default();
43394384
let particle_layout = ParticleLayout::default();
@@ -4361,6 +4406,17 @@ mod tests {
43614406
)
43624407
);
43634408
}
4409+
4410+
{
4411+
let expr = ctx.eval(&m, vec4_xyz_w);
4412+
assert!(expr.is_ok());
4413+
let expr = expr.unwrap();
4414+
let z = ctx.eval(&m, z).unwrap();
4415+
assert_eq!(
4416+
expr,
4417+
format!("vec4(particle.{}, {})", Attribute::POSITION.name(), z)
4418+
);
4419+
}
43644420
}
43654421

43664422
#[test]
@@ -4369,17 +4425,26 @@ mod tests {
43694425

43704426
let x = m.attr(Attribute::POSITION);
43714427
let y = m.lit(Vec3::ONE);
4428+
let z = m.lit(Vec3::splat(2.));
43724429
let t = m.lit(0.3);
4430+
let a = m.lit(-4.2);
4431+
let b = m.lit(53.09);
43734432

43744433
let mix = m.mix(x, y, t);
4434+
let clamp = m.clamp(x, y, z);
43754435
let smoothstep = m.smoothstep(x, y, x);
4436+
let vecthree = m.vec3(a, b, t);
43764437

43774438
let property_layout = PropertyLayout::default();
43784439
let particle_layout = ParticleLayout::default();
43794440
let mut ctx =
43804441
ShaderWriter::new(ModifierContext::Update, &property_layout, &particle_layout);
43814442

4382-
for (expr, op, third) in [(mix, "mix", t), (smoothstep, "smoothstep", x)] {
4443+
for (expr, op, third) in [
4444+
(mix, "mix", t),
4445+
(clamp, "clamp", z),
4446+
(smoothstep, "smoothstep", x),
4447+
] {
43834448
let expr = ctx.eval(&m, expr);
43844449
assert!(expr.is_ok());
43854450
let expr = expr.unwrap();
@@ -4394,6 +4459,16 @@ mod tests {
43944459
)
43954460
);
43964461
}
4462+
4463+
{
4464+
let expr = ctx.eval(&m, vecthree);
4465+
assert!(expr.is_ok());
4466+
let expr = expr.unwrap();
4467+
let a = ctx.eval(&m, a).unwrap();
4468+
let b = ctx.eval(&m, b).unwrap();
4469+
let t = ctx.eval(&m, t).unwrap();
4470+
assert_eq!(expr, format!("vec3({}, {}, {})", a, b, t));
4471+
}
43974472
}
43984473

43994474
#[test]

src/render/mod.rs

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4951,7 +4951,8 @@ impl EffectBindGroups {
49514951
let make_entry = || {
49524952
let mut entries = Vec::with_capacity(3);
49534953
entries.push(
4954-
// @group(3) @binding(0) var<storage, read_write> effect_metadatas : array<EffectMetadata>;
4954+
// @group(3) @binding(0) var<storage, read_write> effect_metadatas :
4955+
// array<EffectMetadata>;
49554956
BindGroupEntry {
49564957
binding: 0,
49574958
resource: BindingResource::Buffer(BufferBinding {

0 commit comments

Comments
 (0)