0

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.

What I've Tried

GraphicsContext setFill() and fillRect()

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...

Using a PixelWriter

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.

Writing using a PixelFormat

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?

AlwaysNeedingHelp
  • 1,851
  • 3
  • 21
  • 29
  • I am by no way an expert on this, but I think you need to prepare an image on a separate task (thread) and swap it when it is ready, rather than drawing it directly on the canvas. You can also have several tasks preparing next images. For more help post [mcve] – c0der Dec 01 '18 at 08:43
  • See [this](https://stackoverflow.com/a/28819973/3992939) answer. That is what I had in mind. – c0der Dec 01 '18 at 08:49
  • A related approach is examined [here](https://stackoverflow.com/a/44141878/230513). – trashgod Dec 01 '18 at 18:30

0 Answers0