Cloud Generator

Somebody PMed me recently for my cloud generator seen here:





Here’s the code, beware as it was made 2-3 years ago and was made for jME1…

The noise function was not created by me, I found it on some site online.


package com.gibbon.mfkarpg.imaging;

import com.jmex.effects.water.ImprovedNoise;
import java.awt.image.BufferedImage;
import java.awt.image.WritableRaster;
import java.nio.ByteBuffer;

public class CloudGenerator {
   
    private double lerp(double start, double end, double blend){
        return start==end ? start : ((1 - blend) * start) + (blend * end);
    }
   
    private double cerp(double start, double end, double blend){
        double cos_blend = (1 - Math.cos(blend * Math.PI)) * .5;
        return lerp(start,end,cos_blend);
    }
   
     private int r1 = 15731;
     private int r2 = 789221;
     private int r3 = 1376312589;
     
     private double noise(int x, int y, int z){
         int n = z + x * 57 + y * 57 * 57;
         n = (n<<13) ^ n;
         
         return ( 1.0 - ( (n * (n * n * r1 + r2) + r3) & 0x7fffffff) / 1073741824.0);
     }
   
    private double smooth_noise(double x, double y, double z){
        double n1 = noise((int)x, (int)y, (int)z);
        double n2 = noise((int)x + 1, (int)y, (int)z);
        double n3 = noise((int)x, (int)y + 1, (int)z);
        double n4 = noise((int)x + 1, (int)y + 1, (int)z);

        double zn1 = noise((int)x, (int)y, (int)z + 1);
        double zn2 = noise((int)x + 1, (int)y, (int)z + 1);
        double zn3 = noise((int)x, (int)y + 1, (int)z + 1);
        double zn4 = noise((int)x + 1, (int)y + 1, (int)z + 1);
       
        double i1 = cerp(n1, n2, x - (int)x);
        double i2 = cerp(n3, n4, x - (int)x);

        double i3 = cerp(i1, i2, y - (int)y);
       
        double zi1 = cerp(zn1, zn2, x - (int)x);
        double zi2 = cerp(zn3, zn4, x - (int)x);
       
        double zi3 = cerp(zi1, zi2, y - (int)y);
       
        return cerp(i3,zi3,z - (int)z);
   }
   
    private double clamp(double d){
        return d > 1.0 ? 1.0 : (d < 0.0 ? 0.0 : d);
    }
   
    private double curve(double d){
      double c = d - (1.0 - density);
      if (c < 0) c = 0.0;
     
      c = clamp(Math.pow(smoothness,c));
     
      return 1.0 - c;
    }
   
    private double frequency = 0.01;
    private double detail = 0.65;
    private double smoothness = 0.2; //0.4
    private double density = 1.0;
   
    private double func(double x, double z, double time, double freq) {
            double r = 0;
 
            double a = 1.0;
            double f = freq;
           
            for (int i = 0; i < 8; i++){
                r += smooth_noise(x * f, z * f, time) * a;
                //r += ImprovedNoise.noise(x * f,z * f, time) * a;
               
                f *= 2;
                a *= detail;
            }
           
            //double cloudCoverage = 0;   // USER ADJUSTABLE
            //double cloudDensity = 1;    // USER ADJUSTABLE

            //r = (r + cloudCoverage) * cloudDensity * fade;
                   
            r = curve(clamp(r));

            return r;
    }

    private byte double2byte (double d){
        return (byte)(((int)(d * 255)) & 0xFF);
    }
   
    private short double2short (double d){
        return (short)(d * 32768.0);
    }
           

    public void setDensity(float density){
        this.density=density;
    }
   
    public ByteBuffer generate(int width, int height, double time, ByteBuffer store){
        if (store==null){
            store = ByteBuffer.allocateDirect(width*height*2);
        }
       
        store.rewind();
        double size = (frequency / width) * 1024;
       
        for (int x = 0; x < width; x++){
            for (int y = 0; y < height; y++){
                double noise = func(x,y,time,size);
                byte b = double2byte(noise);
                //store.put((byte)0xFF).put(b);
                //store.put((byte)0xFF).put((byte)0xFF);
                store.put(b).put((byte)0xFF);
            }
        }
       
        return store;
    }
   
    public BufferedImage generate(int width, int height, double time){
        BufferedImage img = new BufferedImage(width,height,BufferedImage.TYPE_BYTE_GRAY);
        WritableRaster wr = img.getRaster();
       
        double size = (frequency / width) * 1024;
       
        for (int x = 0; x < width; x++){
            for (int y = 0; y < height; y++){
                //short s = double2short(func(x,y,time,size));
                //wr.setSample(x,y,0,s);
                double noise = func(x,y,time,size);
                byte b = double2byte(noise);
                wr.setSample(x,y,0, b );
            }
        }
       
        return img;
    }
}

1 Like

Where's the screenshot?  :-o

darkfrog said:

Where's the screenshot?  :-o

I could see the screenshot just fine  :?
Anyway I uploaded it to imageshack, that might fix it.

I can see clearly now…looks like a bright, bright, sun-shiny day. :slight_smile:

1 Like

why is there a lense flare? when i look at the sky, i don't see one. but i do see a strange colored spot wherever i look for a few minutes… why has nobody implemented such a feature yet?

hehe good point

don't suppose u can provide a test. :slight_smile:

Just call generate() and you get randomly generated clouds!

Momoko_Fan said:

Just call generate() and you get randomly generated clouds!


cool

Can I ask some questions here? I'm a total nood to all this, and although I've generated a texture and attached it to my Skydome, I have two problems. I get a black and white representation of the texture on the inside of the SkyDome, and to update the texture cripples(terminall) my loop. I suspect I need a translating quad to get movement, with one texture pre-calculated and added to the quad, and wrapped, but I'm at a loss as to how to use this code to get the clouds that are shown in the screenshot. It says on your wiki page that you are updating the texture in your loop, can you provide me a sample class of how you do all this.



Sorry for my noobness, but I've got to start somewhere, and am having alot of fun playing around making a terrain engine, just liking finding out how it's all done :slight_smile:

HamsterofDeath said:

why is there a lense flare? when i look at the sky, i don't see one.


But you aren't looking at the sky, an LWJGLCamera does that for you and that one creates a beautiful lens flare  ;)

If I remember correctly, I had issues applying this over the dome. You might want to consider using "sky plane" (search that online), it will allow you to pan the cloud texture without having to re-generate it. In the original test I generated the texture in another thread then applied it when it was ready.

hi there , is there any updates of this generator ? i’m very interested , or in any other way to make some Dynamic Clouds that doesn’t use too much ressources ,



Thank you.