首页 > 解决方案 > 如何使 PImage 中的黑色像素透明?

问题描述

以下代码产生上升的烟雾效果。

PImage buffer1;
PImage buffer2;
PImage cooling;
PImage buffer3;
float yInitial = 0.0;
void setup() {
  size(600, 200);
  buffer1 = createImage(width, 200, RGB);
  buffer2 = createImage(width, 200, RGB);
  buffer3 = createImage(width, 200, RGB);
  cooling = createImage(width, 200, RGB);
}
void newLine(int rows) {
  //create row of white pixels
  buffer1.loadPixels();
  for (int x = 0; x<  buffer1.width; x++){
    for(int j = 0; j< rows; j++){
      //find location to draw pixels
      int y = buffer1.height - (j+1); 
      int index = x + y * buffer1.width;
      buffer1.pixels[index] = color(255);
    }
  }
  buffer1.updatePixels();
}
void cool(){
  cooling.loadPixels();
  //start x at 0
  float xoff = 0.0;
  float increment = 0.02;
  for (int x = 0; x < cooling.width; x++){
    xoff += increment;
    //start y at 0
    float yoff = yInitial;
    for (int y = 0; y < cooling.height; y++){
      yoff += increment;
      //calculate noise and enlarge
      float n = noise(xoff, yoff);
      if(n<0.4)
        n = 0;
      float bright = noise(xoff, yoff) *25;
      //set pixel to grayscale value
      cooling.pixels[x+y*cooling.width]= color(bright);
    }
  }
  cooling.updatePixels();
  yInitial += increment;
}

void draw(){
  cool();
  newLine(10);
  background(0);
  buffer1.loadPixels();
  buffer2.loadPixels();
  //look through all x and y coordinates and find the neightboring pixels colour
  for (int x = 1; x < buffer1.width-1; x++) {
    for (int y = 1; y < buffer1.height-1; y++) {
      int index0 = x + y * buffer1.width;
      int index1 = (x+1) + y * buffer1.width;
      int index2 = (x-1) + y * buffer1.width;
      int index3 = x + (y+1) * buffer1.width;
      int index4 = x + (y-1) * buffer1.width;
      color c1 = buffer1.pixels[index1];
      color c2 = buffer1.pixels[index2];
      color c3 = buffer1.pixels[index3];
      color c4 = buffer1.pixels[index4];
      color c5 = cooling.pixels[index0];
      float newC = brightness(c1) + brightness(c2)+ brightness(c3) + brightness(c4);
      newC = newC - brightness(c5);
      newC = newC / 4;
      buffer2.pixels[index4] = color(newC);
    }
  }
  buffer2.updatePixels();

  //swap
  PImage temp = buffer1;
  buffer1 = buffer2;
  buffer2 = temp;
  image(buffer2, 0, 0);
}

我打算使用这段代码在背景中的图像上绘制移动的烟雾(我还没有把它放进去)。为此,我试图使 PImage 中的所有黑色像素都透明。这应该意味着只有烟雾会被绘制在背景图像上。然后,在绘制 PImage 后,我将所有透明像素改回黑色。但是,当我在烟雾中添加它时,它完全停止了绘制。我做错了什么,这是尝试在背景图像上绘制烟雾的正确方法吗?这是我的代码:

PImage buffer1;
PImage buffer2;
PImage cooling;
PImage buffer3;
float yInitial = 0.0;
void setup() {
  size(600, 200);
  buffer1 = createImage(width, 200, RGB);
  buffer2 = createImage(width, 200, RGB);
  buffer3 = createImage(width, 200, RGB);
  cooling = createImage(width, 200, RGB);
}
void newLine(int rows) {
  //create row of white pixels
  buffer1.loadPixels();
  for (int x = 0; x<  buffer1.width; x++){
    for(int j = 0; j< rows; j++){
      //find location to draw pixels
      int y = buffer1.height - (j+1); 
      int index = x + y * buffer1.width;
      buffer1.pixels[index] = color(255);
    }
  }
  buffer1.updatePixels();
}
void cool(){
  cooling.loadPixels();
  //start x at 0
  float xoff = 0.0;
  float increment = 0.02;
  for (int x = 0; x < cooling.width; x++){
    xoff += increment;
    //start y at 0
    float yoff = yInitial;
    for (int y = 0; y < cooling.height; y++){
      yoff += increment;
      //calculate noise and enlarge
      float n = noise(xoff, yoff);
      if(n<0.4)
        n = 0;
      float bright = noise(xoff, yoff) *25;
      //set pixel to grayscale value
      cooling.pixels[x+y*cooling.width]= color(bright);
    }
  }
  cooling.updatePixels();
  yInitial += increment;
}

void draw(){
  cool();
  newLine(10);
  buffer1.loadPixels();
  buffer2.loadPixels();
  //look through all x and y coordinates and find the neightboring pixels colour
  for (int x = 1; x < buffer1.width-1; x++) {
    for (int y = 1; y < buffer1.height-1; y++) {
      int index0 = x + y * buffer1.width;
      int index1 = (x+1) + y * buffer1.width;
      int index2 = (x-1) + y * buffer1.width;
      int index3 = x + (y+1) * buffer1.width;
      int index4 = x + (y-1) * buffer1.width;
      color c1 = buffer1.pixels[index1];
      color c2 = buffer1.pixels[index2];
      color c3 = buffer1.pixels[index3];
      color c4 = buffer1.pixels[index4];
      color c5 = cooling.pixels[index0];
      float newC = brightness(c1) + brightness(c2)+ brightness(c3) + brightness(c4);
      newC = newC - brightness(c5);
      newC = newC / 4;
      buffer2.pixels[index4] = color(newC);
      //make the black pixels transparent
      if(color(buffer2.pixels[index0])==color(0));
        buffer2.pixels[index0] = color(0,0);
      if(color(buffer1.pixels[index0])==color(0));
        buffer1.pixels[index0] = color(0,0);
    }
  }
  buffer2.updatePixels();

  //swap
  PImage temp = buffer1;
  buffer1 = buffer2;
  buffer2 = temp;
  image(buffer2, 0, 0);
  //set transparent pixels back to black
  for (int x = 1; x < buffer1.width-1; x++) {
    for (int y = 1; y < buffer1.height-1; y++) {
      int index0 = x + y * buffer1.width;
      if(color(buffer2.pixels[index0])==color(0,0))
        buffer2.pixels[index0] = color(0);
      if(color(buffer1.pixels[index0])==color(0,0));
        buffer1.pixels[index0] = color(0);
    }
  }
}

标签: processing

解决方案


这是一个非常酷的烟雾效果。

使用 .com 可以更轻松地合成烟雾效果blendMode()。您所追求的是类似于blendMode(SCREEN);blendMode(ADD);会使效果图像上的黑色像素透明的东西。

红色圆圈上的复合烟雾效果

PImage buffer1;
PImage buffer2;
PImage cooling;
PImage buffer3;
float yInitial = 0.0;

void setup() {
  size(600, 200);
  fill(192,0,0);
  // change blend mode to treat black pixels as transparent
  blendMode(SCREEN);

  buffer1 = createImage(width, 200, RGB);
  buffer2 = createImage(width, 200, RGB);
  buffer3 = createImage(width, 200, RGB);
  cooling = createImage(width, 200, RGB);
}
void newLine(int rows) {
  //create row of white pixels
  buffer1.loadPixels();
  for (int x = 0; x<  buffer1.width; x++){
    for(int j = 0; j< rows; j++){
      //find location to draw pixels
      int y = buffer1.height - (j+1); 
      int index = x + y * buffer1.width;
      buffer1.pixels[index] = color(255);
    }
  }
  buffer1.updatePixels();
}
void cool(){
  cooling.loadPixels();
  //start x at 0
  float xoff = 0.0;
  float increment = 0.02;
  for (int x = 0; x < cooling.width; x++){
    xoff += increment;
    //start y at 0
    float yoff = yInitial;
    for (int y = 0; y < cooling.height; y++){
      yoff += increment;
      //calculate noise and enlarge
      float n = noise(xoff, yoff);
      if(n<0.4)
        n = 0;
      float bright = noise(xoff, yoff) *25;
      //set pixel to grayscale value
      cooling.pixels[x+y*cooling.width]= color(bright);
    }
  }
  cooling.updatePixels();
  yInitial += increment;
}

void updateSmokeEffect(){
  cool();
  newLine(10);
  buffer1.loadPixels();
  buffer2.loadPixels();
  //look through all x and y coordinates and find the neightboring pixels colour
  for (int x = 1; x < buffer1.width-1; x++) {
    for (int y = 1; y < buffer1.height-1; y++) {
      int index0 = x + y * buffer1.width;
      int index1 = (x+1) + y * buffer1.width;
      int index2 = (x-1) + y * buffer1.width;
      int index3 = x + (y+1) * buffer1.width;
      int index4 = x + (y-1) * buffer1.width;
      color c1 = buffer1.pixels[index1];
      color c2 = buffer1.pixels[index2];
      color c3 = buffer1.pixels[index3];
      color c4 = buffer1.pixels[index4];
      color c5 = cooling.pixels[index0];
      float newC = brightness(c1) + brightness(c2)+ brightness(c3) + brightness(c4);
      newC = newC - brightness(c5);
      newC = newC / 4;
      buffer2.pixels[index4] = color(newC);
    }
  }
  buffer2.updatePixels();

  swapBuffers();
}

void swapBuffers(){
  //swap
  PImage temp = buffer1;
  buffer1 = buffer2;
  buffer2 = temp;
}

void draw(){
  background(0);
  // test drawing something in the background
  ellipse(mouseX,mouseY,30,30);

  updateSmokeEffect();
  // render blended image on top
  image(buffer2, 0, 0);
}

您可以使用blendMode(BLEND)恢复到默认混合模式:

void draw(){
  background(0);
  blendMode(ADD);
  // test drawing something in the background
  ellipse(mouseX,mouseY,30,30);

  updateSmokeEffect();
  // render blended image on top
  image(buffer2, 0, 0);

  blendMode(BLEND);
  // test drawing something in the foreground
  ellipse(mouseX + 35,mouseY,30,30);
}

混合混合模式以在烟雾效果后面的背景中渲染一个圆圈,在烟雾效果前面的前景中渲染一个圆圈

此外,您可以结帐PGraphics以模仿图层,但对于像这样的像素效果,您可以做很多事情PImage(它的set()/ copy()/ blend()/ 等方法)

您可能还对着色器感兴趣:片段着色器,特别是用于 GPU 上的“像素”操作


推荐阅读