My goal is to create an arbitrary triangle in SVG with one vertex each of red, yellow, and green, and have the fill color be interpolated based on the colors of the vertices.
Very similar to the early RGB triangle tutorials that DirectX, OpenGL, etc. provide:
Mine works well enough with acute triangles:
But not so much with obtuse triangles:
I created the following SVG, with VueJS for data binding:
<svg xmlns="http://www.w3.org/2000/svg" version="1.1" width="800" height="600">
<defs>
<radialGradient id="red" gradientUnits="userSpaceOnUse" :cx="points[0].x" :cy="points[0].y"
:r="radius(points[0], points[1], points[2])">
<stop offset="0%" stop-color="#ff0000ff" />
<stop offset="100%" stop-color="#7fff0000" />
</radialGradient>
<radialGradient id="green" gradientUnits="userSpaceOnUse" :cx="points[1].x" :cy="points[1].y"
:r="radius(points[1], points[0], points[2])">
<stop offset="0%" stop-color="#00ff00ff" />
<stop offset="100%" stop-color="#ff7f0000" />
</radialGradient>
<radialGradient id="yellow" gradientUnits="userSpaceOnUse" :cx="points[2].x" :cy="points[2].y"
:r="radius(points[2], points[0], points[1])">
<stop offset="0%" stop-color="#ffff00ff" />
<stop offset="100%" stop-color="#7f7f0000" />
</radialGradient>
</defs>
<path :d="svgTriangle" fill="url(#red)" />
<path :d="svgTriangle" fill="url(#yellow)" />
<path :d="svgTriangle" fill="url(#green)" />
</svg>
Points are generated randomly within the SVG's 800x600 space:
for (let p = 0; p < 3; p++) {
this.points[p] = {
id: `p${p}`,
x: Math.floor(Math.random() * 800),
y: Math.floor(Math.random() * 600)
};
}
And the radius calculation is based on the length of the line to the midpoint of the other 2 vertices:
radius: function (me, other1, other2) {
const mid = {
x: (other1.x + other2.x) / 2,
y: (other1.y + other2.y) / 2
};
return Math.sqrt(Math.abs(me.x - mid.x) ** 2 + Math.abs(me.y - mid.y) ** 2);
}
I believe the problem is that the yellow and green (which are rendered after the red) have a much longer radius and are basically hiding the red. Linear gradients aren't any better. Since the gradient approach may be flawed, is there a better approach using SVG?
I know this is possible using Canvas/WebGL (example), but can this same thing even be done using SVG, perhaps with blend filters? Or if I want this type of interpolation, will I need to use Canvas/WebGL
Edit: I couldn't quite get the color blending as nice as I wanted in all the edge cases using SVG, so in the end I ended up moving to canvas and WebGL.


