Skip to content

Learning LX: Effects

Mark Slee edited this page Dec 9, 2020 · 1 revision

Overview

A second common unit for animations in LX is the LXEffect class. An LXEffect implements a real-time run loop which modifies the pixel values of an already-computed animation. An effect comes after at least one pattern, and may be in a chain of many effects.

Scaffolding

The basic scaffolding of an effect class looks as follows:

public class ExampleEffect extends LXEffect {

  /**
   * A basic constructor should be provided which passes lx to the super-constructor
   */
  public ExampleEffect(LX lx) {
    super(lx);
  }

  public void run(double deltaMs, double enabledAmount) {
    // This method is called in real-time when the effect is active, with
    // deltaMs indicating how many milliseconds have passed since the previous frame.

    // The enabledAmount parameter indicates with a value from 0-1 how strongly
    // to apply the effect. Damping is automatically enabled when the effect is turned
    // on or off.

    // The loop is not called when the effect is inactive.
  }
}

Rendering

The core loop may perform whatever mutations it likes to the colors array, taking note that the previous values in colors are the source material that the effect is intended to modify.

  public void run(double deltaMs, double enabledAmount) {
    for (LXPoint p : model.points) {
      colors[p.index] = /* perform some mutation of the color here */
    }
  }

Note that the colors array is not owned by the effect object. At the time run is called, it will contain the values generated by whatever came before this effect in the processing chain. The effect will not have access to the values generated on this frame in future frames. If those values are needed, a secondary buffer may be used to store them.

Parameters and Modulators

An effect may expose parameters to give expose control of its behaviors to the user. As well as using modulators to help generate changing values over time. These should be added as fields to the class and registered in the constructor.

public class ExampleEffect extends LXEffect {

  // This is a parameter with default value 5, range 0-100
  public final CompoundParameter exampleParam =
    new CompoundParameter("Param", 5, 0, 100)
    .setDescription("This is an example parameter");

  // This is an LFO oscillating in a sin wave from 0 to 1 every second (1000ms)
  public final SinLFO lfo = new SinLFO(0, 1, 1000);
  
  public ExampleEffect(LX lx) {
    super(lx);
    addParameter("example", this.exampleParam);
    addModulator(this.lfo).start();
  }

  public void run(double deltaMs, double enabledAmount) {
    // Parameter and modulator values are automatically updated and can be
    // retrieved at runtime
    float paramValue = this.exampleParam.getValuef();
    float lfoValue = this.lfo.getValuef();
    ...
  }
}

Annotations

Category

/**
 * The LXCategory annotation may specify a String (or LXCategory constant) indicating
 * where this effect is shown in the LX content library
 */
@LXCategory(LXCategory.TEXTURE)
public class ExampleEffect extends LXEffect {

Custom Name

/**
 * The LXComponentName annotation may be used to provide a custom name for this device
 * to be show in the UI. The default name will be the name of the class itself, with
 * the "Effect" suffix removed. Another name may be specified if preferred.
 */
@LXComponentName("CustomName")
public class ExampleEffect extends LXEffect {