马黑黑 发表于 2024-4-17 12:02

canvas画布: 闭合性三次贝塞尔曲线的绘制

本帖最后由 马黑黑 于 2024-4-17 12:08 编辑 <br /><br /><style>
.mama { font: normal 18px/24px sans-serif; }
.mama p { margin: 12px 0; }
.mama sub { font-size: 12px; }
canvas { display: block; margin: 20px auto; border: 1px solid gray; }

.mum { position: relative; margin: 0; padding: 10px; font: normal 16px/20px Consolas, Monaco, 'Andale Mono', 'Ubuntu Mono', monospace; color: black; background: rgba(240, 240, 240,.95); box-shadow: 2px 2px 4px gray; border: thick groove lightblue; border-radius: 6px; }
.mum ::selection { background-color: rgba(0,100,100,.35); }
.mum div { margin: 0; padding: 0; }
.mum cl-cd { display: block; position: relative; margin: 0 0 0 50px; padding: 0 0 0 10px; white-space: pre-wrap; overflow-wrap: break-word; border-left: 1px solid silver; }
.mum cl-cd::before { position: absolute; content: attr(data-idx); width: 50px; color: gray; text-align: right; transform: translate(-70px); }
.tRed { color: red; }
.tBlue { color: blue; }
.tGreen { color: green; }
.tDarkRed { color: darkred; }
.tMagenta { color: magenta; }
</style>

<div class="mama">

<p>三次贝塞尔曲线可以自闭合,只需设置曲线的起点坐标和终点坐标重合在一起。假设曲线起始点为 P<sub>0</sub>(100, 190),则曲线终点 P<sub>3</sub> 亦为 (100, 190),这在canvas画布上我们将如此操作(画笔标识为 ctx):</p>

<div class='mum'>
<cl-cd data-idx="1">ctx.moveTo(<span class="tRed">100, 190</span>);</cl-cd>
<cl-cd data-idx="2">ctx.bezierCurveTo(cpx1, cpy1, cpx2, cyp2, <span class="tRed">100, 190</span>);</cl-cd>
</div>

<p>这里,我们先将画笔移到(100, 190)坐标处,表示曲线的起点从该处画起,并设定曲线的终点为(100,190),表示曲线画回了起点处。剩下的工作就是设置两个控制点坐标:P<sub>1</sub>(cpx1, cpy1) 和 P<sub>2</sub>(cpx2, cpy2)。之前我们在相关文章中谈到贝塞尔曲线的曲线外观会受控制点的直接影响,所以设置 P<sub>1</sub> 和 P<sub>2</sub> 在这里大有学问。本文以绘制多叶草的一张叶子为设计目标,同时出于简化目的,仅通过Y方向的控制点来控制叶子的长度、通过控制点的X方向来控制叶子的厚度。我们的画布是 200 * 200 的尺寸,上面,我们已经将叶片的底端定位在了 (100, 190) 坐标处,也就是靠近画布底部的中央,那么,叶片该是往上长的,所以,Y方向的两个控制点我们都设为 -50,以便让叶片往上方拉扯到靠边画布的顶边。X方向控制点要左右对称,两个点以画布水平方向的中心为界,若第一个点为0,则第二个点为画布的宽度,若第一个点是 50,则第二个点是画布宽度减去50,依此类推。如此,P<sub>1</sub> 和 P<sub>2</sub> 我们可以这么确定下来:</p>
<blockquote>P<sub>1</sub>(<span class="tRed">-60,-50</span>)<br>P<sub>2</sub>(<span class="tRed">260,-50</span>)</blockquote>
<p>控制点1、控制点2Y方向的坐标值一样,都是 -50;X方向则应是对称的:点1是 -60,那么,点2为画布宽度减去 - 60 等于 260。最终,画布的绘制操作代码如下:</p>

<div class='mum'>
<cl-cd data-idx="1"><span class="tBlue">let</span> ctx = canv.getContext(<span class="tMagenta">'2d'</span>);</cl-cd>
<cl-cd data-idx="2">ctx.fillStyle = ctx.strokeStyle = <span class="tMagenta">'green'</span>;</cl-cd>
<cl-cd data-idx="3">ctx.beginPath();</cl-cd>
<cl-cd data-idx="4">ctx.moveTo(100, 190); <span class="tGreen">//曲线出发点</span></cl-cd>
<div class="tGreen"><cl-cd data-idx="5">/* 三次贝塞尔曲线参数说明</cl-cd>
<cl-cd data-idx="6">   cpx1, cpy1, cpx2, cpy2, xEnd, yEnd</cl-cd>
<cl-cd data-idx="7">&nbsp;</cl-cd>
<cl-cd data-idx="8">   cpx1 - 控制点1X坐标</cl-cd>
<cl-cd data-idx="9">   cpy1 - 控制点1Y坐标</cl-cd>
<cl-cd data-idx="10">   cpx2 - 控制点2X坐标</cl-cd>
<cl-cd data-idx="11">   cpy2 - 控制点2Y坐标</cl-cd>
<cl-cd data-idx="12">   xEnd - 曲线终点X坐标</cl-cd>
<cl-cd data-idx="13">   yEnd - 曲线终点Y坐标</cl-cd>
<cl-cd data-idx="14">*/</cl-cd></div>
<cl-cd data-idx="15">ctx.bezierCurveTo(-60, -50, 260, -50, 100, 190);</cl-cd>
<cl-cd data-idx="16">ctx.fill();</cl-cd>
<cl-cd data-idx="17">ctx.closePath();</cl-cd>
</div>
<p>效果:</p>
<canvas id="canv" width="200" height="200"></canvas>
<p>这就是仅用一根闭合性曲线绘制出来的效果。如果我们让多根曲线按一定规律拼合在一起,那就是多叶草了。以下页面是使用上述绘制原理编写出来的原创工具,所绘制的多叶草可以右击→图片另存为保存下来,图片尺寸为 400*400,使用时可以通过设置宽高改变图片的大小:</p>
<p><a href="http://mhh.52qingyin.cn/art/show.php?st=5&sd=5&art=mahei_1713321644" target="_blank">canvas画布绘制多叶草</a></p>

</div>

<script>
let ctx = canv.getContext('2d');
ctx.fillStyle = ctx.strokeStyle = 'green';
ctx.beginPath();
ctx.moveTo(100, 190);
ctx.bezierCurveTo(-60, -50, 260, -50, 100, 190);
ctx.fill();
ctx.closePath();
</script>

马黑黑 发表于 2024-4-17 13:15

下面的图片是多叶草绘制工具画的:

https://638183.freep.cn/638183/t24/leaf/16l.png

红影 发表于 2024-4-17 15:00

黑黑把那个在线绘制也发来啊,真的太美了{:4_199:}

红影 发表于 2024-4-17 15:03

在你那里玩了好半天,每一个调配出来都那么惊艳的,太棒了{:4_199:}

红影 发表于 2024-4-17 15:08

看看,我随手配了个

https://pic.imgdb.cn/item/661f75470ea9cb1403fb13a9.png

红影 发表于 2024-4-17 15:10

叶瓣多点少点,厚点薄点都那么好看的,简直让人爱不释手{:4_199:}

樵歌 发表于 2024-4-17 16:03

看样子很美的。

小辣椒 发表于 2024-4-17 17:58

漂亮,透明的特别诱惑{:4_172:}
好喜欢这个效果

小辣椒 发表于 2024-4-17 17:59

先上来瞄一眼,晚上再见

南无月 发表于 2024-4-17 18:18

马黑黑 发表于 2024-4-17 13:15
下面的图片是多叶草绘制工具画的:

早上看到就感觉惊艳。。。
想说能电脑的时候发张图上来。
老师这就发了。。
这个配色太漂亮了。。{:4_199:}

南无月 发表于 2024-4-17 18:20

https://642303.freep.cn/642303/za/99.png

南无月 发表于 2024-4-17 18:21

厚度拉到最大,可以有好多层。。。。这个按纽工具超级优秀。。

南无月 发表于 2024-4-17 18:22

透明度0.2或者0.3比较容易看出重叠层瓣效果。。11楼透明度0.15

马黑黑 发表于 2024-4-17 19:11

南无月 发表于 2024-4-17 18:22
透明度0.2或者0.3比较容易看出重叠层瓣效果。。11楼透明度0.15

经验丰富{:4_199:}

马黑黑 发表于 2024-4-17 19:12

红影 发表于 2024-4-17 15:00
黑黑把那个在线绘制也发来啊,真的太美了

{:4_191:}

马黑黑 发表于 2024-4-17 19:12

红影 发表于 2024-4-17 15:03
在你那里玩了好半天,每一个调配出来都那么惊艳的,太棒了

好玩吧

马黑黑 发表于 2024-4-17 19:12

红影 发表于 2024-4-17 15:08
看看,我随手配了个

{:4_199:}

马黑黑 发表于 2024-4-17 19:12

小辣椒 发表于 2024-4-17 17:58
漂亮,透明的特别诱惑
好喜欢这个效果

{:4_190:}

马黑黑 发表于 2024-4-17 19:13

小辣椒 发表于 2024-4-17 17:59
先上来瞄一眼,晚上再见

{:4_200:}

马黑黑 发表于 2024-4-17 19:13

南无月 发表于 2024-4-17 18:21
厚度拉到最大,可以有好多层。。。。这个按纽工具超级优秀。。

谬赞谬赞
页: [1] 2 3 4 5 6 7 8
查看完整版本: canvas画布: 闭合性三次贝塞尔曲线的绘制