抖动 (Floyd-Steinberg) 仅更新 p5.js 中的部分图形对象
Dithering (Floyd-Steinberg) only updates part of graphics object in p5.js
我正在尝试在 P5.js 草图中实现 Floyd-Steinberg 抖动,方法是在图形对象(在设置中)中预先抖动一堆圆圈,然后再绘制它们。
但是,我一直 运行 解决只有一部分圆圈抖动,其余看起来正常的问题。欢迎提出任何建议,因为我对发生的事情真的很困惑。
setup()
:
let circs;
function setup() {
//...
createCanvas(1000,1000);
let size = 200;
circs = [];
circs.push({
gfx: createGraphics(size, size),
size: size,
color: color(random(255))
});
for (let i = 0; i < circs.length; i++)
dither(circs[i]);
// ...
}
draw()
:
function draw() {
if (!paused) {
background(bg);
drawShadow(4); // just a call to the drawingContext shadow
for (let i = 0; i < circs.length; i++) {
push();
translate(width / 2, height / 2);
imageMode(CENTER);
image(circs[i].gfx, 0, 0);
pop();
}
}
}
floyd-steinberg - based on https://openprocessing.org/sketch/1192123
function index(x, y, g) {
return (x + y * g.width) * 4;
}
function dither(g) {
g.loadPixels();
for (let y = 0; y < g.height - 1; y++) {
for (let x = 1; x < g.width - 1; x++) {
let oldr = g.pixels[index(x, y, g)];
let oldg = g.pixels[index(x, y, g) + 1];
let oldb = g.pixels[index(x, y, g) + 2];
let factor = 1.0;
let newr = round((factor * oldr) / 255) * (255 / factor);
let newg = round((factor * oldg) / 255) * (255 / factor);
let newb = round((factor * oldb) / 255) * (255 / factor);
g.pixels[index(x, y, g)] = newr;
g.pixels[index(x, y, g) + 1] = newg;
g.pixels[index(x, y, g) + 2] = newb;
g.pixels[index(x + 1, y, g)] += ((oldr - newr) * 7) / 16.0;
g.pixels[index(x + 1, y, g) + 1] += ((oldr - newr) * 7) / 16.0;
g.pixels[index(x + 1, y, g) + 2] += ((oldr - newr) * 7) / 16.0;
g.pixels[index(x - 1, y + 1, g)] += ((oldr - newr) * 3) / 16.0;
g.pixels[index(x - 1, y + 1, g) + 1] += ((oldr - newr) * 3) / 16.0;
g.pixels[index(x - 1, y + 1, g) + 2] += ((oldr - newr) * 3) / 16.0;
g.pixels[index(x, y + 1, g)] += ((oldr - newr) * 5) / 16.0;
g.pixels[index(x, y + 1, g) + 1] += ((oldr - newr) * 5) / 16.0;
g.pixels[index(x, y + 1, g) + 2] += ((oldr - newr) * 5) / 16.0;
g.pixels[index(x + 1, y + 1, g)] += ((oldr - newr) * 1) / 16.0;
g.pixels[index(x + 1, y + 1, g) + 1] += ((oldr - newr) * 1) / 16.0;
g.pixels[index(x + 1, y + 1, g) + 2] += ((oldr - newr) * 1) / 16.0;
}
}
g.updatePixels();
}
我不确定我遗漏了什么,因为抖动算法在高度和宽度上循环,然后 应该 更新,但我想我遗漏了什么。
p5.Graphics
对象具有从草图继承的 pixelDensity
。当像素密度 > 1 时,对于高 DPI 显示器,您需要在计算像素索引时考虑到这一点:
function index(x, y, g) {
const d = g.pixelDensity();
return (x + y * g.width * d) * 4;
}
当您处理像素时,您需要将 x 和 y 的最大值加倍。
这里演示了 pixelDensity 的效果(以及你是否处理它):
let g;
function setup() {
createCanvas(400, 400);
g = createGraphics(width, height);
redrawGraphics();
noLoop();
setInterval(
() => {
redrawGraphics(frameCount % 2);
redraw();
},
2000
);
}
function index(x, y, g, d) {
return (x + y * g.width * d) * 4;
}
function redrawGraphics(hdpi) {
const d = hdpi ? pixelDensity() : 1;
g.background(0);
g.loadPixels();
for (let y = 0; y < height * 2; y++) {
for (let x = 0; x < width * 2; x++) {
let ix = index(x, y, g, d);
let r = map(sin((x - y) / width * TWO_PI), -1, 1, 0, 255);
g.pixels[ix] = r;
g.pixels[ix + 1] = 0;
g.pixels[ix + 2] = 0;
g.pixels[ix + 3] = 255;
}
}
g.updatePixels();
}
function draw() {
image(g, 0, 0);
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/p5.js/1.4.0/p5.js"></script>
我正在尝试在 P5.js 草图中实现 Floyd-Steinberg 抖动,方法是在图形对象(在设置中)中预先抖动一堆圆圈,然后再绘制它们。
但是,我一直 运行 解决只有一部分圆圈抖动,其余看起来正常的问题。欢迎提出任何建议,因为我对发生的事情真的很困惑。
setup()
:
let circs;
function setup() {
//...
createCanvas(1000,1000);
let size = 200;
circs = [];
circs.push({
gfx: createGraphics(size, size),
size: size,
color: color(random(255))
});
for (let i = 0; i < circs.length; i++)
dither(circs[i]);
// ...
}
draw()
:
function draw() {
if (!paused) {
background(bg);
drawShadow(4); // just a call to the drawingContext shadow
for (let i = 0; i < circs.length; i++) {
push();
translate(width / 2, height / 2);
imageMode(CENTER);
image(circs[i].gfx, 0, 0);
pop();
}
}
}
floyd-steinberg - based on https://openprocessing.org/sketch/1192123
function index(x, y, g) {
return (x + y * g.width) * 4;
}
function dither(g) {
g.loadPixels();
for (let y = 0; y < g.height - 1; y++) {
for (let x = 1; x < g.width - 1; x++) {
let oldr = g.pixels[index(x, y, g)];
let oldg = g.pixels[index(x, y, g) + 1];
let oldb = g.pixels[index(x, y, g) + 2];
let factor = 1.0;
let newr = round((factor * oldr) / 255) * (255 / factor);
let newg = round((factor * oldg) / 255) * (255 / factor);
let newb = round((factor * oldb) / 255) * (255 / factor);
g.pixels[index(x, y, g)] = newr;
g.pixels[index(x, y, g) + 1] = newg;
g.pixels[index(x, y, g) + 2] = newb;
g.pixels[index(x + 1, y, g)] += ((oldr - newr) * 7) / 16.0;
g.pixels[index(x + 1, y, g) + 1] += ((oldr - newr) * 7) / 16.0;
g.pixels[index(x + 1, y, g) + 2] += ((oldr - newr) * 7) / 16.0;
g.pixels[index(x - 1, y + 1, g)] += ((oldr - newr) * 3) / 16.0;
g.pixels[index(x - 1, y + 1, g) + 1] += ((oldr - newr) * 3) / 16.0;
g.pixels[index(x - 1, y + 1, g) + 2] += ((oldr - newr) * 3) / 16.0;
g.pixels[index(x, y + 1, g)] += ((oldr - newr) * 5) / 16.0;
g.pixels[index(x, y + 1, g) + 1] += ((oldr - newr) * 5) / 16.0;
g.pixels[index(x, y + 1, g) + 2] += ((oldr - newr) * 5) / 16.0;
g.pixels[index(x + 1, y + 1, g)] += ((oldr - newr) * 1) / 16.0;
g.pixels[index(x + 1, y + 1, g) + 1] += ((oldr - newr) * 1) / 16.0;
g.pixels[index(x + 1, y + 1, g) + 2] += ((oldr - newr) * 1) / 16.0;
}
}
g.updatePixels();
}
我不确定我遗漏了什么,因为抖动算法在高度和宽度上循环,然后 应该 更新,但我想我遗漏了什么。
p5.Graphics
对象具有从草图继承的 pixelDensity
。当像素密度 > 1 时,对于高 DPI 显示器,您需要在计算像素索引时考虑到这一点:
function index(x, y, g) {
const d = g.pixelDensity();
return (x + y * g.width * d) * 4;
}
当您处理像素时,您需要将 x 和 y 的最大值加倍。
这里演示了 pixelDensity 的效果(以及你是否处理它):
let g;
function setup() {
createCanvas(400, 400);
g = createGraphics(width, height);
redrawGraphics();
noLoop();
setInterval(
() => {
redrawGraphics(frameCount % 2);
redraw();
},
2000
);
}
function index(x, y, g, d) {
return (x + y * g.width * d) * 4;
}
function redrawGraphics(hdpi) {
const d = hdpi ? pixelDensity() : 1;
g.background(0);
g.loadPixels();
for (let y = 0; y < height * 2; y++) {
for (let x = 0; x < width * 2; x++) {
let ix = index(x, y, g, d);
let r = map(sin((x - y) / width * TWO_PI), -1, 1, 0, 255);
g.pixels[ix] = r;
g.pixels[ix + 1] = 0;
g.pixels[ix + 2] = 0;
g.pixels[ix + 3] = 255;
}
}
g.updatePixels();
}
function draw() {
image(g, 0, 0);
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/p5.js/1.4.0/p5.js"></script>