Better color gradient for custom PShape

Hey forum, I’m having trouble trying to apply a smooth color gradient to a PShape via per vertex shading.

Currently I am filling the points based on the angle of each point. As you can see, the gradient appears to conform to the triangles that make up the polygon.

I was wondering if there was any way to make the gradient appear smooth and still have the per-vertex shading

void setup() {
  size(200, 200, P2D);
  colorMode(HSB, 100);
}
void draw() {
  background(0, 0, 100);
  beginShape();
  for (float i = 0; i < TWO_PI; i+=TWO_PI/12.0) {
    float a = i/TWO_PI;
    fill(a*100, 100, 100);
    vertex(width/2+sin(i)*50, height/2+cos(i)*50);
  }
  endShape(CLOSE);
}

1 Like

Hello,

Add more vertices
Add color to each vertex as required.
Rinse and repeat.




Increased number of slices to 720; just one variable in code example.

Notice what I did in code below.
I used the loop as an integer counter and then used this later to generate angle.
You can do the same for the vertex colors as you sweep through the color wheel; HSB will make that easy.

I left the ? for you to consider.

Minor changes (maybe too much!) to your code:

void setup() 
  {
  size(500, 500, P2D);
  colorMode(HSB, 100);
  }
void draw() 
  {
  background(0);
  //noStroke
  //stroke(100, 100, 100);
  //strokeWeight(2);
  beginShape();
  int count = 12;
  for (int i = 0; i < count; i+=1)
    {
    float a = i*TWO_PI/count;
    fill(0);
    vertex(width/2, height/2);
    fill( ? , 100, 100);
    vertex(width/2+sin(a)*150, height/2+cos(a)*150);
    vertex(?,?);
    }

  endShape(CLOSE);
  }

My favorite example of vertex coloring:
https://processing.org/examples/rgbcube.html

``:)

1 Like

Yes, I’ve thought of this! It really is the best solution, however I’m not sure how well it would smooth over with more complex shapes, which is my ultimate intention. I guess I could always calculate the average vertex to get the center, or use a more complex algorithm to find a suitable ‘center’…

And as for that example, why the heck haven’t I ever seen that before?!? Definitely would’ve come in handy for my past 3D projects :laughing:

There are some gems to be found at the Processing website.

The RGB Cube example does not appear to be linked from here:
https://processing.org/examples/

Update:
Some of the examples are missing from the website but they are available wit the Processing IDE:

And in the Processing repository:
https://github.com/processing
https://github.com/processing/processing-docs/
https://github.com/processing/processing-docs/tree/master/content/examples < This folder.

:)

2 Likes

Maybe this doesn’t help much, as it requires learning a new language (GLSL), but I couldn’t help myself :slight_smile:

Instead of adding lots of vertices, this creates a rainbow-gradient shader. It’s rendered around the specified center and with a given radius (gradient center and radius are passed to the shader using .set().

Then you can draw any shapes you want (circles, squares or something else) and it will be painted with that gradient.

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

  gradient = new PShader(this, new String[] {
    "uniform mat4 transform; attribute vec4 position;", 
    "void main() { gl_Position = transform * position; }"
  }, new String[] {
    "uniform vec2 center;",
    "uniform float radius;",
    "void main() {",
    "  vec2 diff = gl_FragCoord.xy - center;",
    "  float d = clamp(length(diff) / radius, 0.0, 1.0);",
    "  float a = atan(diff.y, diff.x);", 
    "  float r = sin(a) * 0.5 + 0.5;",
    "  float g = sin(a + 2.09) * 0.5 + 0.5;",
    "  float b = sin(a + 4.19) * 0.5 + 0.5;",
    "  gl_FragColor = vec4(r*d, g*d, b*d, 1.0);", 
    "}"
  });
  shader(gradient);  
  hint(DISABLE_OPTIMIZED_STROKE);
}

void gradientCircle(float x, float y, float diam) {
  gradient.set("center", x, height-y);
  gradient.set("radius", diam * 0.5);
  circle(x, y, diam);
}

void draw() {
  background(40);
  for(int i=0; i<10; i++) {
    float F = millis() * i * 0.0001;
    gradientCircle(width*0.5 + 300*sin(i+F), height*0.5 + 300*cos(i+F), 300 - 20 * i);
  }
}

I can try to explain how it works if anyone is curious.

2 Likes

Yes, please.
This is really nice. I had a quick look at this page. But I didn’t see there how you can implement it within Processing in string form.

So I found a simple solution that works for my specific problem but I’m not sure how well it would work for other problems.

Basically all I have to do is create two images: one that has shading and one that doesn’t. This way I can use the non-shaded image as a means of picking the right pixels from the shaded image.

Here is an example of the two images. As you can see, the non-shaded image is more clearly defined, so a pass over its pixels can determine which pixels from the shaded image should be carried over.

.example9

3 Likes

Unfortunately no, but I do hope that I will wrap my head around shaders one day. They’re much too useful not to know how to use :laughing: