High-Resolution Processing Output

纵然是瞬间 提交于 2019-12-06 05:22:38

In addition to Kevin's answer, you can use JVisualVM to see where most of the CPU time is spent on. After sampling and profiling the CPU at different times surprisingly most of the time was computing the RGB values:

It's best to start with the functions taking most of the CPU when optimizing.

Here is a version of the sketch that uses the default 0-255 RGB range and computes the RGB value inlined (putting the A,R,G,B bytes together):

import processing.pdf.*;
import java.util.Arrays;
float[][] z, v, a;

int dim = 900;
int dimScreen = dim/10;

///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////

void setup() {
  size(900, 900);
  smooth(8);
  //colorMode(RGB, 2);
  z = new float[width][height];
  v = new float[width][height];
  a = new float[width][height];
  loadPixels();

}

///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
void draw()  { exampleSketch(); }


void exampleSketch() {

  int r,g,b = 255;
  for (int x = 1; x < width-1; x++) {
    for (int y = 1; y < height-1; y++) {
      a[x][y] = (v[x-1][y] + v[x+1][y] + v[x][y-1] + v[x][y+1]) * .25 - v[x][y];
    //}
  //}
//  //for (int x = 1; x < width-1; x++) {
    //for (int y = 1; y < height-1; y++) {
      v[x][y] += a[x][y];
      z[x][y] += v[x][y];
      r = ((int)((sin(z[x][y]) + 1) * 128) << 16);
      g = ((int)((cos(z[x][y]) * 128)) << 8);
      pixels[width*y+x] = 0xff000000 | r | g | b;
    }
  }
  updatePixels();
  fill(0);
  text((int)frameRate+"fps",15,15);
}

///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////

void move() {
  if (mouseX > -1    &&    mouseX < width    &&    mouseY > -1    &&    mouseY < height) {
    v[mouseX][mouseY] = randomGaussian() * TAU;

  }
}

///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////

void mouseClicked() { move(); }

///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////

void mouseDragged() { move(); }


///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
int screenshotCount=1;
void keyPressed() {
  if (key ==' ') {
    save("result"+nf(screenshotCount,4)+".png");
    println("screenshot saved");
  }
}

//http://stackoverflow.com/questions/40350644/high-resolution-processing-output

Update: Here's an a modified function that maps the values so the background is white:

void exampleSketch() {
  float rv,gv;
  int r,g,b = 255;
  for (int x = 1; x < width-1; x++) {
    for (int y = 1; y < height-1; y++) {
      //compute accumulated value of neighbour cells(left+right+top+bottom), average (/4 or * .25) then subtract the current cell from v
      a[x][y] = (v[x-1][y] + v[x+1][y] + v[x][y-1] + v[x][y+1]) * .25 - v[x][y];
      //increment current v cell by the current accumulated cell
      v[x][y] += a[x][y];
      //increment current z (final/result) cell by the updated v cell
      z[x][y] += v[x][y];
      //in short z[x][y] += v[x][y] + ((v[-1][0] + v[+1][0] + v[0][-1] + v[0][+1]) / 4 - v[x][y])
      //scale sin(z) and cos(z) results to 0-255: sin/cos returns -1.0 to 1.0 then 1.0 is added -> 0.0 to 2.0 , then 128 is multiplied = 0-255
      rv = (sin(z[x][y]) + 1.0) * 128;
      gv = (cos(z[x][y]) + 1.0) * 128;
      //contrain to 0-255
      if(rv < 0)   rv = 0;
      if(rv > 255) rv = 255;
      if(gv < 0)   gv = 0;
      if(gv > 255) gv = 255;
      //cast to int and shift
      r = ((int)(rv) << 16);
      g = ((int)(gv) << 8);
      //alpha (0xff000000) cobined with r , g, b 
      int argb = 0xff000000 | r | g | b;
      pixels[width*y+x] = argb;
    }
  }
  updatePixels();
  fill(0);
  text((int)frameRate+"fps",15,15);
}

Heres what I could save:

Update 2: Here is a version that computes a transparency value instead of white:

import processing.pdf.*;
import java.util.Arrays;
float[][] z, v, a;

int dim = 900;
int dimScreen = dim/10;

PImage canvas;

///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////

void setup() {
  size(900, 900);
  smooth(8);
  //colorMode(RGB, 2);
  z = new float[width][height];
  v = new float[width][height];
  a = new float[width][height];
  loadPixels();


  canvas = createImage(width,height,ARGB);
}

///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
void draw()  { exampleSketch(); }


void exampleSketch() {
  float rs,gc,rv,gv;
  int r,g,b = 255;
  for (int x = 1; x < width-1; x++) {
    for (int y = 1; y < height-1; y++) {
      //compute accumulated value of neighbour cells(left+right+top+bottom), average (/4 or * .25) then subtract the current cell from v
      a[x][y] = (v[x-1][y] + v[x+1][y] + v[x][y-1] + v[x][y+1]) * .25 - v[x][y];
      //increment current v cell by the current accumulated cell
      v[x][y] += a[x][y];
      //increment current z (final/result) cell by the updated v cell
      z[x][y] += v[x][y];
      //in short z[x][y] += v[x][y] + ((v[-1][0] + v[+1][0] + v[0][-1] + v[0][+1]) / 4 - v[x][y])
      //scale sin(z) and cos(z) results to 0-255
      rs = sin(z[x][y]) + 1.0;
      gc = cos(z[x][y]) + 1.0;
      rv = rs * 128;
      gv = gc * 128;
      //contrain to 0-255
      if(rv < 0)   rv = 0;
      if(rv > 255) rv = 255;
      if(gv < 0)   gv = 0;
      if(gv > 255) gv = 255;
      //cast to int and shift
      r = ((int)(rv) << 16);
      g = ((int)(gv) << 8);
      //average sin/cos results = use the sin/cos results used for red/green channels, scale them by half (128) brightness and add them up
      //then subtract that from the max (255) to invert the alpha(transparency) value
      int alpha = 255-(int)((rs * 128) + (gc * 128));
      int argb = alpha << 24 | r | g | b;
      canvas.pixels[width*y+x] = argb;
    }
  }
  canvas.updatePixels();
  image(canvas,0,0);
  fill(0);
  text((int)frameRate+"fps",15,15);
}

///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////

void move() {
  if (mouseX > -1    &&    mouseX < width    &&    mouseY > -1    &&    mouseY < height) {
    v[mouseX][mouseY] = randomGaussian() * TAU;

  }
}

///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////

void mouseClicked() { move(); }

///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////

void mouseDragged() { move(); }


///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
int screenshotCount=1;
void keyPressed() {
  if (key ==' ') {
    canvas.save("result"+nf(screenshotCount,4)+".png");
    println("screenshot saved");
  }
}

Unfortunately I don't have the time to get into more detail and provide a fast working solution, but I can provide some pointers that may help:

This looks like a simplified BZ or Grey Scott reaction diffusion simulation:

Check out Daniel Shiffman's video tutorial on it: it will help you understand the algorithm better and write a more efficient implementation.

There are a couple more hardcore methods of speeding this up that come to mind:

  1. Parallelize the task on the GPU, rewriting the algorithm as a Processing GLSL shader (PShader) - additionally, if you don't mind slightly different implementation, it might be easier to tweak Shadertoy reaction diffusion fragment shaders to run as PShaders (e.g. this one or this one)
  2. Parallelize the task on the CPU (see Java Multiprocessing resources - sorta dry material)

You're really talking about two different things:

Thing One: Making the colored blobs bigger. This is a little annoying because the algorithm uses the pixels array, so it's not as simple as calling the scale() function.

In fact, because the algorithm works on pixels, any simple approach for changing the resolution is going to become pixelated.

The solution you got on the forum is to draw to an off-screen buffer, which won't actually change the size of the blobs. The only way to change the size of the blobs is to change your algorithm.

You might be able to modify how you're manipulating the arrays so the blobs are larger, but honestly I don't totally understand exactly what the arrays are doing now, which makes it hard to help.

Thing Two: Exporting as an image.

The easiest way to do this is to simply call the save("ImageNameHere.png") function. That will create an image with the same size as your sketch that contains whatever was showing on the screen when the function was called.

The solution you found on the forum uses an off-screen buffer, but again: that won't help with the size of the blobs. You can indeed use an off-screen buffer to draw to an image that's larger than the sketch window, but that's only half of what you want. Saving this way is useless if your blobs are still small!

So, my advice for you is to fix Thing One first, and come up with an algorithm that generates larger blobs. Then we can talk about scaling and exporting as an image, which will be pretty easy once you have the algorithm working.

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!