CoralReef

CoralReef

11M Downloads

More isolated reef generation RFC

Xaphiosis opened this issue ยท 2 comments

commented

Hello. I thought about what you said about "how to make the noise make circular patches rather than continuous reefs". Current version lives at https://github.com/Xaphiosis/CoralReef/commits/master

I hacked up a program to display a noise map overlaid over chunk boundaries, identifying where the threshold for reef generation is achieved in red.
Here are some examples:

Exponent 5, 1 octave, threshold 0.01:
pow5oct1thresh01
here's what that looks like in-game:

pow5oct1thresh01_ingame

That's a bit too little reef, so I eventually went with exponent 5, 2 octaves, threshold 0.01:

pow5oct2thresh01

For comparison, here is what we get with 1 octave when we lower the threshold to 0.001:

pow5oct1thresh001

and finally here is the code if you want to play around yourself:

import javax.swing.*;
import java.awt.*;
import net.minecraft.world.gen.NoiseGeneratorOctaves;
import java.util.Random;
import java.awt.image.BufferedImage;
import java.io.File;
import javax.imageio.ImageIO;
import java.io.IOException;

public class NoiseTest {

    final int OCTAVES = 2;
    final double NOISE_SCALE = 0.03125D;

    public static final int CHUNK_SIZE = 16;
    public double[] noise = new double[CHUNK_SIZE * CHUNK_SIZE];
    public NoiseGeneratorOctaves noiseGen = new NoiseGeneratorOctaves(new Random(3364), OCTAVES);

    public static final int imgSize = 1024;
    public static final int chunks_wide = imgSize / CHUNK_SIZE;

    double low = 10000;
    double hi = -10000;

    public NoiseTest() {
    }

    public void genChunkNoise(int cx, int cz) {
        noise = noiseGen.generateNoiseOctaves(noise,
                cx * CHUNK_SIZE, 0, cz * CHUNK_SIZE,         // noise offset (for matching edges)
                CHUNK_SIZE, 1, CHUNK_SIZE,                   // array size
                NOISE_SCALE, 1.0, NOISE_SCALE);              // noise scale
    }

    public void renderChunk(BufferedImage img, int cx, int cz, Random rand) {
        genChunkNoise(cx, cz);

        for (int xoff = 0; xoff < CHUNK_SIZE; ++xoff) {
            for (int yoff = 0; yoff < CHUNK_SIZE; ++yoff) {
                int x = cx * CHUNK_SIZE + xoff;
                int y = cz * CHUNK_SIZE + yoff;

                // fetch and normalise
                double n = noise[xoff * CHUNK_SIZE + yoff] / OCTAVES;

                // gather statistics
                if (n < low) low = n;
                if (n > hi) hi = n;

                // tune noise
                n -= rand.nextDouble() * 0.1;
                n = Math.pow(n, 5);
                boolean threshold = n > 0.01;

                // convert to greyscale
                int c = (int)((n + 1)*128);
                if (c > 255) c = 255;
                if (c < 0) c = 0;
                int r = c;
                int g = c;
                int b = c;

                // mark matches in red
                if (threshold) r = 255;

                // mark chunk edges
                if (xoff == 0 || yoff == 0) {
                    r /= 2; // highlight chunk edges
                    g /= 2;
                    b /= 2;
                }

                img.setRGB(x, y, r << 16 | g << 8 | b);
            }
        }
    }

    public static void main(String[] args) {
        NoiseTest nt = new NoiseTest();
        nt.genChunkNoise(0,0);
        BufferedImage img = new BufferedImage(imgSize, imgSize, BufferedImage.TYPE_INT_RGB);
        Graphics2D g2d = img.createGraphics();
        g2d.setBackground(new Color(0, 0, 0));
        g2d.clearRect(0, 0, img.getWidth(), img.getHeight());

        Random rand = new Random(555);

        for (int cx = 0; cx < chunks_wide; ++cx) {
            for (int cy = 0; cy < chunks_wide; ++cy) {
                nt.renderChunk(img, cx, cy, rand);
            }
        }

        System.out.println("hi: " + nt.hi + " low: " + nt.low);
        try {
            File outputfile = new File("output.png");
            ImageIO.write(img, "png", outputfile);
        } catch (IOException e) {
            System.out.println("Couldn't save image: " + e);
        }

        JFrame frame = new JFrame();
        FlowLayout layout = new FlowLayout();
        layout.setVgap(0);
        frame.setLayout(layout);
        frame.setSize(imgSize, imgSize);
        JLabel picLabel = new JLabel(new ImageIcon(img));
        frame.add(picLabel);
        frame.setVisible(true);
        frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
    }
}

Getting it to compile (on linux, with deobf. sources in the current dir) went something like:
javac -cp ".:/usr/share/java/guava.jar:/usr/share/java/jsr305.jar" NoiseTest.java

commented

I have since changed the generation some more, to the point I am happy with it. Relatively isolated islands favouring proximity to the surface. Obviously not world-gen compatible with the current release, and nor necessarily to your liking either. I think I won't change too much from this point. If you have time, take a look at what's on master and tell me what you think.

(PR #3 is unrelated, just a bugfix)

commented

I like it a lot! looks much better than it did before. I don't particularly mind that it would cause small borders on existing worlds, most people wouldn't notice. Feel free to PR those changes :)