画布-在图像上创建随机薄片

时间:2020-08-12 11:08:05

标签: javascript canvas

任何人都可以给我一个提示,告诉我如何使用javascript创建类似的东西:

flakes

要求是我可以设置薄片的密度。并添加多达5种不同的颜色。

我确实知道如何创建画布并在其中放置像素,但是我不知道如何创建“薄片”。

有没有办法创建这样的随机形状?

2 个答案:

答案 0 :(得分:3)

您可以细分简单的形状并在任意点绘制它。

下面的示例将创建一个3边的点,将其随机测试到大约2像素的细节级别,然后将其添加到路径。

然后用一种颜色填充路径,并添加另一组形状。

function testate(amp, points) {
    const p = [];
    var i = points.length - 2, x1, y1, x2, y2;
    p.push(x1 = points[i++]);
    p.push(y1 = points[i]);
    i = 0;
    while (i < points.length) {
        x2 = points[i++];
        y2 = points[i++];
        const dx = x2 - x1;
        const dy = y2 - y1;
        const r = (Math.random() - 0.5) * 2 * amp;
        p.push(x1 + dx / 2 - dy * r);
        p.push(y1 + dy / 2 + dx * r);
        p.push(x1 = x2);
        p.push(y1 = y2);
    }
    return p;
}

function drawFlake(ctx, size, x, y, noise) {
    const a = Math.random() * Math.PI;
    var points = [];
    const step = Math.PI * (2/3);
    var i = 0;
    while (i < 3) {
        const r = (Math.random() * size + size) / 2;
        points.push(Math.cos(a + i * step) * r);
        points.push(Math.sin(a + i * step) * r);
        i++;
    }
    while (size > 2) {
        points =  testate(noise, points);
        size >>= 1;
    }
    i = 0;
    ctx.setTransform(1,0,0,1,x,y);
    ctx.moveTo(points[i++], points[i++]);
    while (i < points.length) {
        ctx.lineTo(points[i++], points[i++]);
    }
}
function drawRandomFlakes(ctx, count, col, min, max, noise) {
    ctx.fillStyle = col;
    ctx.beginPath();
    while (count-- > 0) {
        const x = Math.random() * ctx.canvas.width;
        const y = Math.random() * ctx.canvas.height;
        const size = min + Math.random() * (max- min);
        drawFlake(ctx, size, x, y, noise);
    }
    ctx.fill();
}

const ctx = canvas.getContext("2d");
canvas.addEventListener("click",drawFlakes);
drawFlakes();
function drawFlakes(){ 
    ctx.setTransform(1,0,0,1,0,0);
    ctx.fillStyle = "#341";
    ctx.fillRect(0, 0, ctx.canvas.width, ctx.canvas.height)
    const noise = Math.random() * 0.3 + 0.3;
    drawRandomFlakes(ctx, 500, "#572", 5, 10, noise)
    drawRandomFlakes(ctx, 200, "#421", 10, 15, noise)
    drawRandomFlakes(ctx, 25, "#257", 15, 30, noise)
}
body { background: #341 }
div {
   position: absolute;
   top: 20px;
   left: 20px;
   color: white;
}   
<canvas id="canvas" width = "600" height = "512"></canvas>
<div>Click to redraw</div>

答案 1 :(得分:2)

您将需要某种噪声算法。

在此示例中,我使用了Perlin noise,但是您可以使用任何适合您的噪声算法。通过使用Perlin噪声,我们可以将blob定义为噪声值高于某个阈值的区域。

我使用了一个发现的库{strong> ,并将代码基于示例代码。压缩后的代码只是其中的一小部分(我剪下了simplex和perlin 3D)。

here

您可以通过更改以下参数来进行调整

Math.abs(noise.perlin2(x / 25, y / 25))

25更改为较高的值将放大,将if (value > 0.4){更改为较小的值

0.4

!function(n){var t=n.noise={};function e(n,t,e){this.x=n,this.y=t,this.z=e}e.prototype.dot2=function(n,t){return this.x*n+this.y*t},e.prototype.dot3=function(n,t,e){return this.x*n+this.y*t+this.z*e};var r=[new e(1,1,0),new e(-1,1,0),new e(1,-1,0),new e(-1,-1,0),new e(1,0,1),new e(-1,0,1),new e(1,0,-1),new e(-1,0,-1),new e(0,1,1),new e(0,-1,1),new e(0,1,-1),new e(0,-1,-1)],o=[151,160,137,91,90,15,131,13,201,95,96,53,194,233,7,225,140,36,103,30,69,142,8,99,37,240,21,10,23,190,6,148,247,120,234,75,0,26,197,62,94,252,219,203,117,35,11,32,57,177,33,88,237,149,56,87,174,20,125,136,171,168,68,175,74,165,71,134,139,48,27,166,77,146,158,231,83,111,229,122,60,211,133,230,220,105,92,41,55,46,245,40,244,102,143,54,65,25,63,161,1,216,80,73,209,76,132,187,208,89,18,169,200,196,135,130,116,188,159,86,164,100,109,198,173,186,3,64,52,217,226,250,124,123,5,202,38,147,118,126,255,82,85,212,207,206,59,227,47,16,58,17,182,189,28,42,223,183,170,213,119,248,152,2,44,154,163,70,221,153,101,155,167,43,172,9,129,22,39,253,19,98,108,110,79,113,224,232,178,185,112,104,218,246,97,228,251,34,242,193,238,210,144,12,191,179,162,241,81,51,145,235,249,14,239,107,49,192,214,31,181,199,106,157,184,84,204,176,115,121,50,45,127,4,150,254,138,236,205,93,222,114,67,29,24,72,243,141,128,195,78,66,215,61,156,180],i=new Array(512),w=new Array(512);function u(n){return n*n*n*(n*(6*n-15)+10)}function f(n,t,e){return(1-e)*n+e*t}t.seed=function(n){n>0&&n<1&&(n*=65536),(n=Math.floor(n))<256&&(n|=n<<8);for(var t=0;t<256;t++){var e;e=1&t?o[t]^255&n:o[t]^n>>8&255,i[t]=i[t+256]=e,w[t]=w[t+256]=r[e%12]}},t.seed(0),t.perlin2=function(n,t){var e=Math.floor(n),r=Math.floor(t);n-=e,t-=r;var o=w[(e&=255)+i[r&=255]].dot2(n,t),h=w[e+i[r+1]].dot2(n,t-1),s=w[e+1+i[r]].dot2(n-1,t),a=w[e+1+i[r+1]].dot2(n-1,t-1),c=u(n);return f(f(o,s,c),f(h,a,c),u(t))}}(this); const c = document.getElementById("canvas"); const cc = c.getContext("2d"); noise.seed(Math.random()); let image = cc.createImageData(canvas.width, canvas.height); let data = image.data; for (let x = 0; x < c.width; x++){ for (let y = 0; y < c.height; y++){ const value = Math.abs(noise.perlin2(x / 25, y / 25)); const cell = (x + y * c.width) * 4; if (value > 0.4){ data[cell] = 256; data[cell + 1] = 0; data[cell + 2] = 0; data[cell + 3] = 256; } else { data[cell] = 0; data[cell + 1] = 0; data[cell + 2] = 0; data[cell + 3] = 0; } } } cc.putImageData(image, 0, 0);更改为较小的值会增加blob的大小,而将其增大则会减小blob的大小。

<canvas id="canvas" width=500 height=500></canvas>
?.