Рисуем постоянно на PGraphics (Обработка) - PullRequest
1 голос
/ 30 сентября 2019

Я хотел бы создать кисть для рисования на элементе PGraphics с помощью Processing. Я хотел бы, чтобы прошлые мазки были видны. Однако, поскольку элемент PGraphics загружается каждый кадр, предыдущие мазки кисти исчезают немедленно.

Моя идея состояла в том, чтобы затем создать PGraphics pg в setup (), скопировать его в void (), изменить исходную графику pg и обновлять копию в каждом кадре. Это создает исключение NullPointerException, скорее всего, потому что pg определяется локально в setup ().

Это то, что я получил до сих пор:

PGraphics pg;Шрифт 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();
}

Моя последняя идея, которую я еще не пытался реализовать, - добавлять пиксели, которые были затронуты мышью, в список и рисовать из этого списка каждый кадр. Но это кажется мне довольно сложным, поскольку это может привести к необходимости обработки сверхдлинных массивов поверх исходного изображения. Итак, я надеюсь, что есть и другой путь!

РЕДАКТИРОВАТЬ: Моя цель - создать пятно, следовательно, кисть, которая копирует области с одной части изображения на другие части.

1 Ответ

3 голосов
/ 30 сентября 2019

Нет необходимости вручную копировать подобные пиксели. Класс PGraphics расширяет 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();
}

Как отмечается в комментариях, одна идея состоит в том, чтобыобразец цвета на прессе, затем используйте образец цвета и затемните его, перетаскивая из области источника. Это показывает просто чтение одного пикселя. Возможно, вы захотите поэкспериментировать с выборкой / считыванием большего количества пикселей (например, прямоугольника или эллипса).

smudge a demo

Кроме того, приведенный выше код не оптимизирован. Несколько вещей могут быть немного ускорены, такие как считывание пикселей, выделение цветов, вычисление расстояния и т. Д.

Например:

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();
}

Идея состоит в том, чтобы начать с простого с четкого, читаемогокод и только в конце, при необходимости посмотрите на оптимизацию.

...