-
-
Save jstanden/1489447 to your computer and use it in GitHub Desktop.
using UnityEngine; | |
using System.Collections; | |
public class SimplexNoiseGenerator { | |
private int[] A = new int[3]; | |
private float s, u, v, w; | |
private int i, j, k; | |
private float onethird = 0.333333333f; | |
private float onesixth = 0.166666667f; | |
private int[] T; | |
public SimplexNoiseGenerator() { | |
if (T == null) { | |
System.Random rand = new System.Random(); | |
T = new int[8]; | |
for (int q = 0; q < 8; q++) | |
T[q] = rand.Next(); | |
} | |
} | |
public SimplexNoiseGenerator(string seed) { | |
T = new int[8]; | |
string[] seed_parts = seed.Split(new char[] {' '}); | |
for(int q = 0; q < 8; q++) { | |
int b; | |
try { | |
b = int.Parse(seed_parts[q]); | |
} catch { | |
b = 0x0; | |
} | |
T[q] = b; | |
} | |
} | |
public SimplexNoiseGenerator(int[] seed) { // {0x16, 0x38, 0x32, 0x2c, 0x0d, 0x13, 0x07, 0x2a} | |
T = seed; | |
} | |
public string GetSeed() { | |
string seed = ""; | |
for(int q=0; q < 8; q++) { | |
seed += T[q].ToString(); | |
if(q < 7) | |
seed += " "; | |
} | |
return seed; | |
} | |
public float coherentNoise(float x, float y, float z, int octaves=1, int multiplier = 25, float amplitude = 0.5f, float lacunarity = 2, float persistence = 0.9f) { | |
Vector3 v3 = new Vector3(x,y,z)/multiplier; | |
float val = 0; | |
for (int n = 0; n < octaves; n++) { | |
val += noise(v3.x,v3.y,v3.z) * amplitude; | |
v3 *= lacunarity; | |
amplitude *= persistence; | |
} | |
return val; | |
} | |
public int getDensity(Vector3 loc) { | |
float val = coherentNoise(loc.x, loc.y, loc.z); | |
return (int)Mathf.Lerp(0,255,val); | |
} | |
// Simplex Noise Generator | |
public float noise(float x, float y, float z) { | |
s = (x + y + z) * onethird; | |
i = fastfloor(x + s); | |
j = fastfloor(y + s); | |
k = fastfloor(z + s); | |
s = (i + j + k) * onesixth; | |
u = x - i + s; | |
v = y - j + s; | |
w = z - k + s; | |
A[0] = 0; A[1] = 0; A[2] = 0; | |
int hi = u >= w ? u >= v ? 0 : 1 : v >= w ? 1 : 2; | |
int lo = u < w ? u < v ? 0 : 1 : v < w ? 1 : 2; | |
return kay(hi) + kay(3 - hi - lo) + kay(lo) + kay(0); | |
} | |
float kay(int a) { | |
s = (A[0] + A[1] + A[2]) * onesixth; | |
float x = u - A[0] + s; | |
float y = v - A[1] + s; | |
float z = w - A[2] + s; | |
float t = 0.6f - x * x - y * y - z * z; | |
int h = shuffle(i + A[0], j + A[1], k + A[2]); | |
A[a]++; | |
if (t < 0) return 0; | |
int b5 = h >> 5 & 1; | |
int b4 = h >> 4 & 1; | |
int b3 = h >> 3 & 1; | |
int b2 = h >> 2 & 1; | |
int b1 = h & 3; | |
float p = b1 == 1 ? x : b1 == 2 ? y : z; | |
float q = b1 == 1 ? y : b1 == 2 ? z : x; | |
float r = b1 == 1 ? z : b1 == 2 ? x : y; | |
p = b5 == b3 ? -p : p; | |
q = b5 == b4 ? -q : q; | |
r = b5 != (b4 ^ b3) ? -r : r; | |
t *= t; | |
return 8 * t * t * (p + (b1 == 0 ? q + r : b2 == 0 ? q : r)); | |
} | |
int shuffle(int i, int j, int k) { | |
return b(i, j, k, 0) + b(j, k, i, 1) + b(k, i, j, 2) + b(i, j, k, 3) + b(j, k, i, 4) + b(k, i, j, 5) + b(i, j, k, 6) + b(j, k, i, 7); | |
} | |
int b(int i, int j, int k, int B) { | |
return T[b(i, B) << 2 | b(j, B) << 1 | b(k, B)]; | |
} | |
int b(int N, int B) { | |
return N >> B & 1; | |
} | |
int fastfloor(float n) { | |
return n > 0 ? (int)n : (int)n - 1; | |
} | |
} |
Oh interesting, it must be something silly I'm doing on my end.
@AsherBearce I found some of the older code. Here's an example of how I was calling it:
SimplexNoiseGenerator noise = new SimplexNoiseGenerator();
float n = noise.coherentNoise(blockX,0,blockZ,4,82,2f,0.5f,1.57f);
Then I took that noise value n
and used it to create a height. It's a float value from -1.0
to +1.0
, so you can multiply it by the midpoint of whatever range of valid height values.
Simplex noise is coherent, so it's smoothly pseudorandom -- hills and valleys are gradual curves rather than chaotic points.
When I made the bitmap version it had 256 values per pixel for intensity.
To simulate sea level where you could dig down or up, the midpoint was 128, so the negative n
values reduced midpoint intensity and the positive values increased it. You could adjust the midpoint/underground/aboveground as needed for your terrain/world (e.g. more sky above than underground below, rather than 50/50).
Here is a little noise texture generator I wrote using this code. It generates seamlessly tiling textures.
Apologies for the late replies. I didn't see any notifications about these comments until the last one.
@Quentin-H At least in Unity 10 years ago, it was a standalone library. I used the coherent noise in a Minecraft clone to experiment with terrain generation.
@mackycheese21 From memory I believe -1 to +1. I picked a base plane (e.g. sea level), then used the noise to generate a height map. Within the height range I set different biomes for the transitions (bedrock, lava, stone, dirt, grass/water, mountain/rock, snow).
@AsherBearce That's possible. I haven't used this code for about 10 years -- although I did update my old Minecraft-inspired world generator to show my kids last year and it still worked fine in modern Unity.
My
x
,y
,z
values were based on world coordinates with 1 meter as the unit. I never needed more than few thousand blocks in any cardinal direction (I also didn't need altitude). The intensity of noise determined the height at a given location, which then determined the terrain features.I created a simple app to generate a bitmap image the size of my expected terrain. That let me tweak the octaves, multiplier, amplitude, lacunarity, and persistence with UI sliders until I had a good result. Then I took those values into my app.