Это довольно крутой эффект дыма.
Проще создать эффект дыма, используя blendMode()
. То, что вам нужно, это что-то вроде blendMode(SCREEN);
или blendMode(ADD);
, которое сделает черные пиксели на изображении с эффектом прозрачными.
![composited smoke effect over red circle](https://i.stack.imgur.com/G7lbA.jpg)
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);
}
![mixing blend modes to render a circle in the background behind the smoke effect and one in the foreground in front of the smoke effect](https://i.stack.imgur.com/NyyDx.jpg)
Дополнительно вы можете оформить заказ PGraphics
* От 1027 * до mimi c слоев, хотя для таких пиксельных эффектов вы можете многое сделать с помощью PImage
(и это set()
/ copy()
/ blend()
/ et c. Методов)
Вас также может заинтересовать шейдеры : фрагментные шейдеры, в частности для "пиксельных" манипуляций на GPU