@@ -343,3 +343,134 @@ impl Modifier for SetPositionCone3dModifier {
343343 Ok ( ( ) )
344344 }
345345}
346+
347+ /// A modifier to set the position of particles on a box.
348+ ///
349+ /// The box is axis aligned.
350+ ///
351+ /// Particles are moved somewhere inside the volume or on the surface of a
352+ /// box defined by its extent.
353+ ///
354+ /// # Attributes
355+ ///
356+ /// This modifier requires the following particle attributes:
357+ /// - [`Attribute::POSITION`]
358+ #[ derive( Clone , Copy , Hash , Reflect ) ]
359+ pub struct SetPositionBoxModifier {
360+ /// The box center, relative to the emitter position.
361+ ///
362+ /// Expression type: `Vec3`
363+ pub center : ExprHandle ,
364+ /// The extent of the box.
365+ ///
366+ /// Expression type: `Vec3`
367+ pub extent : ExprHandle ,
368+ /// The shape dimension to set the position to.
369+ pub dimension : ShapeDimension ,
370+ }
371+
372+ impl SetPositionBoxModifier {
373+ fn eval (
374+ & self ,
375+ module : & mut Module ,
376+ context : & mut dyn EvalContext ,
377+ ) -> Result < String , ExprError > {
378+ let func_id = calc_func_id ( self ) ;
379+ let func_name = format ! ( "set_position_box_{0:016X}" , func_id) ;
380+
381+ context. make_fn (
382+ & func_name,
383+ "particle: ptr<function, Particle>" ,
384+ module,
385+ & mut |m : & mut Module , ctx : & mut dyn EvalContext | -> Result < String , ExprError > {
386+ let center = ctx. eval ( m, self . center ) ?;
387+ let extent = ctx. eval ( m, self . extent ) ?;
388+
389+ let code = match self . dimension {
390+ ShapeDimension :: Surface => {
391+ format ! (
392+ r#" let center = {};
393+ let extent = {};
394+
395+ let face = frand();
396+ let rand1 = frand() - 0.5;
397+ let rand2 = frand() - 0.5;
398+ let fixed = 0.5;
399+
400+ var x: f32;
401+ var y: f32;
402+ var z: f32;
403+
404+ if face < (1. / 6.) {{
405+ x = rand1 * extent.x;
406+ y = fixed * extent.y;
407+ z = rand2 * extent.z;
408+ }} else if face < (2. / 6.) {{
409+ x = rand1 * extent.x;
410+ y = -fixed * extent.y;
411+ z = rand2 * extent.z;
412+ }} else if face < (3. / 6.) {{
413+ x = fixed * extent.x;
414+ y = rand1 * extent.y;
415+ z = rand2 * extent.z;
416+ }} else if face < (4. / 6.) {{
417+ x = -fixed * extent.x;
418+ y = rand1 * extent.y;
419+ z = rand2 * extent.z;
420+ }} else if face < (5. / 6.) {{
421+ x = rand1 * extent.x;
422+ y = rand2 * extent.y;
423+ z = fixed * extent.z;
424+ }} else {{
425+ x = rand1 * extent.x;
426+ y = rand2 * extent.y;
427+ z = -fixed * extent.z;
428+ }}
429+ (*particle).{} = center + vec3(x, y, z);
430+ "# ,
431+ center,
432+ extent,
433+ Attribute :: POSITION . name( )
434+ )
435+ }
436+ ShapeDimension :: Volume => format ! (
437+ r#" let center = {};
438+ let extent = {};
439+ let mult = frand3() - 0.5;
440+ (*particle).{} = center + extent * mult;
441+ "# ,
442+ center,
443+ extent,
444+ Attribute :: POSITION . name( )
445+ ) ,
446+ } ;
447+
448+ Ok ( code)
449+ } ,
450+ ) ?;
451+
452+ let code = format ! ( "{}(&particle);\n " , func_name) ;
453+
454+ Ok ( code)
455+ }
456+ }
457+
458+ impl Modifier for SetPositionBoxModifier {
459+ fn context ( & self ) -> ModifierContext {
460+ ModifierContext :: Init | ModifierContext :: Update
461+ }
462+
463+ fn attributes ( & self ) -> & [ Attribute ] {
464+ & [ Attribute :: POSITION ]
465+ }
466+
467+ fn boxed_clone ( & self ) -> BoxedModifier {
468+ Box :: new ( * self )
469+ }
470+
471+ fn apply ( & self , module : & mut Module , context : & mut ShaderWriter ) -> Result < ( ) , ExprError > {
472+ let code = self . eval ( module, context) ?;
473+ context. main_code += & code;
474+ Ok ( ( ) )
475+ }
476+ }
0 commit comments