In Shaders, how to avoid 'scrubbing' effect

edited April 2017 in GLSL / Shaders

In the penrose tile example for the shader (InfiniteTiles), one can see that there is a value

tileShader.set("time", millis() / 1000.0);

If I try to modify this so that the tile will move at a speed according to my mouse,

float t =millis() / 1000.0; 
float pctX = map (mouseX, 0, width, 0, 1);
tileShader.set("time", t*pctX);

the shader will do this 'scrubbing' effect where the entire image moves very quickly, but then once you stop moving the mouse, it will go at the speed you want. Is there any way to avoid this scrubbing effect? What I'm trying to accomplish are smooth increases in speed of the tile movement.

Answers

  • edited March 2017 Answer ✓

    @aarondbaron --

    This problem isn't specific to shaders -- you would have the same problem if you were doing this with img(). You can't do clock math in this way. Multiplying anything by millis() will always create a scaling effect -- which in this case will always create what you call "scrubbing." For example, if you change the multiplier, 10 seconds suddenly becomes 15.

    Instead, in order to change the speed at which the clock changes in the future but not to change how far it has advanced up-to-now, keep your own clock variable separate from millis(), and change the step amount (use addition, not multiplication) each draw frame. Now the speed at which the clock advances will change, but the base offset (the last clock time) won't jump around, because the original value isn't being scaled (multiplied).

    Here is a working example:

    //-------------------------------------------------------------
    // How to change the speed at which a shader scrolls
    // Modification of InfiniteTiles by martiSteiger
    // forum.processing.org/two/discussion/21149/in-shaders-how-to-avoid-scrubbing-effect
    //-------------------------------------------------------------
    
    PImage tileTexture;
    PShader tileShader;
    float clock; // make your own clock
    
    void setup() {
      size(640, 480, P2D);
      textureWrap(REPEAT);
      tileTexture = loadImage("penrose.jpg");
      loadTileShader();
    }
    
    void loadTileShader() {  
      tileShader = loadShader("scroller.glsl");
      tileShader.set("resolution", float(width), float(height));  
      tileShader.set("tileImage", tileTexture);
    }
    
    void draw() {
      clock = clock + map(mouseX, 0, width, 0, 1); // each frame add a tick, don't multiply
      tileShader.set("time", clock);
      shader(tileShader);             
      rect(0, 0, width, height);
    }
    
  • Thanks. Seems so obvious now.... :)

  • Timely post, thanks - I was dealing with the same issue this week.

  • Simplified version for clock = clock + map(mouseX, 0, width, 0, 1);: :ar!
    clock += norm(mouseX, 0, width);

  • Even more simplified - clock += mouseX/(float)width, and perhaps a tiny bit faster *-:)

  • edited April 2017

    Beaten me to it, @Lord_of_the_Galaxy! >:)

Sign In or Register to comment.