diff --git a/VoxelEngine.Tests/WorldGen/NoiseSourceTests.cs b/VoxelEngine.Tests/WorldGen/NoiseSourceTests.cs new file mode 100644 index 0000000..b4eacd5 --- /dev/null +++ b/VoxelEngine.Tests/WorldGen/NoiseSourceTests.cs @@ -0,0 +1,29 @@ +using VoxelEngine.World.WorldGen; +using Xunit; + +namespace VoxelEngine.Tests.WorldGen; + +public class NoiseSourceTests +{ + [Fact] + public void SameSeed_SameCoord_IsDeterministic() + { + var a = new NoiseSource(42); + var b = new NoiseSource(42); + Assert.Equal(a.Continent(10f, 20f), b.Continent(10f, 20f)); + Assert.Equal(a.Temperature(10f, 20f), b.Temperature(10f, 20f)); + } + + [Fact] + public void Output_InMinusOneToOneRange() + { + var n = new NoiseSource(7); + for (int i = 0; i < 200; i++) + { + float c = n.Continent(i * 3.1f, i * 1.7f); + float t = n.Temperature(i * 2.3f, i * 0.9f); + Assert.InRange(c, -1.001f, 1.001f); + Assert.InRange(t, -1.001f, 1.001f); + } + } +} diff --git a/World/WorldGen/NoiseSource.cs b/World/WorldGen/NoiseSource.cs new file mode 100644 index 0000000..74aef97 --- /dev/null +++ b/World/WorldGen/NoiseSource.cs @@ -0,0 +1,32 @@ +namespace VoxelEngine.World.WorldGen; + +// Seeded wrapper over FastNoiseLite. All Get* methods return roughly [-1, 1]. +public sealed class NoiseSource +{ + private readonly FastNoiseLite _continent; + private readonly FastNoiseLite _temperature; + private readonly FastNoiseLite _forest; + + public NoiseSource(int seed) + { + this._continent = new FastNoiseLite(seed); + this._continent.SetNoiseType(FastNoiseLite.NoiseType.OpenSimplex2); + this._continent.SetFractalType(FastNoiseLite.FractalType.FBm); + this._continent.SetFractalOctaves(4); + this._continent.SetFrequency(0.0035f); + + this._temperature = new FastNoiseLite(seed + 1); + this._temperature.SetNoiseType(FastNoiseLite.NoiseType.OpenSimplex2); + this._temperature.SetFractalType(FastNoiseLite.FractalType.FBm); + this._temperature.SetFractalOctaves(3); + this._temperature.SetFrequency(0.0015f); + + this._forest = new FastNoiseLite(seed + 2); + this._forest.SetNoiseType(FastNoiseLite.NoiseType.OpenSimplex2); + this._forest.SetFrequency(0.02f); + } + + public float Continent(float x, float z) => this._continent.GetNoise(x, z); + public float Temperature(float x, float z) => this._temperature.GetNoise(x, z); + public float Forest(float x, float z) => this._forest.GetNoise(x, z); +}