HTML5 canvas 三角形每个顶点的梯度

Gradients at each vertex of a triangle with HTML5 canvas

如果给定每个顶点的颜色,如何使用从顶点开始的渐变填充三角形?

我正在尝试重现这样的东西:

我正在使用 HTML5 canvas Context2D 中的内置 fill 函数。我试图避免根据它们到顶点的距离来处理逐像素插值。我担心它不会像内置的 fill 函数 (?) 那样高效。另外,我现在无法处理 WebGL。

我已经使用径向渐变技巧,但是,我的天真方法存在一些问题:

OBS:我不知道它是否相关,但我正在构建一个三角形带(实际上是索引几何)。

var canvas = document.querySelector("canvas");

var ctx = canvas.getContext("2d");

var v1 = { x: 100, y: 0 };
var v2 = { x: 0, y: 180 };
var v3 = { x: 200, y: 180 };

var radius = 175;

var grd1 = ctx.createRadialGradient(v1.x, v1.y, 0, v1.x, v1.y, radius);
grd1.addColorStop(0, "#FF0000FF");
grd1.addColorStop(1, "#FF000000");

var grd2 = ctx.createRadialGradient(v2.x, v2.y, 0, v2.x, v2.y, radius);
grd2.addColorStop(0, "#00FF00FF");
grd2.addColorStop(1, "#00FF0000");

var grd3 = ctx.createRadialGradient(v3.x, v3.y, 0, v3.x, v3.y, radius);
grd3.addColorStop(0, "#0000FFFF");
grd3.addColorStop(1, "#0000FF00");

ctx.beginPath();

ctx.moveTo(v1.x, v1.y);
ctx.lineTo(v2.x, v2.y);
ctx.lineTo(v3.x, v3.y);

ctx.closePath();

ctx.fillStyle = "#FFFFFFFF"; // fill with white and apply the gradients on top of it
ctx.fill();

ctx.fillStyle = grd1;
ctx.fill();

ctx.fillStyle = grd2;
ctx.fill();

ctx.fillStyle = grd3;
ctx.fill();
<canvas width="200" height="180"></canvas>

  • The colors don't seem to blend well

为此,您可以将 2D 上下文的 globalCompositeOperation 属性 用于其中一种混合模式,即使在您的情况下,带有黑色背景的合成模式 "lighter" 似乎以产生最接近您的模型的结果。

  • The last applied gradient overwrites the others

多亏了前面的要点,现在已经不是这样了。

  • The value used in the radius variable is arbitrary

在我看来不是这样,它确实对应于等边三角形的每个点与其中心之间的距离,这非常合理。

var canvas = document.querySelector("canvas");

var ctx = canvas.getContext("2d");

// reordered to make the same as OP's image
var v1 = { x: 0, y: 180 };
var v2 = { x: 200, y: 180 };
var v3 = { x: 100, y: 0 };

var radius = 180;

var grd1 = ctx.createRadialGradient(v1.x, v1.y, 0, v1.x, v1.y, radius);
grd1.addColorStop(0, "#FF0000FF");
grd1.addColorStop(1, "#FF000000");

var grd2 = ctx.createRadialGradient(v2.x, v2.y, 0, v2.x, v2.y, radius);
grd2.addColorStop(0, "#00FF00FF");
grd2.addColorStop(1, "#00FF0000");

var grd3 = ctx.createRadialGradient(v3.x, v3.y, 0, v3.x, v3.y, radius);
grd3.addColorStop(0, "#0000FFFF");
grd3.addColorStop(1, "#0000FF00");

ctx.beginPath();

ctx.moveTo(v1.x, v1.y);
ctx.lineTo(v2.x, v2.y);
ctx.lineTo(v3.x, v3.y);

ctx.closePath();

// fill with black
ctx.fill();

// set blend mode
ctx.globalCompositeOperation = "lighter";

ctx.fillStyle = grd1;
ctx.fill();

ctx.fillStyle = grd2;
ctx.fill();

ctx.fillStyle = grd3;
ctx.fill();

// if you need to draw something else, don't forget to reset the gCO
ctx.globalCompositeOperation = "source-over";
<canvas width="200" height="180"></canvas>