I’m sure there are numerous approaches, but here’s one idea:
Instead of using the color each pixel in the “drawing” as a discreet indicator of which source to use (depending on whether the pixel is red, green, or blue), use the red green and blue channels of the drawing as percentages indicating how much of each source to use:
// Normalize the color channels to use as multipliers so that the sum maxes
// out at 1.0
vec3 dnorm = d.rgb / (d.r + d.g + d.b);
// Combine the 3 sources using the R G and B channels of the drawing as masks
// representing how much of each source to use.
gl_FragColor = vec4(
// Premultiplying the alpha has the effect of drawing over a black background
(s1.r * dnorm.r + s2.r * dnorm.g + s3.r * dnorm.b) * d.a,
(s1.g * dnorm.r + s2.g * dnorm.g + s3.g * dnorm.b) * d.a,
(s1.b * dnorm.r + s2.b * dnorm.g + s3.b * dnorm.b) * d.a,
1.0
);
Now, with the existing drawing code this would result in exactly the same effect you already have, however, now you can modify your drawing code to use alpha and blend together the three colors. This could be as simple as giving the drawingColor
a low alpha value, but if you want to get fancy you could use a linear gradient (note: it makes the most sense not to use WebGL for the drawing
graphics context, because it will work just as well as a textured, and WebGL doesn’t support gradients).
// Example of a gradient creation in setup():
g1 = drawing.drawingContext.createRadialGradient(0, 0, 5, 0, 0, 150);
g1.addColorStop(0, 'rgba(255, 0, 0, 0.05)');
g1.addColorStop(0.5, 'rgba(255, 0, 0, 0.01)');
g1.addColorStop(1, 'rgba(255, 0, 0, 0.0)');
// Wherever you draw your circle (I moved this to mouseDragged)
drawing.push();
drawing.translate(mouseX, mouseY);
drawing.drawingContext.fillStyle = drawingGradient;
drawing.ellipse(0, 0, 150);
drawing.pop();
Here’s a working example (click and drag the mouse to paint).