Reputation: 1955
I'm using Kurt Spencer's implementation of OpenSimplexNoise found here.
I'm trying to draw the resulting noise on a 512x52 JavaFX Canvas as fast as possible.
Note: Not shown in the code below for simplicity, the draw functions takes in a zoom level (the value of a JavaFX Slider element). The draw function is called from a change listener on that slider.
Using the value of the noise to set the fill, and then calling fillRect() for a 1x1 rectangle at the appropriate location:
public void drawWithRect() {
// width and height of the canvas
int width = (int)getCanvas().getWidth();
int height = (int)getCanvas().getHeight();
// Get the graphics context of the canvas
GraphicsContext gc = getCanvas().getGraphicsContext2D();
for (int y = 0; y < height; y++) {
for (int x = 0; x < width; x++) {
double val = (noise((double)x/40, (double)y/40));
gc.setFill(Color.color(val,val,val));
gc.fillRect(x,y,1,1);
}
}
}
Result: Despite apparantly taking 40ms roughly, this seriously lags my computer, taking 5+ seconds at a time for the results to display. This was bad. I'm unsure what was going on behind the scenes here to cause the program to have difficulty rendering it all...
My next improvement came from using a PixelWriter:
public void drawWithPixelWriter() {
// width and height of the canvas
int width = (int)getCanvas().getWidth();
int height = (int)getCanvas().getHeight();
// Get the graphics context of the canvas
GraphicsContext gc = getCanvas().getGraphicsContext2D();
// Create the PixelWriter
PixelWriter pixelWriter = gc.getPixelWriter();
for (int y = 0; y < height; y++) {
for (int x = 0; x < width; x++) {
double val = (noise((double)x/40, (double)y/40));
pixelWriter.setColor(x,y, Color.color(val,val,val));
}
}
}
Result: 25ms on average. This is much better. There is no real lag and the application feels smoothish and responsive.
We use PixelFormat.getByteRgbInstance();
and write the values of our noise into a large byte array, which is then passed to the pixelWriter along with the PixelFormat.
public void drawWithPixelFormat() {
// width and height of the canvas
int width = (int)getCanvas().getWidth();
int height = (int)getCanvas().getHeight();
// array to hold rgb value for every pixel
byte[] pixels = new byte[height * width * 3];
// Get the graphics context of the canvas
GraphicsContext gc = getCanvas().getGraphicsContext2D();
// Create the PixelWriter
PixelWriter pixelWriter = gc.getPixelWriter();
// Define the PixelFormat
PixelFormat<ByteBuffer> pixelFormat = PixelFormat.getByteRgbInstance();
for (int y = 0; y < height; y++) {
for (int x = 0; x < width; x++) {
// Get the index
int i = y * width * 3 + x * 3;
//Get the noise value
byte val = (byte)(noise((double)x/40, (double)y/40)*255);
// set the rgb colors of the pixel;
pixels[i] = val;
pixels[i + 1] = val;
pixels[i + 2] = val;
}
}
// draw the noise
pixelWriter.setPixels(0, 0, width, height, pixelFormat, pixels, 0, width * 3);
}
Result: 16ms average for each draw. This is much better and for a 512x512 it is very smooth. See here for gif.
But what if I want to generate bigger maps? For a 1024x1024 canvas the draw time is around 65ms and noticable choppy. What if I want to add a number of octaves or change the color based on some conditions? All this would add to the draw time so It's imperative I bring it down as much as possible.
Any suggestions for improvements?
Upvotes: 0
Views: 388