在 PGraphics 上永久绘制(处理中)

Draw permanently on PGraphics (Processing)

我想创建一个画笔,用于使用 Processing 在 PGraphics 元素上绘图。我希望过去的笔触可见。但是,由于 PGraphics 元素是每帧加载的,因此之前的笔触会立即消失。

然后我的想法是在 setup() 中创建 PGraphics pg,在 void() 中复制它,更改原始图形 pg 并在每一帧更新副本。这会产生 NullPointerException,很可能是因为 pg 是在 setup() 中本地定义的。

这是我目前得到的:

P图形页; PFont 字体;

void setup (){
  font = createFont("Pano Bold Kopie.otf", 600);
  size(800, 800, P2D);
  pg = createGraphics(800, 800, P2D);
  pg.beginDraw();
  pg.background(0);
  pg.fill(255);
  pg.textFont(font);
  pg.textSize(400);
  pg.pushMatrix();
  pg.translate(width/2, height/2-140);
  pg.textAlign(CENTER, CENTER);
  pg.text("a", 0 , 0);
  pg.popMatrix();
  pg.endDraw();
}

void draw () {
  copy(pg, 0, 0, width, height, 0, 0, width, height);
  loop();
  int c;

  loadPixels();
  for (int x=0; x<width; x++) {
    for (int y=0; y<height; y++) {
      pg.pixels[mouseX+mouseY*width]=0;
    }
  }
  updatePixels();
}

我还没有尝试实现的最后一个想法是将鼠标触摸过的像素附加到列表中,并从该列表中绘制每一帧。但这对我来说似乎很复杂,因为它可能会导致需要在原始图像之上处理超长数组。所以,我希望有另一种方法!

编辑:我的目标是创建一个涂抹画笔,因此是一种将区域从图像的一部分复制到其他部分的画笔。

无需像那样手动复制像素。 PGraphics class 扩展了 PImage,这意味着您可以简单地用 image(pg,0,0); 渲染它。

您可以做的另一件事是使背景变淡的老技巧:您可以渲染一个草图大小略微不透明的矩形,而不是描边,而不是完全清除像素。

这是基于您的代码的快速概念证明:

PFont font;
PGraphics pg;

void setup (){
  //font = createFont("Pano Bold Kopie.otf", 600);
  font = createFont("Verdana",600);

  size(800, 800, P2D);
  // clear main background once
  background(0);
  // prep fading background
  noStroke();
  // black fill with 10/255 transparnecy
  fill(0,10);

  pg = createGraphics(800, 800, P2D);
  pg.beginDraw();
  // leave the PGraphics instance transparent
  //pg.background(0);
  pg.fill(255);
  pg.textFont(font);
  pg.textSize(400);
  pg.pushMatrix();
  pg.translate(width/2, height/2-140);
  pg.textAlign(CENTER, CENTER);
  pg.text("a", 0 , 0);
  pg.popMatrix();
  pg.endDraw();
}

void draw () {
  // test with mouse pressed
  if(mousePressed){
    // slowly fade/clear the background by drawing a slightly opaque rectangle
    rect(0,0,width,height);
  }
  // don't clear the background, render the PGraphics layer directly
  image(pg, mouseX - pg.width / 2, mouseY - pg.height / 2);
}

按住鼠标可以看到淡入淡出的效果。 (将透明度更改为 10 到更高的值,使淡入淡出更快)

更新 要创建涂抹画笔,您仍然可以对像素进行采样,然后在某种程度上操纵读取的颜色。有很多方法可以根据您想要在视觉上实现的效果来实现涂抹效果。

这是一个非常粗略的概念证明:

PFont font;
PGraphics pg;

int pressX;
int pressY;

void setup (){
  //font = createFont("Pano Bold Kopie.otf", 600);
  font = createFont("Verdana",600);

  size(800, 800, P2D);
  // clear main background once
  background(0);
  // prep fading background
  noStroke();
  // black fill with 10/255 transparnecy
  fill(0,10);

  pg = createGraphics(800, 800, JAVA2D);
  pg.beginDraw();
  // leave the PGraphics instance transparent
  //pg.background(0);
  pg.fill(255);
  pg.noStroke();
  pg.textFont(font);
  pg.textSize(400);
  pg.pushMatrix();
  pg.translate(width/2, height/2-140);
  pg.textAlign(CENTER, CENTER);
  pg.text("a", 0 , 0);
  pg.popMatrix();
  pg.endDraw();
}

void draw () {
  image(pg,0,0);
}

void mousePressed(){
  pressX = mouseX;
  pressY = mouseY;
}

void mouseDragged(){
  // sample the colour where mouse was pressed
  color sample = pg.get(pressX,pressY);
  // calculate the distance from where the "smudge" started to where it is
  float distance = dist(pressX,pressY,mouseX,mouseY);
  // map this distance to transparency so the further the distance the less smudge (e.g. short distance, high alpha, large distnace, small alpha)
  float alpha = map(distance,0,30,255,0);
  // map distance to "brush size"
  float size = map(distance,0,30,30,0);
  // extract r,g,b values
  float r = red(sample);
  float g = green(sample);
  float b = blue(sample);
  // set new r,g,b,a values
  pg.beginDraw();
  pg.fill(r,g,b,alpha);
  pg.ellipse(mouseX,mouseY,size,size);
  pg.endDraw();
}

正如评论中提到的那样,一种想法是在印刷机上对颜色进行采样,然后使用样本颜色并在拖离源区域时将其淡化。这显示了简单地读取单个像素。您可能想尝试使用 sampling/reading 更多像素(例如矩形或椭圆)。

另外,上面的代码没有优化。 有些事情可以加快一点,比如读取像素、提取颜色、计算距离等。

例如:

void mouseDragged(){
  // sample the colour where mouse was pressed
  color sample = pg.pixels[pressX + (pressY * pg.width)];
  // calculate the distance from where the "smudge" started to where it is (can use manual distance squared if this is too slow)
  float distance = dist(pressX,pressY,mouseX,mouseY);
  // map this distance to transparency so the further the distance the less smudge (e.g. short distance, high alpha, large distnace, small alpha)
  float alpha = map(distance,0,30,255,0);
  // map distance to "brush size"
  float size = map(distance,0,30,30,0);
  // extract r,g,b values
  int r = (sample >> 16) & 0xFF; // Like red(), but faster
  int g = (sample >> 8) & 0xFF;
  int b =  sample & 0xFF;
  // set new r,g,b,a values
  pg.beginDraw();
  pg.fill(r,g,b,alpha);
  pg.ellipse(mouseX,mouseY,size,size);
  pg.endDraw();
}

我们的想法是从简单的开始,使用清晰、可读的代码,只有在最后,如果需要才研究优化。