Is there a better way to draw gradient colored ellipse?

I’m pretty new to Processing and graphical programming but keen to learn new stuff. I was trying to create a gradient colored sun for my project but I couldn’t find any obvious technique to do this. This is the solution I came up with:

void setup() {
  size(600,600);
  for (float k = 0; k < PI/2; k += PI/1000) {    // looping through the highest point of the circle to the middle
    float xMul = cos(k);
    float yMul = sin(k);
    float x = xMul * height/4;
    float y = yMul * height/4;
    stroke(map(k,0,PI/2,255,255),map(k,0,PI/2,255,0),0);    // defining the color gradient by the Y coordinate
    line(width/2-x,height/2-y,width/2+x,height/2-y);    // drawing the top part of the circle
    line(width/2-x,height/2+y,width/2+x,height/2+y);
  }
}

It’s all in the setup method for simplicity. But anyways, I was wondering if there would be some more efficient way to do this. With my solution the program executes quite a many rows of code to accomplish such a simple task. Any ideas?

That is one way to dray the circle, for a smoother color ramp you can use lerpColor().
https://processing.org/reference/lerpColor_.html

Here another of many ways to accomplish this …

void setup() {
  size(500, 500);
  noStroke();
  background(3, 7, 11);

  drawSunGradient(color(#F0BA70), color(#C12600), 450, 3);
}

void drawSunGradient(color fromColor, color toColor, final int diam, final int inc) {
  for (int x = diam; x > 0; x -= inc) {
    float inter = map(x, 0, diam, 0, 1.0);
    color lerpedColor = lerpColor(fromColor, toColor, inter);
    fill(lerpedColor);
    circle(width*0.5, height*0.5, x);
  }
}

Hello,

Advanced topic…

This may be of interest:

You can create an image with Processing, other tools or use an existing one (with permission if needed).

:)

Welcome to the forum! :slight_smile:

There is a more efficient way, but efficient ways are not always easy. By programming the GPU you can create gradients, but it’s a different language called GLSL. If you’re starting with Processing then you can look at this in a year or two :slight_smile:

The reason it’s faster it’s because there are no loops. The GPU calculates all the pixel colors in parallel. I’ll leave it here just in case someone needs faster gradients:

PShader gradient;
void setup() {
  size(800, 800, P2D);

  gradient = new PShader(this, new String[] {
      "uniform mat4 transformMatrix;", 
      "attribute vec4 position;", 
      "attribute vec4 color;", 
      "varying vec4 va_color;", 
      "varying vec2 va_pos;",
      "void main() {", 
      "  gl_Position = transformMatrix * position;", 
      "  va_color = color;",
      "  va_pos = position.xy;",
      "}"
    }, new String[] {
      "uniform vec2 center;",
      "uniform vec3 centerColor;",
      "uniform float radius;",
      "uniform bool linear;",
      "varying vec4 va_color;", 
      "varying vec2 va_pos;",
      "void main() {",
      "  float d = (linear ? distance(center.y, va_pos.y) : distance(center, va_pos))/radius;",
      "  vec3 c = mix(centerColor / 255.0, va_color.rgb, min(d*d, 1.0));",
      "  gl_FragColor = vec4(c, va_color.a);", 
      "}"
    });
}

void draw() {
  float x = random(width);
  float y = random(height);
  float radius = random(20, 200);

  shader(gradient); // activate the shader. Next shapes are affected by it.
  gradient.set("center", x, y); // set the center of the gradient
  gradient.set("radius", radius); // set the radius of the gradient
  gradient.set("linear", false); // two modes: linear and radial
  gradient.set("centerColor", random(255), random(255), random(255)); // use 3 floats here!
  fill(random(255), random(255), random(255)); // the outer color
  noStroke();
  circle(x, y, radius * 2); // you can draw any shape, not just circles
  resetShader(); // deactivate the shader. Next shapes use default rendering
  // ...draw something else here
}

The “linear” mode I implemented is just a vertical gradient. You can change .y to .x to make it horizontal. To allow any angle it needs some work. Instead of center and radius we should define startPos and endPos for the shader.

Note that center and radius do not need to match the shape you draw. You can draw a radial gradient in a square. Or set the center of the gradient in the top-left corner of the window and the shape on the center. You can experiment :slight_smile:

Another note: centerColor must be 3 floats. It won’t work if you use integers. Fortunately random() produces floats.

One place to learn about shaders is the https://thebookofshaders.com/ (oops, link was wrong! fixed)

ps. Forgot to mention that the gradient is exponential. You can replace d*d with d to distribute the colors uniformly instead. Or with pow(d, 3.0) for a more extreme exponential distribution.

4 Likes