Triangle
There is a concept of barycentric coordinates in triangle. Given that A, B and C are points spanning the triangle, every point inside the triangle can be expressed by an equation:
t * A + s * B + p * C
Where 0 <= t, s, p <= 1
and t + s + p = 1
. You can evaluate t, s and p and treat them as weights for colors defined for respective triangle vertices, easily evaluating target color for every rendered point.
Note however, that effects of this algorithm looks nice only for triangles. If you think about stiching triangles together and using this method to evaluate colors, you'll end up with triangular gradient pattern, which you probably want to avoid.
Random set of points
For more random set of points, I'm using the following algorithm:
Given point (x, y), for which I want to calculate the color, and set of points (x1, y1, color1), (x2, y2, color2), ..., (xN, yN, colorN):
- Calculate distances to all points (x1, y1), ... (xN, yN)
- Calculate value of Gaussian function for every point:
- Calculate weighted average of color, based on those weights.
Implementation looks more less like this:
private float Gauss(float x, float a, float b, float c)
{
var v1 = (x - b) / (2d * c * c);
var v2 = -v1 * v1 / 2d;
var v3 = (float)(a * Math.Exp(v2));
return v3;
}
private float GetWeight(float distance) => Gauss(distance, Peak, 0, Falloff);
public override Color GetColor(PointF p)
{
float[] distances = Points
.Select(pt => (pt.AsVector2 - p.ToVector2()).Length())
.ToArray();
float r = 0, g = 0, b = 0, sum = 0;
for (int i = 0; i < Points.Length; i++)
{
var weight = GetWeight(distances[i]);
r += Points[i].Color.R * weight;
g += Points[i].Color.G * weight;
b += Points[i].Color.B * weight;
sum += weight;
}
int targetR = Math.Max(0, Math.Min(255, (int)(r / sum)));
int targetG = Math.Max(0, Math.Min(255, (int)(g / sum)));
int targetB = Math.Max(0, Math.Min(255, (int)(b / sum)));
return Color.FromArgb(targetR, targetG, targetB);
}
The problem is that you need to pick Peak
and Falloff
values, so that they will satisfy your needs. Peak defines value of weight at distance 0 (so where you are exactly over one of defined points) and Falloff defines, how quickly the weight dissipates towards 0 (it never reaches it though).
For instance, Peak of 100, Falloff of 5 for image 256x256:

Peak of 100, Falloff of 7:
:
Peak of 100, Falloff of 9:

Notes
My proposed solution is unfortunately more of a workaround than a real solution, because it relies heavily on picking proper Peak and Falloff values. Generally you are seeking for a 2D function, which behaves in the following way:
- At defined point X it has (exact) value of X's color
- The farther you go from point X, the less it influences the final color and the more other points do.
My solution fulfills the second requirement, but does not fulfill the first one (color is near X's color, but not neccesarily equal).