HTML5 canvas 三角形每个顶点的梯度
Gradients at each vertex of a triangle with HTML5 canvas
如果给定每个顶点的颜色,如何使用从顶点开始的渐变填充三角形?
我正在尝试重现这样的东西:
我正在使用 HTML5 canvas Context2D 中的内置 fill
函数。我试图避免根据它们到顶点的距离来处理逐像素插值。我担心它不会像内置的 fill
函数 (?) 那样高效。另外,我现在无法处理 WebGL。
我已经使用径向渐变技巧,但是,我的天真方法存在一些问题:
- 颜色似乎不太协调
- 最后应用的渐变会覆盖其他渐变
radius
变量中使用的值是任意的
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>
如果给定每个顶点的颜色,如何使用从顶点开始的渐变填充三角形?
我正在尝试重现这样的东西:
我正在使用 HTML5 canvas Context2D 中的内置 fill
函数。我试图避免根据它们到顶点的距离来处理逐像素插值。我担心它不会像内置的 fill
函数 (?) 那样高效。另外,我现在无法处理 WebGL。
我已经使用径向渐变技巧,但是,我的天真方法存在一些问题:
- 颜色似乎不太协调
- 最后应用的渐变会覆盖其他渐变
radius
变量中使用的值是任意的
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>