Getting rid of artifacts on generated gradient textures

67 views Asked by At

I'm generating a falloff texture by adding gradient part to the white image I have. If implementation is relevant, I'm doing it with HTML5 canvas. For some reason I'm getting weird ray like while artifacts where it's supposed to be gradient smooth. I couldn't find any way to take care of that on implementation level, so I have to get rid of them after generating. Question is, if I have per pixel access to the image, how do I recognize those white pixels and replace with pixels to keep the gradient smooth?

enter image description here

1

There are 1 answers

2
AudioBubble On BEST ANSWER

The rays are caused by overlaps and rounding errors. They can be removed or at least reduced by using a Gaussian blur filter (which in effect act as a low-pass filter).

To avoid new problems such as the inner shape's black pixels leaking into the gradient, I'd suggest these steps:

  1. Fill inner shape in the same color as the start color of the gradient.
  2. Produce gradients
  3. Apply Gaussian blur using either the filter property of context (f.ex context.filter = "blur(7px)";, reset by setting it to none), or by using a manual implementation
  4. Redraw the inner shape in the destination color.

Now it's a simple matter of experimenting with the blur radius to find an optimal value. Note that blurring will add to the gradient so you might want to link the two so that the radius of the gradient is reduced when blur radius is increased.

Pro-tip: you can also drop the gradient production all together and simply make the glow effect using Gaussian blur (run example below).

var ctx = c.getContext("2d");
ctx.moveTo(300, 50);
ctx.quadraticCurveTo(325, 300, 550, 550);
ctx.quadraticCurveTo(300, 500, 50, 550);
ctx.quadraticCurveTo(250, 300, 300, 50);
ctx.closePath();

// blur next drawings
ctx.filter = "blur(20px)"; // glow radius

// produce a full base using fill and heavy stroke
ctx.fillStyle = ctx.strokeStyle = "#fff";
ctx.fill();
ctx.lineWidth = 40;        // thicker = stronger spread
ctx.stroke();

// final, fill center in destination color
ctx.filter = "none";
ctx.fillStyle = "#000";
ctx.fill();
#c {background:#000}
<canvas id=c width=600 height=600></canvas>

result