JoshDreamland

Noise World

Nov 13th, 2013
102
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
Java 8.56 KB | None | 0 0
  1. // This program is free software: you can redistribute it and/or modify
  2. // it under the terms of the GNU General Public License as published by
  3. // the Free Software Foundation, either version 3 of the License, or
  4. // at your option) any later version.
  5.  
  6. // This program is distributed in the hope that it will be useful,
  7. // but WITHOUT ANY WARRANTY; without even the implied warranty of
  8. // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  9. // GNU General Public License for more details.
  10.  
  11. // You should have received a copy of the GNU General Public License
  12. // along with this program.  If not, see <http://www.gnu.org/licenses/>.
  13.  
  14. import java.util.Random;  // I can't stand arbitrary output
  15. import java.util.TreeMap; // FloorEntry/CeilEntry is needed for sampling
  16.  
  17. // Image parameters: This is the stuff that's easy to change
  18. final int W = 2400, H = 1350;
  19. final int w = W, h = H;
  20. final long seed  = 0x09f911029D74E35BL;
  21. final long seed2 = 0xD84156C5635688C0L;
  22. final long seed3 = 0xDECAFF;
  23. final int noiseCount = 512;
  24. final int cloudFreq = 16;
  25. final float baser = 32, basey = 96;
  26. final float dist1 = .002, dist2 = .0002;
  27. final int nth = 0;
  28.  
  29. // Other locals
  30. PImage img = createImage(w, h, RGB);
  31.  
  32. // Set up our noise and run it.
  33. void setup() {
  34.   size(W, H);
  35.   img.loadPixels();
  36.  
  37.   Combiner earth = new Combiner((new Octave())
  38.     .addOctave(1.0,   new Worley(seed, noiseCount, nth, dist1))
  39.     .addOctave(1./12, new Worley(seed + 1, noiseCount * 4, nth, dist2))
  40.   ).addLevel(0, new ColorSampler(0xFF0000FF))
  41.    .addLevel(.6, new ColorSampler(0xFF00FFFF))
  42.    .addLevel(.8, new ColorSampler(0xFFFFFEB4))
  43.    .addLevel(1.4, new Combiner((new Octave())
  44.       .addOctave(1./1,  new Perlin(seed2, noiseCount / 4).square().square().square())
  45.       .addOctave(1./2,  new Perlin(seed2, noiseCount / 2))
  46.       .addOctave(1./4,  new Perlin(seed2, noiseCount * 1))
  47.       .addOctave(1./8,  new Perlin(seed2, noiseCount * 2))
  48.       .addOctave(1./16, new Perlin(seed2, noiseCount * 4))
  49.     ).addLevel(0,  new ColorSampler(0xFF006000))
  50.      .addLevel(.5, new ColorSampler(0xFF008000))
  51.      .addLevel(1,  new ColorSampler(0xFF00C000))
  52.   );
  53.  
  54.   Combiner clouds = new Combiner((new Octave())
  55.     .addOctave(2.0,  new Perlin(seed3, cloudFreq * 1).square())
  56.     .addOctave(1./2, new Perlin(seed3, cloudFreq * 2).square())
  57.     .addOctave(1./4, new Perlin(seed3, cloudFreq * 4))
  58.     .addOctave(1./8, new Perlin(seed3, cloudFreq * 8))
  59.   ).addLevel(1,   earth)
  60.    .addLevel(2, new ColorSampler(0xFFFFFFFF))
  61.    .addLevel(3, new ColorSampler(0xFFC0C0C0));
  62.  
  63.   Sampler pic = clouds;
  64.  
  65.   int ind = 0;
  66.   for (int y = 0; y < h; ++y) {
  67.     float yf = y / (float)h;
  68.     for (int x = 0; x < w; ++x)
  69.       img.pixels[ind++] = pic.get(x / (float)w, yf);
  70.   }
  71.   img.updatePixels();
  72.   image(img, 0, 0, W, H);
  73.   save("cloudy-world.png");
  74. }
  75.  
  76.  
  77. // Utility functions, boilerplate boilerplate boilerplate
  78. static double sqr(double x) { return x*x; }
  79. static void arrins(int[] arr, int x, int ind) {
  80.   for (int i = arr.length - 1; i > ind; --i)
  81.     arr[i] = arr[i-1];
  82.   arr[ind] = x;
  83. } // This function exists because Java generics don't like primitives.
  84. // This will work in Java 7. OHWAITNOITWONT
  85. static void arrins(double[] arr, double x, int ind) {
  86.   for (int i = arr.length - 1; i > ind; --i)
  87.     arr[i] = arr[i-1];
  88.   arr[ind] = x;
  89. }
  90. float clamp(float v, float min, float max) {
  91.   return v < min? min : v > max? max : v;
  92. }
  93. float sigmoid(float a) {
  94.   return 1 / (1 + exp(-4*a+2));
  95. }
  96. float slerp(float x, float y, float a) {
  97.   return lerp(x, y, sin(a * PI/2));
  98. }
  99.  
  100. color mergeColor2(color c1, color c2, float a) {
  101.   int r1 = (c1 & 0xFF0000) >> 16, g1 = (c1 & 0xFF00) >> 8, b1 = (c1 & 0xFF);
  102.   int r2 = (c2 & 0xFF0000) >> 16, g2 = (c2 & 0xFF00) >> 8, b2 = (c2 & 0xFF);
  103.   if (a <= .5) {
  104.     color m = color(max(r1, (r1 + r2)/2), max(g1, (g1 + g2)/2), max(b1, (b1 + b2)/2));
  105.     return lerpColor(c1, m, 2 * a);
  106.   }
  107.   color m = color(max(r2, (r1 + r2)/2), max(g2, (g1 + g2)/2), max(b2, (b1 + b2)/2));
  108.   return lerpColor(m, c2, a * 2 - 1);
  109. }
  110.  
  111. color mergeColor(color c1, color c2, float a) {
  112.   int r1 = (c1 & 0xFF0000) >> 16, g1 = (c1 & 0xFF00) >> 8, b1 = (c1 & 0xFF);
  113.   int r2 = (c2 & 0xFF0000) >> 16, g2 = (c2 & 0xFF00) >> 8, b2 = (c2 & 0xFF);
  114.   color m = color(max(r1, r2), max(g1, g2), max(b1, b2));
  115.   return (a < .5)? lerpColor(c1, m, 2 * a) : lerpColor(m, c2, a * 2 - 1);
  116. }
  117.  
  118. color slerpColor(color c1, color c2, float a) {
  119.   return mergeColor(c1, c2, sigmoid(a));
  120. }
  121.  
  122. // Interfaces, classes
  123.  
  124. static interface Noise {
  125.   public float get(float x, float y);
  126. }
  127.  
  128.  
  129. // This is where the actual logic starts.
  130.  
  131. // This is a class to sample one octave of worley noise.
  132. static class Worley implements Noise {
  133.   // These are the variables needed by the actual image logic
  134.   double[][] points;
  135.   int k;
  136.   double max;
  137.  
  138.   // This creates our points, scattering them randomly according to the seed.
  139.   public Worley(long seed, int npts, int k, double max) {
  140.     Random worlrand = new Random(seed);
  141.     points = new double[npts][2];
  142.     this.k = k;
  143.     this.max = max;
  144.    
  145.     for (int i = 0; i < points.length; ++i) {
  146.       points[i][0] = worlrand.nextDouble();
  147.       points[i][1] = worlrand.nextDouble();
  148.     }
  149.   }
  150.  
  151.   // This samples a point by computing the squared distance to the nearest k points,
  152.   // then returning the kth closest
  153.   public float get(float x, float y) {
  154.     double[] d2 = new double[k + 1];
  155.     int[] ptnum = new int[k + 1];
  156.     for (int i = 0; i <= k; ++i) {
  157.       d2[i] = Double.POSITIVE_INFINITY;
  158.       ptnum[i] = 0;
  159.     }
  160.     for (int i = 0; i < points.length; ++i) {
  161.       double d2i = sqr(x - points[i][0]) + sqr(y - points[i][1]);
  162.       for (int j = 0; j <= k; ++j)
  163.         if (d2i < d2[j]) {
  164.           arrins(d2, d2i, j);
  165.           arrins(ptnum, i, j);
  166.           break;
  167.         }
  168.     }
  169.     return (float)(d2[k] / max);
  170.   }
  171. }
  172.  
  173. class Perlin implements Noise {
  174.   float[][] grid;
  175.   int size;
  176.  
  177.   Perlin(long seed, int dim) {
  178.     Random r = new Random(seed);
  179.     grid = new float[dim][dim];
  180.     size = dim;
  181.     for (int i = 0; i < dim; ++i)
  182.       for (int j = 0; j < dim; ++j)
  183.         grid[i][j] = (float)r.nextDouble();
  184.   }
  185.  
  186.   Perlin square() {
  187.     for (int i = 0; i < size; ++i)
  188.       for (int j = 0; j < size; ++j)
  189.         grid[i][j] *= grid[i][j];
  190.     return this;
  191.   }
  192.  
  193.   float get(float x, float y) {
  194.     float i = clamp(y, 0, 1) * (size - 1);
  195.     float j = clamp(x, 0, 1) * (size - 1);
  196.     int in = (int)floor(i), ix = (int)ceil(i);
  197.     int jn = (int)floor(j), jx = (int)ceil(j);
  198.     return slerp(
  199.       slerp(grid[in][jn], grid[in][jx], (j - jn)),
  200.       slerp(grid[ix][jn], grid[ix][jx], (j - jn)),
  201.       (i - in)
  202.     );
  203.   }
  204. }
  205.  
  206. class Octave implements Noise {
  207.   ArrayList<Noise>  octaves = new ArrayList<Noise>();
  208.   ArrayList<Double> factors = new ArrayList<Double>();
  209.   public Octave addOctave(double fac, Noise n) {
  210.     octaves.add(n);
  211.     factors.add(fac);
  212.     return this;
  213.   }
  214.   float get(float x, float y) {
  215.     double accum = 0;
  216.     for (int i = 0; i < octaves.size(); ++i)
  217.       accum += factors.get(i) * octaves.get(i).get(x, y);
  218.      return (float)accum;
  219.   }
  220. }
  221.  
  222. interface Interpolator {
  223.   color erp(color x, color y, float a);
  224. }
  225.  
  226. class LinearInterpolator implements Interpolator {
  227.   color erp(color x, color y, float a) {
  228.     return lerpColor(x, y, a);
  229.   }
  230. }
  231.  
  232. interface Sampler {
  233.   color get(float x, float y);
  234. }
  235.  
  236. class ColorSampler implements Sampler {
  237.   color c;
  238.   public ColorSampler(color c) { this.c = c; }
  239.   public color get(float x, float y) { return c; }
  240. }
  241.  
  242. class Combiner implements Sampler {
  243.   private class SampLerp {
  244.     public Sampler s;
  245.     public Interpolator i;
  246.     public SampLerp(Sampler ss, Interpolator si) { s = ss; i = si; }
  247.   }
  248.   TreeMap<Float, SampLerp> subsamplers = new TreeMap<Float, SampLerp>();
  249.   Noise sampleNoise;
  250.  
  251.   public Combiner(Noise n) { sampleNoise = n; }
  252.  
  253.   public Combiner addLevel(float threshold, Sampler s) { return addLevel(threshold, s, new LinearInterpolator()); }
  254.   public Combiner addLevel(float threshold, Sampler s, Interpolator i) { subsamplers.put(threshold, new SampLerp(s, i)); return this; }
  255.  
  256.   public color get(float x, float y) {
  257.     float noise = sampleNoise.get(x, y);
  258.     Float less = subsamplers.floorKey(noise);
  259.     Float more = subsamplers.ceilingKey(noise);
  260.     if (less == null) less = more;
  261.     if (less == more || more == null)
  262.       return subsamplers.get(less).s.get(x, y);
  263.     SampLerp sl = subsamplers.get(less);
  264.     return sl.i.erp(sl.s.get(x, y), subsamplers.get(more).s.get(x, y), (noise - less)/(more - less));
  265.   }
  266. }
Advertisement
Add Comment
Please, Sign In to add comment