在 p5.js 中画一条不同宽度的线
Draw a line of varying width in p5.js
我想在我的 canvas 上绘制宽度从头到尾逐渐变化的线条。也就是说,假设该行以 width = 1
开始于 (0, 0)
(相当于 strokeWeight
)并以 (50, 50)
结束于 width = 3
,并且 width
必须(线性)从 1
增加到 3
从开始到结束。
关于如何实现这一点有什么想法吗?无法从网上抓取它。
关键是将线分成例如 30 段。你用递增的 strokeWeight()
绘制每个线段。您拥有的线段越多,线条看起来就越平滑。
您可以使用 lerp()
找到两端点之间的 x,y 坐标。
您可以使用 lerp()
查找两端之间的线 strokeWeight()
。
function setup() {
createCanvas(200, 200);
background("black");
stroke("white");
gradientLine(0, 0, 50, 50, 1, 3, 30);
noLoop();
}
function gradientLine(
start_x,
start_y,
end_x,
end_y,
start_weight,
end_weight,
segments
) {
let prev_loc_x = start_x;
let prev_loc_y = start_y;
for (let i = 1; i <= segments; i++) {
let cur_loc_x = lerp(start_x, end_x, i / segments);
let cur_loc_y = lerp(start_y, end_y, i / segments);
push();
strokeWeight(lerp(start_weight, end_weight, i / segments));
line(prev_loc_x, prev_loc_y, cur_loc_x, cur_loc_y);
pop();
prev_loc_x = cur_loc_x;
prev_loc_y = cur_loc_y;
}
}
<script src="https://cdn.jsdelivr.net/npm/p5@1.0.0/lib/p5.min.js"></script>
编辑:
此外,如果使用 alpha < 255
的颜色,可能会出现这样的伪像:
发生这种情况是因为笔划的默认上限设置为 ROUND
。设置 strokeCap(SQUARE)
将解决此问题:
这需要在gradientLine(...)
函数中的push()...pop()
块中设置。 (注意:这会使线的末端看起来很平,需要更精细的工作。)
您也可以使用 beginShape()
/ endShape()
将线画成“梯形”,并将线的每一端转换成两个单独的点。请参阅下面的代码片段:
function setup() {
createCanvas(400, 400);
noStroke();
fill(220);
}
function draw() {
background(20);
drawVaryingWidthLine(0, 0, 50, 50, 1, 3);
drawVaryingWidthLine(80, 20, 200, 140, 1, 5);
drawVaryingWidthLine(30, 60, 230, 260, 10, 3);
drawVaryingWidthLine(210, 180, 360, 330, 40, 20);
}
function drawVaryingWidthLine(x1, y1, x2, y2, startWidth, endWidth) {
const halfStartWidth = startWidth / 2
const halfEndwidth = endWidth / 2
beginShape();
vertex(x1 + halfStartWidth, y1 - halfStartWidth);
vertex(x2 + halfEndwidth, y2 - halfEndwidth);
vertex(x2 - halfEndwidth, y2 + halfEndwidth);
vertex(x1 - halfStartWidth, y1 + halfStartWidth);
vertex(x1 + halfStartWidth, y1 - halfStartWidth);
endShape();
}
<!DOCTYPE html>
<html lang="en">
<head>
<script src="https://cdnjs.cloudflare.com/ajax/libs/p5.js/0.10.2/p5.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/p5.js/0.10.2/addons/p5.sound.min.js"></script>
<link rel="stylesheet" type="text/css" href="style.css">
<meta charset="utf-8" />
</head>
<body>
<script src="sketch.js"></script>
</body>
</html>
与@ffmaer 的解决方案相比,此解决方案没有任何平滑度/透明度瑕疵。
我认为我的速度稍快一些,因为每条线只绘制一个形状(尽管我还没有测试过)。但是,这里的这个版本目前仅限于原始 post 中要求的角度线(右下角 45 度)。通过调整梯形的角位置,可以很容易地适应任意角度。
编辑:根据@ffmaer 的评论,现在使用梯形而不是三角形。
我想在我的 canvas 上绘制宽度从头到尾逐渐变化的线条。也就是说,假设该行以 width = 1
开始于 (0, 0)
(相当于 strokeWeight
)并以 (50, 50)
结束于 width = 3
,并且 width
必须(线性)从 1
增加到 3
从开始到结束。
关于如何实现这一点有什么想法吗?无法从网上抓取它。
关键是将线分成例如 30 段。你用递增的 strokeWeight()
绘制每个线段。您拥有的线段越多,线条看起来就越平滑。
您可以使用 lerp()
找到两端点之间的 x,y 坐标。
您可以使用 lerp()
查找两端之间的线 strokeWeight()
。
function setup() {
createCanvas(200, 200);
background("black");
stroke("white");
gradientLine(0, 0, 50, 50, 1, 3, 30);
noLoop();
}
function gradientLine(
start_x,
start_y,
end_x,
end_y,
start_weight,
end_weight,
segments
) {
let prev_loc_x = start_x;
let prev_loc_y = start_y;
for (let i = 1; i <= segments; i++) {
let cur_loc_x = lerp(start_x, end_x, i / segments);
let cur_loc_y = lerp(start_y, end_y, i / segments);
push();
strokeWeight(lerp(start_weight, end_weight, i / segments));
line(prev_loc_x, prev_loc_y, cur_loc_x, cur_loc_y);
pop();
prev_loc_x = cur_loc_x;
prev_loc_y = cur_loc_y;
}
}
<script src="https://cdn.jsdelivr.net/npm/p5@1.0.0/lib/p5.min.js"></script>
编辑:
此外,如果使用 alpha < 255
的颜色,可能会出现这样的伪像:
发生这种情况是因为笔划的默认上限设置为 ROUND
。设置 strokeCap(SQUARE)
将解决此问题:
这需要在gradientLine(...)
函数中的push()...pop()
块中设置。 (注意:这会使线的末端看起来很平,需要更精细的工作。)
您也可以使用 beginShape()
/ endShape()
将线画成“梯形”,并将线的每一端转换成两个单独的点。请参阅下面的代码片段:
function setup() {
createCanvas(400, 400);
noStroke();
fill(220);
}
function draw() {
background(20);
drawVaryingWidthLine(0, 0, 50, 50, 1, 3);
drawVaryingWidthLine(80, 20, 200, 140, 1, 5);
drawVaryingWidthLine(30, 60, 230, 260, 10, 3);
drawVaryingWidthLine(210, 180, 360, 330, 40, 20);
}
function drawVaryingWidthLine(x1, y1, x2, y2, startWidth, endWidth) {
const halfStartWidth = startWidth / 2
const halfEndwidth = endWidth / 2
beginShape();
vertex(x1 + halfStartWidth, y1 - halfStartWidth);
vertex(x2 + halfEndwidth, y2 - halfEndwidth);
vertex(x2 - halfEndwidth, y2 + halfEndwidth);
vertex(x1 - halfStartWidth, y1 + halfStartWidth);
vertex(x1 + halfStartWidth, y1 - halfStartWidth);
endShape();
}
<!DOCTYPE html>
<html lang="en">
<head>
<script src="https://cdnjs.cloudflare.com/ajax/libs/p5.js/0.10.2/p5.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/p5.js/0.10.2/addons/p5.sound.min.js"></script>
<link rel="stylesheet" type="text/css" href="style.css">
<meta charset="utf-8" />
</head>
<body>
<script src="sketch.js"></script>
</body>
</html>
与@ffmaer 的解决方案相比,此解决方案没有任何平滑度/透明度瑕疵。 我认为我的速度稍快一些,因为每条线只绘制一个形状(尽管我还没有测试过)。但是,这里的这个版本目前仅限于原始 post 中要求的角度线(右下角 45 度)。通过调整梯形的角位置,可以很容易地适应任意角度。
编辑:根据@ffmaer 的评论,现在使用梯形而不是三角形。