More isolated reef generation RFC
Xaphiosis opened this issue ยท 2 comments
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:
here's what that looks like in-game:
That's a bit too little reef, so I eventually went with exponent 5, 2 octaves, threshold 0.01:
For comparison, here is what we get with 1 octave when we lower the threshold to 0.001:
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
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)