public static float[,] GenerateNoiseMap(int mapWidth, int mapHeight, int seed, float scale, int octavesNumber, float persistance, float lacunarity, Float2 offset, NormalizedMode normalizeMode) { float[,] noiseMap = new float[mapWidth, mapHeight]; float amplitude = 1; float frequency = 1; float noiseHeight = 0; float sampleX; float sampleY; float halfWidth = mapWidth / 2f; float halfHeight = mapHeight / 2f; float perlinValue; //divide by zero handler if (scale <= 0) { scale = 0.0001f; } System.Random prng = new System.Random(seed); //pseudo-random number generator (prng) Float2[] octaveOffsets = new Float2[octavesNumber]; float maxPossibleHeight = 0; for (int i = 0; i < octavesNumber; i++) { //we don't want to give Mathf.PerlinNoise a coordinate that's too hight, //otherwise it's just keep returning the same value over and over again //range(-100000, 100000) works pretty well float offsetX = prng.Next(-100000, 100000) + offset.x; float offsetY = prng.Next(-100000, 100000) - offset.y; //substraction to inverse the orientation of the generation on the y axis octaveOffsets[i] = new Float2(offsetX, offsetY); maxPossibleHeight += amplitude; //we found the max possible height value here (end of the for loop) amplitude *= persistance; } float maxLocalNoiseHeight = float.MinValue; float minLocalNoiseHeight = float.MaxValue; for (int y = 0; y < mapHeight; y++) { for (int x = 0; x < mapWidth; x++) { amplitude = 1; frequency = 1; noiseHeight = 0; for (int i = 0; i < octavesNumber; i++) { //take the frequency into account: //the higher the frequency the further the sample points will be //the height value will change more rapidly sampleX = (x - halfWidth + octaveOffsets[i].x) / scale * frequency; sampleY = (y - halfHeight + octaveOffsets[i].y) / scale * frequency; perlinValue = Mathf.PerlinNoise(sampleX, sampleY); // give value between 0 and 1 perlinValue = perlinValue * 2 - 1; //to get negative values so that the noiseHeight could decrease //Perlin value of each octaves noiseHeight += perlinValue * amplitude; amplitude *= persistance; // 0 < persistance < 1: decreases the octave frequency *= lacunarity; // the frequency increases each octave: lacunarity > 1 } //to know the min/max noiseHeight if (noiseHeight > maxLocalNoiseHeight) { maxLocalNoiseHeight = noiseHeight; } else if (noiseHeight < minLocalNoiseHeight) { minLocalNoiseHeight = noiseHeight; } //to apply the noiseHeight to the noiseMap noiseMap[x, y] = noiseHeight; } } //"normalization" of the noiseMap so that the values get back to range(0,1), //need to keep track the lowest and the highest values #warning (Rivo) need to optimise this if (normalizeMode == NormalizedMode.Local) { for (int y = 0; y < mapHeight; y++) { for (int x = 0; x < mapWidth; x++) { noiseMap [x, y] = Mathf.InverseLerp(minLocalNoiseHeight, maxLocalNoiseHeight, noiseMap [x, y]); //produces the interpolant value of noiseMap [x, y] within the range(minNoiseHeight, maxNoiseHeight) //if the values is exceding the max it is set to 1 //if it is exceding the min it is set to 0 } } } else { float normalizedHeight; //float divisor; for (int y = 0; y < mapHeight; y++) { for (int x = 0; x < mapWidth; x++) { //divisor = 2f; //divisor *= maxPossibleHeight; //as the heightMap will never reach the max possible height, the map will render too flatly //need of estimation: division by 1.5 or 1.75 //divisor /= 1.75f; normalizedHeight = (noiseMap [x, y] + 1) / maxPossibleHeight; // inverse of the op done (cf perlinValue = perlinValue * 2 - 1; //to get negative values so that the noiseHeight could decrease) noiseMap[x, y] = Mathf.Clamp(normalizedHeight, 0, int.MaxValue); //assuming that the height can exceed one } } } return(noiseMap); }
public static float[, ] GeneratedNoiseMap(int mapWidth, int mapHeight, float scale, int seed, int octaves, float persistance, float lacunarity, Vector2 offset, NormalizedMode normalizedMode) { float[, ] noiseMap = new float[mapWidth, mapHeight]; System.Random prng = new System.Random(seed); Vector2[] octavesOffsets = new Vector2[octaves]; float halfWidht = mapWidth / 2f; float halfHeight = mapHeight / 2f; float maxPossibleHeight = 0f; float amplitude = 1; float frequency = 1; for (int i = 0; i < octaves; i++) { float offsetX = prng.Next(-100000, 100000) + offset.x; float offsetY = prng.Next(-100000, 100000) - offset.y; octavesOffsets[i] = new Vector2(offsetX, offsetY); maxPossibleHeight += amplitude; amplitude *= persistance; } if (scale <= 0) { scale = 0.0001f; } float maxLocalNoiseHeight = float.MinValue; float minNoiseHeight = float.MaxValue; for (int y = 0; y < mapHeight; y++) { for (int x = 0; x < mapWidth; x++) { amplitude = 1; frequency = 1; float noiseHeight = 0; for (int i = 0; i < octaves; i++) { float sampleX = (x - halfWidht + octavesOffsets[i].x) / scale * frequency; float sampleY = (y - halfHeight + octavesOffsets[i].y) / scale * frequency; float perlinVale = Mathf.PerlinNoise(sampleX, sampleY) * 2 - 1; noiseHeight += perlinVale * amplitude; amplitude *= persistance; frequency *= lacunarity; } if (maxLocalNoiseHeight < noiseHeight) { maxLocalNoiseHeight = noiseHeight; // Debug.Log("Max value changed to: "+maxNoiseHeight); } else if (minNoiseHeight > noiseHeight) { minNoiseHeight = noiseHeight; // Debug.Log("Min value changed to: " + maxNoiseHeight); } noiseMap[x, y] = noiseHeight; } } for (int y = 0; y < mapHeight; y++) { for (int x = 0; x < mapWidth; x++) { if (normalizedMode == NormalizedMode.Local) { noiseMap[x, y] = Mathf.InverseLerp(minNoiseHeight, maxLocalNoiseHeight, noiseMap[x, y]); } else { float normalizedHeight = (noiseMap[x, y] + 1) / (2f * maxPossibleHeight / 2f); noiseMap[x, y] = Mathf.Clamp(normalizedHeight, 0, int.MaxValue); } } } return(noiseMap); }
/// <summary> /// GenerateNoiseMap by some random math /// </summary> /// <param name="mapWidth">the map's width by pixels</param> /// <param name="mapHeight">the map's height by pixels</param> /// <param name="seed"> randmom seed </param> /// <param name="scale">the scale of the NoiseMap</param> /// <param name="octaves">the stack for the Noise may. we add all stack of the NoiseMap together make more detail for the NoiseMap</param> /// <param name="persistance">Change the amplitude for each stack,if the first stack's possible max Height is 1. then the next stack possible height will be persistance, the thrid statck persistance*persistance, the total possible max Height will be 1 + persistance + persistance * persistance</param> /// <param name="lacunarity">Change the frequency for each stack</param> /// <param name="offset"></param> /// <param name="normalizedMode"></param> /// <returns></returns> public static float[,] GenerateNoiseMap(int mapWidth, int mapHeight, int seed, float scale, int octaves, float persistance, float lacunarity, Vector2 offset, NormalizedMode normalizedMode) { float[,] noiseMap = new float[mapWidth, mapHeight]; if (scale == 0) { scale = 0.0001f; } System.Random prng = new System.Random(seed); Vector2[] octaveOffsets = new Vector2[octaves]; // because now octaves represent the total of the Vector2, so It should be a passitive int or z float maxPossibleHeight = 0; float amplitude = 1; //up down value float frequency = 1; // for (int j = 0; j < octaves; ++j) { float offsetX = prng.Next(-100000, 100000) + offset.x; float offsetY = prng.Next(-100000, 100000) - offset.y; octaveOffsets[j] = new Vector2(offsetX, offsetY); maxPossibleHeight += amplitude; amplitude *= persistance; } float maxLocalNoiseHeight = float.MinValue; float minLocalNoiseHeight = float.MaxValue; float halfWidth = mapWidth / 2f; float halfHeight = mapHeight / 2f; for (int y = 0; y < mapHeight; ++y) { for (int x = 0; x < mapWidth; ++x) { amplitude = 1; //up down value frequency = 1; // float noiseHeight = 0; // x - halfWidth and y - halfHeight means move the origin point to the center of the map when we scale the map // when we scale we move to the origiin to the center, then we zoom in or zoom out. for (int i = 0; i < octaves; ++i) { float sampleX = (x - halfWidth + octaveOffsets[i].x) / scale * frequency * 1.000003f; //just wanna make sure sampleX and sampleY not intger all the time. float sampleY = (y - halfHeight + octaveOffsets[i].y) / scale * frequency * 1.000003f; //the perlinValue is the greyscale values represent values from 0..1 float perlinValue = Mathf.PerlinNoise(sampleX, sampleY) * 2 - 1; // now the value become [-1,1] //Debug.Log(perlinValue); //octaves 1, main outline. octaves 2,boulders. octaves 3 small rocks. noiseHeight += perlinValue * amplitude; // here those three stack overleped. // the first noiseHeight will be perlinValue, the second noisHeight will be (noiseHeight + noiseHeight * persistance)...(noiseHeight + noiseHeight * persistance^2); amplitude *= persistance; //a1 =p^0; a2 = p^1; a3 = p^2; change the undown amplitude value of each stack frequency *= lacunarity; //f1 = l^0; f2 = l^1; f3 = l^2; change the frequency for each stack. } // When an set numbers is not increase order, or decrease order. // and we wanta get the min and max....we can use this mothed. // Max)-------------------------> // noiseHeight //<------------------------(Min if (noiseHeight > maxLocalNoiseHeight) { maxLocalNoiseHeight = noiseHeight; } if (noiseHeight < minLocalNoiseHeight) { minLocalNoiseHeight = noiseHeight; } noiseMap[x, y] = noiseHeight; } } for (int y = 0; y < mapHeight; ++y) { for (int x = 0; x < mapWidth; ++x) { //if noiseMap[x,y] = minNoiseHeight, then return 0; if...... return 1; //before the range of noiseMap[x,y] is [minNoiseHeight,MaxNoiseHeight]. //now we covert the range to [0,1] based on the origin noiseMap[x,y] if (normalizedMode == NormalizedMode.Local) { noiseMap[x, y] = Mathf.InverseLerp(minLocalNoiseHeight, maxLocalNoiseHeight, noiseMap[x, y]); } else { float normalizeHeight = (noiseMap[x, y] + 1) / (maxPossibleHeight); noiseMap[x, y] = Mathf.Clamp(normalizeHeight, 0, int.MaxValue); } } } return(noiseMap); }