5

I wish to draw a simple mouse trail using fragment shaders, similar in appearance to drawing the following in processing (omitting the step of clearing the canvas). I cannot wrap my head around the setup necessary to achieve this.

processing reference

// processing reference using cursor as paintbrush
void setup () {
  size(400, 400);
  background(255);
  fill(0);
}

void draw () {
  ellipse(mouseX, mouseY, 20, 20);
}

Here's my vain approach, based on this shadertoy example:

  1. I draw a simple shape at cursor position
void main(void) {
    float pct = 0.0;
    pct = distance(inData.v_texcoord.xy, vec2(mouse.x, 1.-mouse.y)) * SIZE;
    pct = 1.0 - pct - BRIGHTNESS;
    vec3 blob = vec3(pct);
 
    fragColor = vec4( blob, 1.0 );
}
  1. Then my confusion begins. My thinking goes that I'd need to mix the output above with a texture containing my previous pass. This creates at least a solid trail, albeit copying the previous pass only within a set distance from the mouse position.
#shader pass 1
void main(void) {
    float pct = 0.0;
    pct = distance(inData.v_texcoord.xy, vec2(mouse.x, 1.-mouse.y)) * SIZE;
    pct = 1.0 - pct - BRIGHTNESS;
    vec3 blob = vec3(pct);
    
    vec3 stack = texture(prevPass, inData.v_texcoord.xy).xyz;
    
    fragColor = vec4( blob*.1 + (stack*2.), 1.0 );
}
#shader pass 2
void main(void) {
    fragColor = texture(prevPass,inData.v_texcoord);
}

enter image description here

Frankly, I'm a little bit in the blue about how to draw without data and "stack" previous draw calls in webgl on a conceptual level, and I'm having a hard time finding beginner documentation.

I would be grateful if someone could point me towards where my code and thinking becomes faulty, or point me towards some resources.

msalla
  • 717
  • 6
  • 23

2 Answers2

2

What you need to do is:

After doing your first pass rendering (i.e. making an ellipse at the cursor position), copy the contents of the framebuffer to a different image.

Then pass this image as an sampler input to the next pass. Notice how that shadertoy example ahs 2 images.

Makogan
  • 8,208
  • 7
  • 44
  • 112
-2

You can make a simple HTML/Javascript trail with this code:

<!DOCTYPE html>
<style>
  .trail { /* className for trail elements */
    position: absolute;
    height: 6px; width: 6px;
    border-radius: 3px;
    background: teal;
  }
  body {
    height: 300px;
  }
</style>

<body>
  <script>
    document.body.addEventListener("mousemove", moved);

    // create, style, append trail elements
    var trailElements = [];
    var numOfTrailElements = 10;
    for (var i = 0; i < numOfTrailElements; i++) {
      var element = document.createElement('div');
      element.className = 'trail';
      document.body.appendChild(element);
      trailElements.push(element);
    }

    // when mouse moves, display trail elements in wake of mouse pointer
    var counter = 0; // current trail element index
    function moved(event) {              
      trailElements[counter].style.left = event.clientX + 'px';
      trailElements[counter].style.top = event.clientY + 'px';

      if (counter == 9) {
        counter = 0;
      } else {
          counter += 1; 
      }
    }
  </script>
</body>


<!doctype html>

<style>
  .trail { /* className for the trail elements */
    position: absolute;
    height: 6px; width: 6px;
    border-radius: 3px;
    background: black;
  }
  body {
    height: 300px;
  }
</style>

<body>
<script>
  var dots = [];
  for (var i = 0; i < 12; i++) {
    var node = document.createElement("div");
    node.className = "trail";
    document.body.appendChild(node);
    dots.push(node);
  }
  var currentDot = 0;
  
  addEventListener("mousemove", function(event) {
    var dot = dots[currentDot];
    dot.style.left = (event.pageX - 3) + "px";
    dot.style.top = (event.pageY - 3) + "px";
    currentDot = (currentDot + 1) % dots.length;
  });
</script>
</body>