【问题标题】:noisy gradient in p5.jsp5.j​​s 中的嘈杂渐变
【发布时间】:2020-05-02 19:33:38
【问题描述】:

目标

插图和其他图形作品中常见的效果是两种颜色之间的渐变,带有颗粒/噪点,因此可以获得非常特殊的效果。 (尤其是示例 3。)

我的研究已经展示了许多解决方案如何在 Illustrator 等软件中实现这种效果,但我想用 p5js 或 vanilla js 画布重新创建它。

(来源:https://medium.com/@stefanhrlemann/how-to-create-noisy-risograph-style-gradients-and-textures-in-photoshop-in-3-ways-394d6012a93a

我的尝试

我已经尝试创建渐变并使用其顶部的像素阵列设置具有特定颜色的随机噪声。 这只是部分地导致了预期的效果:

function draw() {
    setGradient(0, 0, width, height, color(0, 0, 0), color(255, 255 ,255));
    setNoise();
}

function setNoise() {
    loadPixels();
    for (let x = 0; x < width; x++ ) {
        for (let y = 0; y < height; y++ ) {
            if (random(1) > 0.9) {
                const index = (x + y * width) * 4;
                pixels[index] = 255;
                pixels[index + 1] = 255;
                pixels[index + 2] = 255;
                pixels[index + 3] = 255;
            }
        }
    }
    updatePixels();
}

function setGradient(x, y, w, h, c1, c2) {
    noFill();
    for (let i = y; i <= y + h; i++) {
        let inter = map(i, y, y + h, 0, 1);
        let c = lerpColor(c1, c2, inter);
        stroke(c);
        line(x, i, x + w, i);
    }
}

你怎么看?这是正确的方法还是有更好/更简单的解决方案?

【问题讨论】:

    标签: javascript canvas gradient p5.js


    【解决方案1】:

    您需要将噪声与渐变混合。您不能直接混合 ImageData,您需要先将其转换为位图(将其放在画布上即可)。因此,您可能更喜欢 hard-light ,而不是 overlay,它会颠倒我们的图层顺序。

    const w = 300;
    const h = 300;
    const canvas = document.getElementById( 'canvas' );
    const ctx = canvas.getContext( '2d' );
    // some colored noise
    const data = Uint32Array.from( {length: w*h }, () => Math.random() * 0xFFFFFFFF );
    const img = new ImageData( new Uint8ClampedArray( data.buffer ), w, h );
    
    ctx.putImageData( img, 0, 0 );
    // first pass to convert our noise to black and transparent
    ctx.globalCompositeOperation = "color";
    ctx.fillRect( 0, 0, w, h );
    
    ctx.globalCompositeOperation = "hard-light";
    ctx.fillStyle = ctx.createLinearGradient( 0, 0, 0, h );
    ctx.fillStyle.addColorStop( 0.1, 'white' );
    ctx.fillStyle.addColorStop( 0.9, 'black' );
    ctx.fillRect( 0, 0, w, h );
    canvas { background: lime; }
    &lt;canvas id="canvas" height="300"&gt;&lt;/canvas&gt;

    但是混合需要你有一个不透明的场景。如果你想有透明度,那么你也必须使用合成:

    const w = 300;
    const h = 300;
    const canvas = document.getElementById( 'canvas' );
    const ctx = canvas.getContext( '2d' );
    // some black and transparent noise
    const data = Uint32Array.from( {length: w*h }, () => Math.random() > 0.5 ? 0xFF000000 : 0 );
    const img = new ImageData( new Uint8ClampedArray( data.buffer ), w, h );
    
    ctx.putImageData( img, 0, 0 );
    
    ctx.fillStyle = ctx.createLinearGradient( 0, 0, 0, h );
    ctx.fillStyle.addColorStop( 0.1, 'transparent' );
    ctx.fillStyle.addColorStop( 0.9, 'black' );
    // apply transparency gradient on noise (dim top)
    ctx.globalCompositeOperation = "destination-in";
    ctx.fillRect( 0, 0, w, h );
    // apply black of the gradient on noise (darken bottom)
    ctx.globalCompositeOperation = "multiply";
    ctx.fillRect( 0, 0, w, h ); 
    
    // optionally change the color of the noise
    ctx.globalCompositeOperation = "source-atop";
    ctx.fillStyle = "red";
    ctx.fillRect( 0, 0, w, h );
    canvas { background: lime; }
    &lt;canvas id="canvas" height="300"&gt;&lt;/canvas&gt;

    【讨论】:

    • 这正是我想要的。独自一人,我永远不会想出这个解决方案。非常感谢。
    猜你喜欢
    • 1970-01-01
    • 2014-11-24
    • 2021-12-14
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2021-03-24
    • 1970-01-01
    相关资源
    最近更新 更多