- Home /
Perlin Noise and Terrain Generation
I'm attempting to write a script that generates a random terrain at runtime using Perlin Noise. I've found two very useful scripts, but I can't seem to combine them together. How would I do this? SCRIPT 1: GENERATES A RANDOM TEXTURE
// This script is placed in public domain. The author takes no responsibility for any possible harm.
var gray = true; var width = 128; var height = 128;
var lacunarity = 6.18; var h = 0.69; var octaves = 8.379; var offset = 0.75; var scale = 0.09;
var offsetPos = 0.0;
private var texture : Texture2D; private var perlin : Perlin; private var fractal : FractalNoise;
function Start () { texture = new Texture2D(width, height, TextureFormat.RGB24, false); renderer.material.mainTexture = texture;
Calculate();
}
function Calculate() { if (perlin == null) perlin = new Perlin(); fractal = new FractalNoise(h, lacunarity, octaves, perlin);
for (var y = 0;y<height;y++)
{
for (var x = 0;x<width;x++)
{
if (gray)
{
var value = fractal.HybridMultifractal(x*scale + Time.time, y * scale + Time.time, offset);
texture.SetPixel(x, y, Color (value, value, value, value));
}
else
{
offsetPos = Time.time;
var valuex = fractal.HybridMultifractal(x*scale + offsetPos * 0.6, y*scale + offsetPos * 0.6, offset);
var valuey = fractal.HybridMultifractal(x*scale + 161.7 + offsetPos * 0.2, y*scale + 161.7 + offsetPos * 0.3, offset);
var valuez = fractal.HybridMultifractal(x*scale + 591.1 + offsetPos, y*scale + 591.1 + offsetPos * 0.1, offset);
texture.SetPixel(x, y, Color (valuex, valuey, valuez, 1));
}
}
}
texture.Apply();
}
And here is Eric's script for getting a heightmap from a texture (thanks!)
@MenuItem ("Terrain/Heightmap From Texture")
static function ApplyHeightmap () { var heightmap : Texture2D = Selection.activeObject as Texture2D; if (heightmap == null) { EditorUtility.DisplayDialog("No texture selected", "Please select a texture.", "Cancel"); return; } Undo.RegisterUndo (Terrain.activeTerrain.terrainData, "Heightmap From Texture");
var terrain = Terrain.activeTerrain.terrainData;
var w = heightmap.width;
var h = heightmap.height;
var w2 = terrain.heightmapWidth;
var heightmapData = terrain.GetHeights(0, 0, w2, w2);
var mapColors = heightmap.GetPixels();
var map = new Color[w2 * w2];
if (w2 != w || h != w) {
// Resize using nearest-neighbor scaling if texture has no filtering
if (heightmap.filterMode == FilterMode.Point) {
var dx : float = parseFloat(w)/w2;
var dy : float = parseFloat(h)/w2;
for (y = 0; y < w2; y++) {
if (y%20 == 0) {
EditorUtility.DisplayProgressBar("Resize", "Calculating texture", Mathf.InverseLerp(0.0, w2, y));
}
var thisY = parseInt(dy*y)*w;
var yw = y*w2;
for (x = 0; x < w2; x++) {
map[yw + x] = mapColors[thisY + dx*x];
}
}
}
// Otherwise resize using bilinear filtering
else {
var ratioX = 1.0/(parseFloat(w2)/(w-1));
var ratioY = 1.0/(parseFloat(w2)/(h-1));
for (y = 0; y < w2; y++) {
if (y%20 == 0) {
EditorUtility.DisplayProgressBar("Resize", "Calculating texture", Mathf.InverseLerp(0.0, w2, y));
}
var yy = Mathf.Floor(y*ratioY);
var y1 = yy*w;
var y2 = (yy+1)*w;
yw = y*w2;
for (x = 0; x < w2; x++) {
var xx = Mathf.Floor(x*ratioX);
var bl = mapColors[y1 + xx];
var br = mapColors[y1 + xx+1];
var tl = mapColors[y2 + xx];
var tr = mapColors[y2 + xx+1];
var xLerp = x*ratioX-xx;
map[yw + x] = Color.Lerp(Color.Lerp(bl, br, xLerp), Color.Lerp(tl, tr, xLerp), y*ratioY-yy);
}
}
}
EditorUtility.ClearProgressBar();
}
else {
// Use original if no resize is needed
map = mapColors;
}
// Assign texture data to heightmap
for (y = 0; y < w2; y++) {
for (x = 0; x < w2; x++) {
heightmapData[y,x] = map[y*w2+x].grayscale;
}
}
terrain.SetHeights(0, 0, heightmapData);
}
Thanks!
Answer by Bunny83 · Apr 19, 2011 at 03:22 PM
The first script is a script that is designed to be executed at runtime (in game). The second script is an editor script that can only be used in the editor. You have to "pack" the first script into a single function so you can generate a texture with it.
If you want to modify the perlin noise parameters you would have to create either an editorwindow to show those options, or do it the runtime way and generate it during runtime.