1

I am currently working on a game in Java. For this project I have been looking into generating asteroid and planet textures procedurally. The functions below works pretty well, in fact it does exactly what I intend it to do and I am very pleased with the results. The object generates the graphic once while it initializes and then stores the BufferedImage for later rendering.

Since it is a 3D noise I am using (OpenSimplexNoise) it is very easy to implement a sort of animation in my graphic. By increasing the i variable and re-generating my graphic on every frame i can "animate" through the 3D noise, making for a really neat effect. This, however is very taxing as it has to iterate through every pixel of every graphic on every frame.

Here in lays my issue, and subsequent question. Is there a was to accelerate this with a GPU using a library like LWJGL? I have been trying to read up on LWJGL and other OpenGL libraries, but to no avail. Since every cycle is independent of the previous calculation in the loop I would guess that this is a perfect target for parallel computing, I am just unsure how to do it.

Another way to lower the computation time would be to just lower the "resolution" of the rendered image or lowering the amount of updates to something like one every second but I'm not too keen on any of these solutions.

TL:DR Parallel computing of graphics made easy in Java?

Two pictures of the current algorithm in action:
henriknilsson.ml/2017-01-21%2022'49.PNG
henriknilsson.ml/2017-01-21%2023'20.PNG

Planet.generateGraphic

private static BufferedImage generateGraphic(int seed, double radius, double i){
    BufferedImage image = new BufferedImage((int)radius * 2, (int)radius * 2, BufferedImage.TYPE_4BYTE_ABGR);

    Random r = new Random(seed);

    //Select two random colors

    int cr = r.nextInt(256);
    int cg = r.nextInt(256);
    int cb = r.nextInt(256);

    Color color = new Color(cr, cg, cb);

    cr *= r.nextDouble() + 0.5;
    cg *= r.nextDouble() + 0.5;
    cb *= r.nextDouble() + 0.5;

    if(cr > 255)cr = 255;
    if(cg > 255)cg = 255;
    if(cb > 255)cb = 255;

    Color color2 = new Color(cr, cg, cb);

    OpenSimplexNoise osn = new OpenSimplexNoise(seed);
    double modifierx = r.nextDouble() * 5 + radius / 5;
    double modifiery = modifierx;

    double limit1 = 0.15;
    double limit2 = 0.05;

    //Offset the x and y modifiers for a Gas-giant "look"

    if(r.nextBoolean()){
        modifierx *= r.nextInt(8) + 4;
        modifiery /= 2;
    }

    //Itterate through every pixel

    for(int x = 0; x < image.getWidth(); x++){
        for(int y = 0; y < image.getWidth(); y++){
            double distance = Math.sqrt((x - radius) * (x - radius) + (y - radius) * (y - radius));

            if(distance > radius){
                image.setRGB(x, y, 0);
            }
            else{
                Color c;
                float noise = (float)osn.eval(x / modifierx, y / modifiery, i);

                if(noise > limit1){
                    c = color;
                }
                else if (noise > limit2){
                    float alpha = (float)(1 - (noise - limit2) / (limit1 - limit2)); 
                    c = Functions.blend(color, color2, alpha);
                }
                else{
                    c = color2;
                }

                float red = (float)c.getRed() / 255;
                float green = (float)c.getGreen() / 255;
                float blue = (float)c.getBlue() / 255;


                //Random offset
                double q = (((double)r.nextInt(81) + 960) / 1000);

                //Shadow
                double s = (Math.sqrt(radius * radius - distance * distance + 250) / radius);

                red *= q;
                green *= q;
                blue *= q;

                red *= s;
                green *= s;
                blue *= s;

                //Limit values
                if(red > 1)red = 1;
                if(green > 1)green = 1;
                if(blue > 1)blue = 1;

                image.setRGB(x, y, new Color(red, green, blue).getRGB());
            }
        }
    }
    return image;
}

Functions.blend

public static Color blend(Color c1, Color c2, float ratio) {
    if ( ratio > 1f ) ratio = 1f;
    else if ( ratio < 0f ) ratio = 0f;
    float iRatio = 1.0f - ratio;

    int i1 = c1.getRGB();
    int i2 = c2.getRGB();

    int a1 = (i1 >> 24 & 0xff);
    int r1 = ((i1 & 0xff0000) >> 16);
    int g1 = ((i1 & 0xff00) >> 8);
    int b1 = (i1 & 0xff);

    int a2 = (i2 >> 24 & 0xff);
    int r2 = ((i2 & 0xff0000) >> 16);
    int g2 = ((i2 & 0xff00) >> 8);
    int b2 = (i2 & 0xff);

    int a = (int)((a1 * iRatio) + (a2 * ratio));
    int r = (int)((r1 * iRatio) + (r2 * ratio));
    int g = (int)((g1 * iRatio) + (g2 * ratio));
    int b = (int)((b1 * iRatio) + (b2 * ratio));

    return new Color( a << 24 | r << 16 | g << 8 | b );
}
genpfault
  • 51,148
  • 11
  • 85
  • 139
Henrik
  • 11
  • 1
  • 2
  • How much faster do you need? Parallelization on the CPU is pretty easy and you can get pretty close to a speedup that equals the number of CPU cores almost for free. GPU-acceleration is not too easy on the other hand. And it is questionable if transferring the data to and from the GPU makes up for the speedup in computation. Shifting the entire game to the GPU is another question, though – Nico Schertler Jan 23 '17 at 16:47
  • @NicoSchertler Well having just five planets with a radius of 100px on screen drops my fps way below my target 60 fps, if that is any sort of quantification. And I am still unsure of how I would go about splitting it up in Threads on the CPU. Also, could you further elaborate on shifting the game to the GPU, please :) – Henrik Jan 23 '17 at 17:54
  • In the simplest case, just distribute the rows over the threads (as many as there are cores). [This question](http://stackoverflow.com/questions/4010185/parallel-for-for-java) might give you some ideas. My second comment was about rendering the entire game with OpenGL so you don't have to transfer image data between CPU and GPU. But this would require a major rewrite. – Nico Schertler Jan 23 '17 at 18:30
  • https://github.com/ashima/webgl-noise/wiki – genpfault Jan 23 '17 at 19:31

0 Answers0