p5.js: Make a Gradient Stroke with beginShape()

4.2k views Asked by At

The following code generates a single particle at a random position. The particle moves right, once it's completely off the screen, it appears left again.

The particle creates a nice trail. However, I'd like the trail to fade out.
I tried setting the stroke color stroke(random(255)) while setting the vertexes, but it changes the color of the entire shape instead.

You will find the relevant lines at the comment
// draw particle and history (approx. line 76)

https://codepen.io/normanwink/project/editor/XJoRYa

<!DOCTYPE html>
<html>
    <head>
        <link rel="stylesheet" href="css/style.css">
    </head>
    <body>
        <div id="framerate"></div>
        <!-- scripts -->
        <script src="https://github.com/processing/p5.js/releases/download/0.5.14/p5.min.js"></script>
        <script>
            function setup() {
                frameRate(30);
                createCanvas(1000, 500, 'WEBGL');

                particle = new Particle();
            }

            function draw() {
                background(0);

                particle.update();
                particle.edges();
                particle.show();

                var output = '';
                output += floor(frameRate()) + 'fps';

                document.getElementById('framerate').innerHTML = output;
            }

            function Particle(mX = random(width), mY = random(height)) {
                this.pos = createVector(mX,mY);
                this.vel = createVector(8,0);
                this.acc = createVector(0,0);
                this.maxSpeed = 8;
                this.trail = 60; // how long to track history
                this.history = [];

                this.update = function() {
                    this.vel.add(this.acc);
                    this.vel.limit(this.maxSpeed);
                    this.pos.add(this.vel);
                    this.acc.mult(0);

                    this.history.push(this.pos.copy());

                    if (this.history.length > this.trail) {
                        this.history.splice(0,1);
                    }
                }

                this.show = function() {
                    stroke(255);
                    strokeWeight(5);

                    // draw particle and history
                    beginShape();
                    for (var i=0; i<this.history.length; i++) {
                        var pos = this.history[i];
                        // stroke(random(255))
                        curveVertex(pos.x, pos.y);
                    }
                    endShape();

                    noStroke();
                    fill(255);
                    ellipse(this.pos.x, this.pos.y, 10);

                }

                // if particle hits the edge
                this.edges = function() {
                    if (this.history[0].x > width && this.pos.x > width) {
                        this.pos.x = 0;
                        this.history = [];
                        return false;
                    }
                    if (this.history[0].x < 0 && this.pos.x < 0) {
                        this.pos.x = width;
                        this.history = [];
                        return false;
                    }
                    if (this.history[0].y > height && this.pos.y > height) {
                        this.pos.y = 0;
                        this.history = [];
                        return false;
                    }
                    if (this.history[0].y < 0 && this.pos.y < 0) {
                        this.pos.y = height;
                        this.history = [];
                        return false;
                    }
                }
            }
        </script>
    </body>
</html>

Unfortunately, it requires minor physics and handling the particles collision with the edges to work, so this is the most reduced version of the code.
For those who are interested, here is a full example: https://codepen.io/normanwink/pen/jLdpez

1

There are 1 answers

4
Kevin Workman On BEST ANSWER

You'll have better luck if you post a MCVE showing what you've tried along with a specific techincal question. Here's an example:

function setup(){
  createCanvas(200, 200);
}
  
function draw(){
  background(220);

  noFill();
  stroke(255);
  beginShape();
  curveVertex(84,  91);
  curveVertex(84,  91);
  curveVertex(68,  19);

  stroke(128);
  curveVertex(21,  17);

  stroke(0);
  curveVertex(32, 100);
  curveVertex(32, 100);
  endShape();
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/p5.js/0.5.14/p5.js"></script>

We might expect this to show a very basic gradient on a path. (Notice how much easier this is to think about than your whole project!) But if we run it, then we'll see that it only ever takes the last color, in this case black.

To get around this, we need to break your path down into multiple shapes. Here's the same path, split into multiple shapes so we can give each section of the path a different shape:

function setup() { 
  createCanvas(200, 200);
} 

function draw() { 
  background(220);
 
  noFill();
 
 
  stroke(0);
  beginShape();
  curveVertex(84,  91);
  curveVertex(84,  91);
  curveVertex(68,  19);
  curveVertex(21,  17);
  endShape();
 
  stroke(128);
  beginShape();
  curveVertex(84,  91);
  curveVertex(68,  19);
  curveVertex(21,  17);
  curveVertex(32, 100);
  endShape();
 
  stroke(255);
  beginShape();
  curveVertex(68,  19);
  curveVertex(21,  17);
  curveVertex(32, 100);
  curveVertex(32, 100);
  endShape();
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/p5.js/0.5.14/p5.js"></script>

If we run that, we'll see that the path does indeed have different colors.

You'd need to do something very similar where you break your path down into multiple shapes. Then you'd just need to modify the color passed into the stroke() function to create your gradient.