绘图软刷
Drawing soft brush
我正在尝试在 HTML5 中创建平滑画笔,示例如下。
这是我试过的,有点东西。但是没有上图那么流畅
Editor.Drawing.Context.globalAlpha = 0.3;
var amount = 3;
for(var t = -amount; t <= amount; t += 3) {
for(var n = -amount; n <= amount; n += 3) {
Editor.Drawing.Context.drawImage(Editor.Drawing.ClipCanvas, -(n-1), -(t-1));
}
}
看起来像这样。
使用画笔
选择一个画笔,这可以是带有预定义画笔的图像,或者您可以使用屏幕外 canvas 制作一个画笔并在其中绘制径向渐变。为了简单起见,我制作了一个简单的图像画笔,如下所示:
然后对于绘制到 canvas 的每个新点:
- 计算前一个点和当前点之间的差异
- 计算线的长度,这样我们就可以使用与长度无关的绝对步长值
- 使用归一化值和先前计算的步长值迭代长度
步长值可以是任何看起来不错的结果 - 它在很大程度上取决于画笔的平滑度及其一般大小(更平滑的画笔需要更小的步长才能相互融合)。
对于这个演示,我使用了 brush-width,使用的值越小,沿线绘制的画笔越多,效果越好,但也会减慢程序速度,所以找到一个妥协质量和速度。
例如:
每次绘制时注册一个新点都会调用这个:
function brushLine(ctx, x1, y1, x2, y2) {
var diffX = Math.abs(x2 - x1), // calc diffs
diffY = Math.abs(y2 - y1),
dist = Math.sqrt(diffX * diffX + diffY * diffY), // find length
step = 20 / (dist ? dist : 1), // "resolution"
i = 0, // iterator for length
t = 0, // t [0, 1]
b, x, y;
while (i <= dist) {
t = Math.max(0, Math.min(1, i / dist));
x = x1 + (x2 - x1) * t;
y = y1 + (y2 - y1) * t;
b = (Math.random() * 3) | 0;
ctx.drawImage(brush, x - bw * 0.5, y - bh * 0.5); // draw brush
i += step;
}
}
演示
var brush = new Image();
brush.onload = ready;
brush.src = "//i.stack.imgur.com/HsbVA.png";
function ready() {
var c = document.querySelector("canvas"),
ctx = c.getContext("2d"),
isDown = false, px, py,
bw = this.width, bh = this.height;
c.onmousedown = c.ontouchstart = function(e) {
isDown = true;
var pos = getPos(e);
px = pos.x;
py = pos.y;
};
window.onmousemove = window.ontouchmove = function(e) {
if (isDown) draw(e);
};
window.onmouseup = window.ontouchend = function(e) {
e.preventDefault();
isDown = false
};
function getPos(e) {
e.preventDefault();
if (e.touches) e = e.touches[0];
var r = c.getBoundingClientRect();
return {
x: e.clientX - r.left,
y: e.clientY - r.top
}
}
function draw(e) {
var pos = getPos(e);
brushLine(ctx, px, py, pos.x, pos.y);
px = pos.x;
py = pos.y;
}
function brushLine(ctx, x1, y1, x2, y2) {
var diffX = Math.abs(x2 - x1),
diffY = Math.abs(y2 - y1),
dist = Math.sqrt(diffX * diffX + diffY * diffY),
step = bw / (dist ? dist : 1),
i = 0,
t = 0,
b, x, y;
while (i <= dist) {
t = Math.max(0, Math.min(1, i / dist));
x = x1 + (x2 - x1) * t;
y = y1 + (y2 - y1) * t;
b = (Math.random() * 3) | 0;
ctx.drawImage(brush, x - bw * 0.5, y - bh * 0.5);
i += step
}
}
}
body {background: #777}
canvas {background: #fff;cursor:crosshair}
<canvas width=630 height=500></canvas>
您可以使用此技术来模拟各种画笔。
提示:稍作修改,您还可以根据速度改变宽度以增加真实感(未显示)。
我正在尝试在 HTML5 中创建平滑画笔,示例如下。
这是我试过的,有点东西。但是没有上图那么流畅
Editor.Drawing.Context.globalAlpha = 0.3;
var amount = 3;
for(var t = -amount; t <= amount; t += 3) {
for(var n = -amount; n <= amount; n += 3) {
Editor.Drawing.Context.drawImage(Editor.Drawing.ClipCanvas, -(n-1), -(t-1));
}
}
看起来像这样。
使用画笔
选择一个画笔,这可以是带有预定义画笔的图像,或者您可以使用屏幕外 canvas 制作一个画笔并在其中绘制径向渐变。为了简单起见,我制作了一个简单的图像画笔,如下所示:
然后对于绘制到 canvas 的每个新点:
- 计算前一个点和当前点之间的差异
- 计算线的长度,这样我们就可以使用与长度无关的绝对步长值
- 使用归一化值和先前计算的步长值迭代长度
步长值可以是任何看起来不错的结果 - 它在很大程度上取决于画笔的平滑度及其一般大小(更平滑的画笔需要更小的步长才能相互融合)。
对于这个演示,我使用了 brush-width,使用的值越小,沿线绘制的画笔越多,效果越好,但也会减慢程序速度,所以找到一个妥协质量和速度。
例如:
每次绘制时注册一个新点都会调用这个:
function brushLine(ctx, x1, y1, x2, y2) {
var diffX = Math.abs(x2 - x1), // calc diffs
diffY = Math.abs(y2 - y1),
dist = Math.sqrt(diffX * diffX + diffY * diffY), // find length
step = 20 / (dist ? dist : 1), // "resolution"
i = 0, // iterator for length
t = 0, // t [0, 1]
b, x, y;
while (i <= dist) {
t = Math.max(0, Math.min(1, i / dist));
x = x1 + (x2 - x1) * t;
y = y1 + (y2 - y1) * t;
b = (Math.random() * 3) | 0;
ctx.drawImage(brush, x - bw * 0.5, y - bh * 0.5); // draw brush
i += step;
}
}
演示
var brush = new Image();
brush.onload = ready;
brush.src = "//i.stack.imgur.com/HsbVA.png";
function ready() {
var c = document.querySelector("canvas"),
ctx = c.getContext("2d"),
isDown = false, px, py,
bw = this.width, bh = this.height;
c.onmousedown = c.ontouchstart = function(e) {
isDown = true;
var pos = getPos(e);
px = pos.x;
py = pos.y;
};
window.onmousemove = window.ontouchmove = function(e) {
if (isDown) draw(e);
};
window.onmouseup = window.ontouchend = function(e) {
e.preventDefault();
isDown = false
};
function getPos(e) {
e.preventDefault();
if (e.touches) e = e.touches[0];
var r = c.getBoundingClientRect();
return {
x: e.clientX - r.left,
y: e.clientY - r.top
}
}
function draw(e) {
var pos = getPos(e);
brushLine(ctx, px, py, pos.x, pos.y);
px = pos.x;
py = pos.y;
}
function brushLine(ctx, x1, y1, x2, y2) {
var diffX = Math.abs(x2 - x1),
diffY = Math.abs(y2 - y1),
dist = Math.sqrt(diffX * diffX + diffY * diffY),
step = bw / (dist ? dist : 1),
i = 0,
t = 0,
b, x, y;
while (i <= dist) {
t = Math.max(0, Math.min(1, i / dist));
x = x1 + (x2 - x1) * t;
y = y1 + (y2 - y1) * t;
b = (Math.random() * 3) | 0;
ctx.drawImage(brush, x - bw * 0.5, y - bh * 0.5);
i += step
}
}
}
body {background: #777}
canvas {background: #fff;cursor:crosshair}
<canvas width=630 height=500></canvas>
您可以使用此技术来模拟各种画笔。
提示:稍作修改,您还可以根据速度改变宽度以增加真实感(未显示)。