【问题标题】:P5.js: how to programatically calculate BURN blendMode between 2 colors?P5.js:如何以编程方式计算 2 种颜色之间的 BURN 混合模式?
【发布时间】:2022-01-25 18:07:49
【问题描述】:

我正在做一些 blendMode(BURN) 来绘制一些形状。以及其他形状我需要直接用之前形状的结果颜色绘制,所以我需要自己生成混合结果颜色。

我正在寻找类似的东西:

let blendedColor = blendColorsBurn(color1, color2);

【问题讨论】:

    标签: p5.js color-blending


    【解决方案1】:

    没有用于此的内置函数。在 2d 模式下,p5.js 利用画布的 globalCompositeOperation property,当设置为 color-burn 时,执行以下颜色混合操作:

    将反转的底层除以顶层,然后将结果反转。

    这听起来很简单,但我想验证它的含义,因此我决定尝试快速测试实现。按 shift 和 control 键分别查看内置的 BURN blendMode 和我的计算。

    let existingContent;
    let newContent;
    
    let manualBurn;
    
    let scaleFactor = 1;
    
    function preload() {
      existingContent = loadImage("https://www.paulwheeler.us/files/existing-content.png");
      newContent = loadImage("https://www.paulwheeler.us/files/new-content.png");
    }
    
    function setup() {
      createCanvas(windowWidth, windowHeight);
      noLoop();
    
      scaleFactor = height / newContent.height;
      manualBurn = createImage(newContent.width, newContent.height);
    
      // Divides the inverted bottom layer by the top layer, and then inverts the result.
      for (let x = 0; x < newContent.width; x++) {
        for (let y = 0; y < newContent.height; y++) {
          const c1 = existingContent.get(x, y);
          const c2 = newContent.get(x, y);
    
          if (alpha(c2) > 0) {
            let a = alpha(c1) / 255;
            // Inverted bottom layer
            let [inv_r, inv_g, inv_b, inv_a] = [
              // Subtracting from alpha instead of 1 is to deal with pre-multiplied alpha
              a - red(c1) / 255,
              a - green(c1) / 255,
              a - blue(c1) / 255,
              1 - alpha(c1) / 255,
            ];
    
            // divided by the top layer
            let [div_r, div_g, div_b, div_a] = [
              inv_r / (red(c2) / 255),
              inv_g / (green(c2) / 255),
              inv_b / (blue(c2) / 255),
              inv_a / (alpha(c2) / 255),
            ];
    
            // inverted
            let out = [255 * (1 - div_r), 255 * (1 - div_g), 255 * (1 - div_b), max(alpha(c2), 255 * (1 - div_a))];
    
            manualBurn.set(x, y, out);
          } else {
            manualBurn.set(x, y, c1);
          }
        }
      }
    
      manualBurn.updatePixels();
    }
    
    function keyPressed() {
      redraw();
    }
    
    function keyReleased() {
      redraw();
    }
    
    function draw() {
      clear();
      scale(scaleFactor);
      if (keyIsDown(CONTROL)) {
        blendMode(BLEND);
        image(manualBurn, 0, 0);
      } else {
        image(
          existingContent,
          0,
          0
        );
        if (keyIsDown(SHIFT)) {
          blendMode(BURN);
          image(newContent, 0, 0);
        }
      }
    }
    html, body {
      margin: 0;
      padding: 0;
    }
    body {
      background-image: url("https://www.paulwheeler.us/files/checkerboard.jpeg");
      background-repeat: repeat;
      background-size: 200px;
    }
    canvas {
      display: block;
    }
    &lt;script src="https://cdnjs.cloudflare.com/ajax/libs/p5.js/1.4.0/p5.js"&gt;&lt;/script&gt;

    肯定有一些问题:

    1. 这可能很明显,但这个数学运算必须使用 0 到 1 的值,而不是 0 到 255 的值。
    2. colorMode(RGB, 1, 1, 1, 1) 不起作用,因为 red()green()blue() 函数四舍五入为整数?‍♂️
    3. 在反转颜色时,您需要从 alpha 值而不是 1 开始,因为预乘 alpha。
    4. 从描述中看不出来,但似乎刻录图像 alpha 优先。

    【讨论】:

    • 印象深刻!
    猜你喜欢
    • 2012-04-01
    • 2014-12-15
    • 2017-04-09
    • 1970-01-01
    • 2019-10-31
    • 2012-10-23
    • 2013-08-02
    • 1970-01-01
    相关资源
    最近更新 更多