Gradient interpolation with 3+ points

We have a n x n canvas and m (say 3) points in it. The m points/nodes all have different fixed RGB colors. The color of each dot in n x n is defined by the distance from any of the color nodes. So each dot is a mixture (gradient) of the m nodes, ruled by the distance from the node.

How can you do this efficiently in processing, given that n and m can be large?

I implemented an n-point shader for OPENRNDR (a different framework). Maybe that approach is efficient enough? If you can read GLSL you might understand the code at orx/NPointGradient.kt at master · openrndr/orx · GitHub and port it to Processing.
Basically it’s passing an array of positions and array of colors, then using them to calculate the colors of every pixel. The built in uniforms for the shader are listed here.

It is fast enough for real time animation.

2 Likes

Ok here is my version, the rect() bit is probably not the best, also it doesn’t look at smooth as I expected.

PVector[] points = new PVector[4];
PVector[] cols = new PVector[4];

void setup() {
	size(200, 200);
	background(100);
	frameRate(1);
	noLoop();
  points[0] = new PVector(50, 50);
  points[1] = new PVector(20, 20);
  points[2] = new PVector(80, 60);
  points[3] = new PVector(120, 120);
  cols[0] = new PVector(255, 100, 100);
  cols[1] = new PVector(200, 255, 100);
  cols[2] = new PVector(0, 100, 200);								
  cols[3] = new PVector(50, 0, 200);                
}

void draw() {
	// ellipse(mouseX, mouseY, 20, 20);
	for (int x = 0; x < width; x += 1) {
		for (int y = 0; y < height; y += 1) {
			PVector rgb = new PVector(0, 0, 0);
			float d_total = 0;
			for (int i = 0; i < points.length; i++) {
				// weight by inverse distance, avoid div by 0
				float d = 100 / (dist(x, y, points[i].x, points[i].y) + random(-0.001, .001));
        PVector incr = PVector.mult(cols[i], d);
        // rgb.add(cols[i]);
				rgb.add(incr);
				d_total += d;
			}
			rgb.div(d_total);
      // rgb.div(points.length);
      noStroke();
			fill(rgb.x, rgb.y, rgb.z);
			rect(x, y, 1, 1);
		}
	}
       filter(BLUR, 5);
}

Correction, it should be float d_total

Great that you got it working! :slight_smile:

btw. you can edit your post to make the int a float with the little pen icon.

And I would say if you use the pixels array it would be faster than with rect. pixels[] / Reference / Processing.org

Even faster would be to use GLSL shaders but that’s a whole different language and not ideal if you don’t know it already. The reason it would be faster is because it would calculate the pixel colors in parallel instead of sequentially. Also only important if you want to do it animated in real time. If the goal is to save an image it doesn’t matter that much.

Cheers!

Thanks, I also added filter(BLUR) now.

Related: