P5.js:如何以编程方式计算两种颜色之间的 BURN 混合模式?
P5.js: how to programatically calculate BURN blendMode between 2 colors?
我正在做一些 blendMode(BURN) 来绘制一些形状。其他形状我需要直接在之前形状的结果颜色中绘制,所以我需要自己生成混合结果颜色。
我正在寻找类似的东西:
let blendedColor = blendColorsBurn(color1, color2);
没有内置函数。在 2d 模式下 p5.js 利用 canvas 的 globalCompositeOperation
property,当设置为 color-burn
时执行以下颜色混合操作:
Divides the inverted bottom layer by the top layer, and then inverts the result.
这听起来很简单,但我想验证它的意思,所以我决定尝试快速测试实现。按 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;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/p5.js/1.4.0/p5.js"></script>
肯定有一些陷阱:
- 这可能很明显,但必须使用 0 到 1 之间的值来完成此数学运算,而不是 0 到 255 之间的值。
colorMode(RGB, 1, 1, 1, 1)
不起作用,因为 red()
、green()
和 blue()
函数四舍五入为整数 ♂️
- 当反转颜色时,您需要从 alpha 值而不是 1 开始,因为预乘了 alpha。
- 从描述上看并不明显,但似乎刻录图像 alpha 优先。
我正在做一些 blendMode(BURN) 来绘制一些形状。其他形状我需要直接在之前形状的结果颜色中绘制,所以我需要自己生成混合结果颜色。
我正在寻找类似的东西:
let blendedColor = blendColorsBurn(color1, color2);
没有内置函数。在 2d 模式下 p5.js 利用 canvas 的 globalCompositeOperation
property,当设置为 color-burn
时执行以下颜色混合操作:
Divides the inverted bottom layer by the top layer, and then inverts the result.
这听起来很简单,但我想验证它的意思,所以我决定尝试快速测试实现。按 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;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/p5.js/1.4.0/p5.js"></script>
肯定有一些陷阱:
- 这可能很明显,但必须使用 0 到 1 之间的值来完成此数学运算,而不是 0 到 255 之间的值。
colorMode(RGB, 1, 1, 1, 1)
不起作用,因为red()
、green()
和blue()
函数四舍五入为整数 ♂️- 当反转颜色时,您需要从 alpha 值而不是 1 开始,因为预乘了 alpha。
- 从描述上看并不明显,但似乎刻录图像 alpha 优先。