Skip to content

Commit 04ac0cb

Browse files
authored
Normalize, limit, broadcasting.
1 parent 542aee8 commit 04ac0cb

6 files changed

Lines changed: 55 additions & 13 deletions

File tree

‎crates/processing_core/src/constants.rs‎

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -87,6 +87,8 @@ pub const AFFINE: &str = "affine";
8787
pub const ABS: &str = "abs";
8888
pub const NEGATE: &str = "negate";
8989
pub const FLOOR: &str = "floor";
90+
pub const NORMALIZE: &str = "normalize";
91+
pub const LIMIT: &str = "limit";
9092
pub const SQRT: &str = "sqrt";
9193
pub const GREATER: &str = "greater";
9294
pub const LESS: &str = "less";

‎crates/processing_pyo3/src/constants.rs‎

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -62,7 +62,7 @@ pub fn register(m: &Bound<'_, PyModule>) -> PyResult<()> {
6262
add!(
6363
m, MAP, COMBINE, MIX, LOOKUP, REDUCE, EXTRACT, PACK, GENERATE
6464
);
65-
add!(m, AFFINE, ABS, NEGATE, FLOOR, SQRT);
65+
add!(m, AFFINE, ABS, NEGATE, FLOOR, SQRT, NORMALIZE, LIMIT);
6666
add!(m, GREATER, LESS, GEQ, LEQ, EQ, NEQ);
6767
add!(m, SUB, MUL, DIV, POW);
6868
add!(m, LENGTH, SUM, SUMSQ, MEAN, MIN, MAX);

‎crates/processing_pyo3/src/particles.rs‎

Lines changed: 12 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,7 @@ use processing_render::{
2525
use processing_render::{GEN_GAUSSIAN, GEN_SIGNED, GEN_UNIFORM};
2626
use processing_render::{
2727
MAP_ABS, MAP_AFFINE, MAP_CLAMP, MAP_EQ, MAP_FLOOR, MAP_GEQ, MAP_GREATER, MAP_LEQ, MAP_LESS,
28-
MAP_NEGATE, MAP_NEQ, MAP_SQRT, MAP_SQUARE,
28+
MAP_LIMIT, MAP_NEGATE, MAP_NEQ, MAP_NORMALIZE, MAP_SQRT, MAP_SQUARE,
2929
};
3030
use processing_render::{
3131
REDUCE_LENGTH, REDUCE_MAX, REDUCE_MEAN, REDUCE_MIN, REDUCE_SUM, REDUCE_SUMSQ,
@@ -46,6 +46,8 @@ fn parse_map_op(s: &str) -> PyResult<u32> {
4646
_ if s.eq_ignore_ascii_case(c::LEQ) => Ok(MAP_LEQ),
4747
_ if s.eq_ignore_ascii_case(c::EQ) => Ok(MAP_EQ),
4848
_ if s.eq_ignore_ascii_case(c::NEQ) => Ok(MAP_NEQ),
49+
_ if s.eq_ignore_ascii_case(c::NORMALIZE) => Ok(MAP_NORMALIZE),
50+
_ if s.eq_ignore_ascii_case(c::LIMIT) => Ok(MAP_LIMIT),
4951
_ => Err(PyValueError::new_err(format!("map: unknown op {s:?}"))),
5052
}
5153
}
@@ -239,6 +241,11 @@ fn map_params(kwargs: Option<&Bound<'_, PyDict>>, op: u32) -> PyResult<(f32, f32
239241
kw_f32(kwargs, "offset", 0.0)?,
240242
),
241243
MAP_CLAMP => (kw_f32(kwargs, "lo", 0.0)?, kw_f32(kwargs, "hi", 1.0)?),
244+
MAP_NORMALIZE => (kw_f32(kwargs, "length", 1.0)?, 0.0),
245+
MAP_LIMIT => (
246+
kw_f32(kwargs, "min_length", 0.0)?,
247+
kw_f32(kwargs, "max_length", f32::MAX)?,
248+
),
242249
MAP_GREATER | MAP_LESS | MAP_GEQ | MAP_LEQ | MAP_EQ | MAP_NEQ => (
243250
kw_f32(kwargs, "threshold", 0.0)?,
244251
kw_f32(kwargs, "epsilon", 1.0e-6)?,
@@ -251,6 +258,8 @@ fn map_param_keys(op: u32) -> &'static [&'static str] {
251258
match op {
252259
MAP_AFFINE => &["scale", "offset"],
253260
MAP_CLAMP => &["lo", "hi"],
261+
MAP_NORMALIZE => &["length"],
262+
MAP_LIMIT => &["min_length", "max_length"],
254263
MAP_GREATER | MAP_LESS | MAP_GEQ | MAP_LEQ | MAP_EQ | MAP_NEQ => &["threshold", "epsilon"],
255264
_ => &[],
256265
}
@@ -567,9 +576,9 @@ impl Particles {
567576
reject_unknown_kwargs(kwargs, &["a", "b", "out", "op", "b_scale", "b_offset"])?;
568577
let (a, comp) = self.operand(kwargs, "a")?;
569578
let (b, b_comp) = self.operand(kwargs, "b")?;
570-
if b_comp != comp {
579+
if b_comp != comp && b_comp != 1 {
571580
return Err(PyValueError::new_err(format!(
572-
"apply(combine): `a` has {comp} components but `b` has {b_comp} (must match)"
581+
"apply(combine): the first operand has {comp} components, so the second needs {comp} or 1, not {b_comp}"
573582
)));
574583
}
575584
let out = self.dest(kwargs, a)?;

‎crates/processing_render/src/lib.rs‎

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -23,9 +23,9 @@ pub mod transform;
2323

2424
pub use particles::algebra::{
2525
GEN_GAUSSIAN, GEN_SIGNED, GEN_UNIFORM, MAP_ABS, MAP_AFFINE, MAP_CLAMP, MAP_EQ, MAP_FLOOR,
26-
MAP_GEQ, MAP_GREATER, MAP_LEQ, MAP_LESS, MAP_NEGATE, MAP_NEQ, MAP_SQRT, MAP_SQUARE,
27-
REDUCE_LENGTH, REDUCE_MAX, REDUCE_MEAN, REDUCE_MIN, REDUCE_SUM, REDUCE_SUMSQ, combine, extract,
28-
generate, lookup, map, mix, pack, reduce_components,
26+
MAP_GEQ, MAP_GREATER, MAP_LEQ, MAP_LESS, MAP_LIMIT, MAP_NEGATE, MAP_NEQ, MAP_NORMALIZE,
27+
MAP_SQRT, MAP_SQUARE, REDUCE_LENGTH, REDUCE_MAX, REDUCE_MEAN, REDUCE_MIN, REDUCE_SUM,
28+
REDUCE_SUMSQ, combine, extract, generate, lookup, map, mix, pack, reduce_components,
2929
};
3030
pub use particles::compact::compact;
3131
pub use particles::grid::{Grid, GridParams, grid_build, grid_create, grid_destroy, grid_get};

‎crates/processing_render/src/particles/algebra.rs‎

Lines changed: 34 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,8 @@ pub const MAP_GEQ: u32 = 9;
2222
pub const MAP_LEQ: u32 = 10;
2323
pub const MAP_EQ: u32 = 11;
2424
pub const MAP_NEQ: u32 = 12;
25+
pub const MAP_NORMALIZE: u32 = 13;
26+
pub const MAP_LIMIT: u32 = 14;
2527

2628
const MAP_SRC: &str = r#"
2729
struct Params {
@@ -60,10 +62,25 @@ fn main(@builtin(global_invocation_id) gid: vec3<u32>) {
6062
let i = gid.x;
6163
let n = arrayLength(&a) / params.components;
6264
if i >= n { return; }
65+
// normalize and limit scale the whole vector by its length
66+
var len2 = 0.0;
67+
for (var c = 0u; c < params.components; c = c + 1u) {
68+
let x = a[i * params.components + c];
69+
len2 += x * x;
70+
}
71+
let len = sqrt(len2);
72+
var k = 1.0;
73+
if params.op == 13u && len > 0.0 {
74+
k = params.p0 / len;
75+
} else if params.op == 14u && len > 0.0 {
76+
k = clamp(len, params.p0, params.p1) / len;
77+
}
6378
for (var c = 0u; c < params.components; c = c + 1u) {
6479
let idx = i * params.components + c;
65-
@if(in_place) { a[idx] = apply_op(a[idx]); }
66-
@if(!in_place) { dst[idx] = apply_op(a[idx]); }
80+
var r = a[idx] * k;
81+
if params.op < 13u { r = apply_op(a[idx]); }
82+
@if(in_place) { a[idx] = r; }
83+
@if(!in_place) { dst[idx] = r; }
6784
}
6885
}
6986
"#;
@@ -149,6 +166,8 @@ struct Params {
149166
op: u32,
150167
b_scale: f32,
151168
b_offset: f32,
169+
// 1 = one `b` per particle, applied to every component
170+
b_components: u32,
152171
}
153172
154173
@if(in_place) @group(0) @binding(0) var<storage, read_write> a: array<f32>;
@@ -177,7 +196,8 @@ fn main(@builtin(global_invocation_id) gid: vec3<u32>) {
177196
if i >= n { return; }
178197
for (var c = 0u; c < params.components; c = c + 1u) {
179198
let idx = i * params.components + c;
180-
let r = combine_op(a[idx], b[idx] * params.b_scale + params.b_offset);
199+
let b_idx = select(idx, i, params.b_components == 1u);
200+
let r = combine_op(a[idx], b[b_idx] * params.b_scale + params.b_offset);
181201
@if(in_place) { a[idx] = r; }
182202
@if(!in_place) { dst[idx] = r; }
183203
}
@@ -198,6 +218,16 @@ pub fn combine(
198218
check_components("combine", components)?;
199219
let v = variants(&COMBINE, COMBINE_SRC)?;
200220
let floats = buffer_size(a)? / 4;
221+
let b_floats = buffer_size(b)? / 4;
222+
let b_components = if b_floats == floats {
223+
components
224+
} else if b_floats == floats / components as u64 {
225+
1
226+
} else {
227+
return Err(ProcessingError::InvalidArgument(format!(
228+
"combine: `b` needs {components} or 1 components per particle"
229+
)));
230+
};
201231

202232
let c = if dst == a {
203233
ensure_no_alias("combine", a, &[b])?;
@@ -216,6 +246,7 @@ pub fn combine(
216246
compute_set(c, "op", ShaderValue::UInt(op))?;
217247
compute_set(c, "b_scale", ShaderValue::Float(b_scale))?;
218248
compute_set(c, "b_offset", ShaderValue::Float(b_offset))?;
249+
compute_set(c, "b_components", ShaderValue::UInt(b_components))?;
219250
dispatch_particles(c, floats, components)
220251
}
221252

‎crates/processing_render/src/particles/mod.rs‎

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -15,9 +15,9 @@ pub mod sort;
1515

1616
pub use algebra::{
1717
GEN_GAUSSIAN, GEN_SIGNED, GEN_UNIFORM, MAP_ABS, MAP_AFFINE, MAP_CLAMP, MAP_EQ, MAP_FLOOR,
18-
MAP_GEQ, MAP_GREATER, MAP_LEQ, MAP_LESS, MAP_NEGATE, MAP_NEQ, MAP_SQRT, MAP_SQUARE,
19-
REDUCE_LENGTH, REDUCE_MAX, REDUCE_MEAN, REDUCE_MIN, REDUCE_SUM, REDUCE_SUMSQ, combine, extract,
20-
generate, lookup, map, mix, pack, reduce_components,
18+
MAP_GEQ, MAP_GREATER, MAP_LEQ, MAP_LESS, MAP_LIMIT, MAP_NEGATE, MAP_NEQ, MAP_NORMALIZE,
19+
MAP_SQRT, MAP_SQUARE, REDUCE_LENGTH, REDUCE_MAX, REDUCE_MEAN, REDUCE_MIN, REDUCE_SUM,
20+
REDUCE_SUMSQ, combine, extract, generate, lookup, map, mix, pack, reduce_components,
2121
};
2222
pub use compact::compact;
2323
pub use emit::{

0 commit comments

Comments
 (0)