I know a good amount of Lua, however some of the syntax and maths I do not seem to understand in this wiki article. I've tested the script and it works as described, however I want to make custom terrain myself and I do not understand it. I've tried messing around with it a bit but this confuses me. Any recommendations on wiki articles I can view to help me use this to the extent of helping me learn?
This is what I have trouble understanding, by the way: http://wiki.roblox.com/index.php?title=Terrain_Generation
Hope this isn't too much to ask, I'm not asking you to narrow down the whole article, just some pages or advice that can help me learn this better. Cheers! :)
The concept of "terrain" in programming usually means generating some sort of "height map".
That is a map that takes a position along the horizontal plane (x, z) and turns it into a height.
There are some useful observations about the sorts of height maps you want when generating realistic terrain:
So the goal can usually be stated as, *make a function h(x, z)
that gives me a height for a part positioned at Vector3.new(x, __, z)
.
Since we want it to be wavy, we could take advantage of sine and cosine;
function h1(x, z) x = x / 20 -- Sine and Cosine want relatively close -- numbers; x and z in studs will make it way too noisy z = z / 20 return (math.sin(x) + math.sin(z)) * 20 -- -40 to 40 studs end
You'll get a wavy pattern if you use something like that.
Here's a different one:
function h2(x, z) x, z = x / 20, z / 20 return math.sin(x) * math.cos(z) * 20 -- -40 to 40 studs end
Interestingly, you can also add these two functions to get something that has a bit of both features:
function h3(x, z) return (h1(x, z) + h2(x, z) ) /2 end
With this in mind, there is the concept of fractal noise which is similar to Perlin noise.
We use a simple noise function over and over but at different scales, e.g.,
function h(x, z) local weight = 0 local sum = 0 for i = 1, 10 do local w = math.exp(-i / 5) local f = h3(x * i, z * i); sum = sum + f * w weight = weight + w end return sum / weight end
Another basic approach would be to place "nodes" which control the terrain -- "higher" nodes make mountains, lower ones valleys.
When you put enough mixed together, then you get a messy but smoothish result -- which is ideal for nice terrain.
Here is an inefficient, but simple algorithm. It consists of generating random points; the height function is then a weighted average of all of the values of the random points, where the weight of each decreases when you get further from it.
local points = {}; while #points < 100 do table.insert(points, {x = math.random() * 100, y = math.random() * 100; v = math.random()}) end -- Only will works nicely for points in the box [0, 100] x [0, 100] function h(x, z) local query = Vector3.new(x, 0, z); local totalWeight = 0; local total = 0; for _, point in pairs(points) do local position = Vector3.new(point.x, 0, point.y); local distance = position - query.magnitude; local weight = math.exp(-distance^2 / 1000.0); totalWeight = totalWeight + weight total = total + weight * point.v end return total / totalWeight end