3434import heronarts .lx .parameter .FunctionalParameter ;
3535import heronarts .lx .parameter .LXParameter ;
3636import heronarts .lx .pattern .LXPattern ;
37+ import heronarts .lx .transform .LXParameterizedMatrix ;
3738import heronarts .lx .utils .LXUtils ;
3839
3940import static heronarts .lx .utils .Noise .*;
@@ -265,6 +266,30 @@ public double getValue() {
265266 new BoundedParameter ("Ridge" , .9 , 0 , 2 )
266267 .setDescription ("Used to invert the feedback ridges" );
267268
269+ public final BooleanParameter rotate =
270+ new BooleanParameter ("Rotate" , false )
271+ .setDescription ("Whether to rotate the geometry" );
272+
273+ public final CompoundParameter yaw =
274+ new CompoundParameter ("Yaw" , 0 , 360 )
275+ .setWrappable (true )
276+ .setUnits (CompoundParameter .Units .DEGREES )
277+ .setDescription ("Yaw rotation" );
278+
279+ public final CompoundParameter pitch =
280+ new CompoundParameter ("Pitch" , 0 , 360 )
281+ .setWrappable (true )
282+ .setUnits (CompoundParameter .Units .DEGREES )
283+ .setDescription ("Pitch rotation" );
284+
285+ public final CompoundParameter roll =
286+ new CompoundParameter ("Roll" , 0 , 360 )
287+ .setWrappable (true )
288+ .setUnits (CompoundParameter .Units .DEGREES )
289+ .setDescription ("Roll rotation" );
290+
291+ private final LXParameterizedMatrix transform = new LXParameterizedMatrix ();
292+
268293 private final GradientUtils .GrayTable invertLUT = new GradientUtils .GrayTable (this .invert , 256 );
269294
270295 public NoisePattern (LX lx ) {
@@ -305,6 +330,11 @@ public NoisePattern(LX lx) {
305330 addParameter ("yMode" , this .yMode );
306331 addParameter ("zMode" , this .zMode );
307332
333+ addTransformParameter ("rotate" , this .rotate );
334+ addTransformParameter ("yaw" , this .yaw );
335+ addTransformParameter ("pitch" , this .pitch );
336+ addTransformParameter ("roll" , this .roll );
337+
308338 // Set the order of most useful control parameters
309339 setRemoteControls (
310340 this .scale ,
@@ -324,6 +354,11 @@ public NoisePattern(LX lx) {
324354 );
325355 }
326356
357+ private void addTransformParameter (String key , LXParameter parameter ) {
358+ addParameter (key , parameter );
359+ this .transform .addParameter (parameter );
360+ }
361+
327362 @ Override
328363 public void onParameterChanged (LXParameter p ) {
329364 super .onParameterChanged (p );
@@ -340,6 +375,17 @@ public void onParameterChanged(LXParameter p) {
340375 public void run (double deltaMs ) {
341376 this .invertLUT .update ();
342377
378+ if (this .rotate .isOn ()) {
379+ this .transform .update (matrix -> {
380+ matrix
381+ .translate (.5f , .5f , .5f )
382+ .rotateZ ((float ) Math .toRadians (-this .roll .getValue ()))
383+ .rotateX ((float ) Math .toRadians (-this .pitch .getValue ()))
384+ .rotateY ((float ) Math .toRadians (-this .yaw .getValue ()))
385+ .translate (-.5f , -.5f , -.5f );
386+ });
387+ }
388+
343389 switch (this .algorithm .getEnum ()) {
344390 case PERLIN :
345391 case FBM :
@@ -353,6 +399,37 @@ public void run(double deltaMs) {
353399 }
354400 }
355401
402+ private interface CoordinateAccessor {
403+
404+ public float xn (LXPoint p );
405+ public float yn (LXPoint p );
406+ public float zn (LXPoint p );
407+
408+ static final CoordinateAccessor RAW = new CoordinateAccessor () {
409+ public float xn (LXPoint p ) {
410+ return p .xn ;
411+ }
412+ public float yn (LXPoint p ) {
413+ return p .yn ;
414+ }
415+ public float zn (LXPoint p ) {
416+ return p .zn ;
417+ }
418+ };
419+ }
420+
421+ private final CoordinateAccessor TRANSFORM = new CoordinateAccessor () {
422+ public float xn (LXPoint p ) {
423+ return transform .xn (p );
424+ }
425+ public float yn (LXPoint p ) {
426+ return transform .yn (p );
427+ }
428+ public float zn (LXPoint p ) {
429+ return transform .zn (p );
430+ }
431+ };
432+
356433 private void runPerlin (double deltaMs , Algorithm algorithm ) {
357434 final int seed = this .seed .getValuei ();
358435
@@ -375,15 +452,17 @@ private void runPerlin(double deltaMs, Algorithm algorithm) {
375452 final float maxLevel = this .maxLevel .getValuef ();
376453 final float level = LXUtils .lerpf (minLevel , maxLevel , (this .level .getValuef () - contrast / 4 ) * .01f );
377454
455+ final CoordinateAccessor coord = this .rotate .isOn () ? TRANSFORM : CoordinateAccessor .RAW ;
456+
378457 final CoordinateFunction xMode = this .xMode .getEnum ().function ;
379458 final CoordinateFunction yMode = this .yMode .getEnum ().function ;
380459 final CoordinateFunction zMode = this .zMode .getEnum ().function ;
381460
382461 if (algorithm .equals (Algorithm .PERLIN )) {
383462 for (LXPoint p : model .points ) {
384- float xd = xMode .getCoordinate (p , p .xn , xo );
385- float yd = yMode .getCoordinate (p , p .yn , yo );
386- float zd = zMode .getCoordinate (p , p .zn , zo );
463+ float xd = xMode .getCoordinate (p , coord .xn ( p ) , xo );
464+ float yd = yMode .getCoordinate (p , coord .yn ( p ) , yo );
465+ float zd = zMode .getCoordinate (p , coord .zn ( p ) , zo );
387466
388467 float b = level + contrast * stb_perlin_noise3_seed (xa + xs * xd , ya + ys * yd , za + zs * zd , 0 , 0 , 0 , seed );
389468 this .colors [p .index ] = this .invertLUT .lut [(int ) (2.559 * clamp (b , minLevel , maxLevel ))];
@@ -396,25 +475,25 @@ private void runPerlin(double deltaMs, Algorithm algorithm) {
396475 if (algorithm .equals (Algorithm .RIDGE )) {
397476 float ridgeOffset = this .ridgeOffset .getValuef ();
398477 for (LXPoint p : model .points ) {
399- float xd = xMode .getCoordinate (p , p .xn , xo );
400- float yd = yMode .getCoordinate (p , p .yn , yo );
401- float zd = zMode .getCoordinate (p , p .zn , zo );
478+ float xd = xMode .getCoordinate (p , coord .xn ( p ) , xo );
479+ float yd = yMode .getCoordinate (p , coord .yn ( p ) , yo );
480+ float zd = zMode .getCoordinate (p , coord .zn ( p ) , zo );
402481 float b = level + contrast * stb_perlin_ridge_noise3 (xa + xs * xd , ya + ys * yd , za + zs * zd , lacunarity , gain , ridgeOffset , octaves );
403482 this .colors [p .index ] = this .invertLUT .lut [(int ) (2.559 * clamp (b , minLevel , maxLevel ))];
404483 }
405484 } else if (algorithm .equals (Algorithm .FBM )) {
406485 for (LXPoint p : model .points ) {
407- float xd = xMode .getCoordinate (p , p .xn , xo );
408- float yd = yMode .getCoordinate (p , p .yn , yo );
409- float zd = zMode .getCoordinate (p , p .zn , zo );
486+ float xd = xMode .getCoordinate (p , coord .xn ( p ) , xo );
487+ float yd = yMode .getCoordinate (p , coord .yn ( p ) , yo );
488+ float zd = zMode .getCoordinate (p , coord .zn ( p ) , zo );
410489 float b = level + contrast * stb_perlin_fbm_noise3 (xa + xs * xd , ya + ys * yd , za + zs * zd , lacunarity , gain , octaves );
411490 this .colors [p .index ] = this .invertLUT .lut [(int ) (2.559 * clamp (b , minLevel , maxLevel ))];
412491 }
413492 } else if (algorithm .equals (Algorithm .TURBULENCE )) {
414493 for (LXPoint p : model .points ) {
415- float xd = xMode .getCoordinate (p , p .xn , xo );
416- float yd = yMode .getCoordinate (p , p .yn , yo );
417- float zd = zMode .getCoordinate (p , p .zn , zo );
494+ float xd = xMode .getCoordinate (p , coord .xn ( p ) , xo );
495+ float yd = yMode .getCoordinate (p , coord .yn ( p ) , yo );
496+ float zd = zMode .getCoordinate (p , coord .zn ( p ) , zo );
418497 float b = level + contrast * stb_perlin_turbulence_noise3 (xa + xs * xd , ya + ys * yd , za + zs * zd , lacunarity , gain , octaves );
419498 this .colors [p .index ] = this .invertLUT .lut [(int ) (2.559 * clamp (b , minLevel , maxLevel ))];
420499 }
0 commit comments