Rhino fire horn

 Like any normal person, when I see the blue rhino propane gas logo, I think to myself, that horn needs to have the “80′s fire demo effect” added to it.  If you don’t know what an “80′s fire demo effect” is, go back to the 80′s and check out some demos.

In the code I use three different ways to get the average pixel, I also add random black and bright dots to the fire; this enhances the fire effect.

And the code in processing to do the fire

import processing.opengl.*;

PGraphics fire;
PImage firemask;
PImage rhino;

int bs = 5;

void setup() {

  size(800, 800);
  background(0);
  rhino = loadImage("rhino.png");
  //rhino.resize(width, height);

  fire = createGraphics(600, 220, P3D);
  firemask = loadImage("flame.png");
  firemask.resize( fire.width, fire.height);
  // firemask.loadPixels();
  noStroke();
  smooth();

  //frameRate(14);
}

/*
+-----------------------+-------
 |  x-1,y+1  |    x,y-1  |  x+1,y-1  |
 |-----|-----------|-----|
 |  x-1,y    |    x,y    |  x+1,y    |
 |-----|-----------|-----|
 |  x-1, y+1 |    x,y+1  |  x+1, y+1 |
 +-----------------------+-------
 */
void update() {

  fire.loadPixels();

  for (int i=0; i < fire.width * fire.height; i++) {
    if (random(255) > 250 && red(fire.pixels[i]) > 90 ) { 
      fire.pixels[i] = color(170, 0, 0);
    }
    if (random(255) > 250 && red(fire.pixels[i]) > 30 ) { 
      fire.pixels[i] = color(0, 0, 0);
    }
  }

  for (int x=1; x < fire.width-1; x++) {
    for (int y=1; y < fire.height-1; y++) {

      float r1, r2, r3, r4;

      switch ( floor(random(3)) ) {
      case 1:
        r1 = red(fire.pixels[x + (y* fire.width) ]);
        r2 = red(fire.pixels[(x-1) + ((y+1) * fire.width)]);
        r3 = red(fire.pixels[(x+1) + ((y-1) * fire.width)]);
        r4 = red(fire.pixels[(x) + ((y-1) * fire.width)]);
        break;
      case 2:
        r1 = red(fire.pixels[x + (y * fire.width)]);
        r2 = red(fire.pixels[(x-1) + ((y+1) * fire.width)]);
        r3 = red(fire.pixels[(x) + ((y+1) * fire.width)]);
        r4 = red(fire.pixels[(x+1) + (y * fire.width)]);
        break;
      default:
        r1 = red(fire.pixels[x + (y* fire.width) ]);
        r2 = red(fire.pixels[(x-1) + ((y+1) * fire.width)]);
        r3 = red(fire.pixels[(x) + ((y+1) * fire.width)]);
        r4 = red(fire.pixels[(x+1) + ((y+1) * fire.width)]);
      }

      float rf = (r1+r2+r3+r4)/4;
      if (rf > 10) {
        fire.set(x, y-1, color( rf, 45, 57));
      } 
      else { 
        fire.set(x, y-1, color( 0));
      }
    }
  }

  fire.filter(BLUR, 1);  

  // create the new row;
  for (int i=0; i < fire.width; i++) {  
    fire.set(i, fire.height-1, color( random(255), 0, 0) );
  }
}

void draw() {
  copy(fire, 0, -10, fire.width, fire.height, 0, -200, width, height);
  image(rhino, 0, 0);
  update();
  saveFrame("output/ani####.jpg");
}

Now I just need to port this to the Android and get some sensor data controlling the fire so I can get some use of the IOIO class I took.

I played with the display, and used an image to seed the fire at the bottom and got this

code:

import processing.opengl.*;

PGraphics fire;
PImage firemask;
PImage rhino;
PImage clouds;
int pointer=0;

int bs = 5;

void setup() {

  size(800, 800);
  //frameRate(10);
  background(0);
  rhino = loadImage("rhino.png");
  clouds = loadImage("clouds1.jpg");

  //rhino.resize(width, height);

  fire = createGraphics(200, 220, P3D);
  clouds.resize(fire.width, fire.height);
  //fire.copy(clouds,0,0, clouds.width, clouds.height, 0,0, fire.width, fire.height);
  firemask = loadImage("flame.png");
  firemask.resize( fire.width, fire.height);
  // firemask.loadPixels();
  noStroke();
  smooth();

  //frameRate(14);
}

/*
+-----------------------+-------
 |  x-1,y+1  |    x,y-1  |  x+1,y-1  |
 |-----|-----------|-----|
 |  x-1,y    |    x,y    |  x+1,y    |
 |-----|-----------|-----|
 |  x-1, y+1 |    x,y+1  |  x+1, y+1 |
 +-----------------------+-------
 */
void update() {

  fire.loadPixels();

  for (int i=0; i < fire.width * fire.height; i++) {
    if (random(255) > 250 && red(fire.pixels[i]) > 90 ) { 
      fire.pixels[i] = color(170, 0, 0);
    }
    if (random(255) > 250 && red(fire.pixels[i]) > 30 ) { 
      fire.pixels[i] = color(0, 0, 0);
    }
  }

  for (int x=1; x < fire.width-1; x++) {
    for (int y=1; y < fire.height-1; y++) {

      float r1, r2, r3, r4;

      switch ( floor(random(3)) ) {
      case 1:
        r1 = red(fire.pixels[x + (y* fire.width) ]);
        r2 = red(fire.pixels[(x-1) + ((y+1) * fire.width)]);
        r3 = red(fire.pixels[(x+1) + ((y-1) * fire.width)]);
        r4 = red(fire.pixels[(x) + ((y-1) * fire.width)]);
        break;
      case 2:
        r1 = red(fire.pixels[x + (y * fire.width)]);
        r2 = red(fire.pixels[(x-1) + ((y+1) * fire.width)]);
        r3 = red(fire.pixels[(x) + ((y+1) * fire.width)]);
        r4 = red(fire.pixels[(x+1) + (y * fire.width)]);
        break;
      default:
        r1 = red(fire.pixels[x + (y* fire.width) ]);
        r2 = red(fire.pixels[(x-1) + ((y+1) * fire.width)]);
        r3 = red(fire.pixels[(x) + ((y+1) * fire.width)]);
        r4 = red(fire.pixels[(x+1) + ((y+1) * fire.width)]);
      }

      float rf = (r1+r2+r3+r4)/4;
      if (rf > 20) {
        fire.set(x, y-1, color( rf+1, 0, 0));
      } 
      else { 
        fire.set(x, y-1, color( 0));
      }
    }
  }

  fire.filter(BLUR, 1);  

  // create the new row;
  for (int i=0; i < fire.width; i++) {  
    fire.set(i, fire.height-1, clouds.get( i, pointer));
    pointer++;
    if (pointer > fire.height) { 
      pointer = 0;
    }

    //fire.set(i, fire.height-1, color( random(255), 0, 0) );
  }
}

void draw() {
  copy(fire, 0, -10, fire.width, fire.height, 0, -height*4, width, height*5);
  //image(rhino, 0, 0);
  update();
  saveFrame("output/ani####.jpg");
}

More Rhino With the new fire:

Got some code to convert from cartesian to polar coordinate system, plotted fire on circlular system:

Code found on processing forum to do the polar conversion:

PImage inputBasedPolar(PImage input, float factor, float density) {
  PImage output = createImage(input.width, input.height, RGB);
  for (float y=0; y<input.height; y+=density) {
    float r = y * factor;
    for (float x=0; x<input.width; x+=density) {
      float q = map(x, output.width, 0, 0, TWO_PI)-HALF_PI;
      int polarX = int(r * cos(q)) + output.width/2;
      int polarY = int(r * sin(q)) + output.height/2;
      polarX = constrain(polarX, 0, output.width-1);
      polarY = constrain(polarY, 0, output.height-1);
      int outputIndex = polarX + polarY * output.width;
      int inputIndex = int(x) + int(y) * input.width;
      output.pixels[outputIndex] = input.pixels[inputIndex];
    }
  }
  return output;
}

Although this is what I had in mind, which was actually easier:

Just draw a circle with random red values for each point , and then let the fire algorithm work off that.

Leave a Reply

Your email address will not be published. Required fields are marked *

*


five + 6 =

You may use these HTML tags and attributes: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <strike> <strong>