Issues with infinite triangle terrain generator

I have a few issues currently I am still figuring out how to fix.

First issue:

Tears appear in my terrain due to how I load chunks probably.

The chunk loading works fine, but I am trying to make chunks that are near load first before loading the others further away.

My current way of doing it is basically this:

	while true do
		for x = 0, renderdist.Value do
			local campos = cam.CFrame.Position
			local x2 = x * abcs
			local fl = campos+v3(-x2,0,-x2)
			local fr = campos+v3(x2,0,-x2)
			local bl = campos+v3(-x2,0,x2)
			local br = campos+v3(x2,0,x2)
			--i loop
			for i = 0, (renderdist.Value) - x do
				local i2 = i * abcs
				loadchunk(fl + v3(-i2, 0, 0))
				loadchunk(fl + v3(0, 0, -i2))
				loadchunk(fr + v3(i2, 0, 0))
				loadchunk(fr + v3(0, 0, -i2))
				loadchunk(bl + v3(-i2, 0, 0))
				loadchunk(bl + v3(0, 0, i2))
				loadchunk(br + v3(i2, 0, 0))
				loadchunk(br + v3(0, 0, i2))
			--i loop

This isn’t the whole script (it’s like 3 modules btw) but this is where I load nearby chunks first and then the ones further away.

Also, the chunkloading is multi-threaded so the tears can’t be because of chunks not loading in time/too slow.

I’m not certain what the best way to load nearby chunks first is (in a circle pattern that slowly expands as you walk).

Second issue I’m running into is the fact that there are too many mountains and don’t really know a way to adjust perlin noise to generate flat areas as well.

mod.noisey = function(pos)
	local spos = tostring(pos)
	local key = noiseycache[spos]
	if key then
		return v3(pos.x, pos.y + key, pos.z)
	noiseycache[spos] = (noise( --Noise 1
		pos.x / steepnessx,
		pos.z / steepnessz
		) * amplitude
	noiseycachesize = noiseycachesize + 1
	return v3(pos.x, pos.y + noiseycache[spos], pos.z)

ignore the key/table part, that’s just for caching in case I expand the function and it becomes heavier/more expensive.

I’m not certain how to modify this so it generates not only hills but also flat ground and mountains.

Currently just 2 issues.
Too many hills and inefficient nearby chunk loading causing tears in the distance.

(Nothing is wrong with the chunk loading itself, it snaps to positions correctly and does not overlap.)

Help would be very appreciated, looking forward on making this generate more than just grass terrain.

I eventually even want to generate randomly placed houses, cities, roads, etc, maybe even a desert or snow wonderland.


So far I have figured out the current method of loading chunks isn’t so bad after all, but would still like a better method.

The issue I’m stuck at the most is how I would make more flat terrain appear instead of only hills.
And I would like to know where my flat terrain is generated so I know where houses can be placed or even entire cities.

1 Like

A simple way of adding hills and plains is to have another noise function that doesn’t represent height, but “mountanousness”. It should probably have a much lower frequency than your “hill function”, like 1/4 - 1/16 frequency. Multiplying the output of your height function with the output of your mountanousnessfunction will make some areas be multiplied by ~0.1, making the features a lot less intense. This will be the plains part of your map. Some areas will be multiplied by ~0.9, making it almost as intense as your normal height function. When the mountanousnessis ~0.5, you’ve got hilly areas. Since you’re using coherent noise to represent mountanousness, you will get smooth transitions between these “biomes”

1 Like

Thanks, can you actually show how this would be done if you don’t mind?

Is it like doing:

local noise1 = math.noise(x / steepness, seed, z / steepness)
local noise2 = (math.noise(x, seed, z) * noise1) * amplitude

Is this the correct use?

Yes, but you’ll probably get some pretty weird results because the seeds to both noise functions are the same. Ideally the two noise functions should be completely different. Here’s my own implementation, with a helper function for making noise generators with different frequencies and amplitudes:

function noiseGenerator( seed, frequency, amplitude )
	--Returns a function identical to math.noise, except
	--	the coordinates are offset by some seed,
	--	scaled by some frequency, and the result
	--	is scaled by some amplitude

	local seed = seed or math.random(10e6)

	return function( x, y, z )
		return math.noise(
			x * freq,
			y * freq,
			z * freq + seed --offset by some amount, so different generators produce different results
		) * amplitude

--The basis for the height of the terrain
local baseGenerator = noiseGenerator(nil, 1/32, 16)

--Represents the intensity of the terrain features.
--	More intensity means more mountain- like,
--	less intensity means more plains- like.
local mountainousnessGenerator = noiseGenerator(nil, 1/64, 1)

function heightGenerator(x, y, z)
	--The height of the terrain at any coordinate
	return baseGenerator(x, y, z) * mountainousnessGenerator(x, y, z)

--Generate a set of heights for each (x, z) coordinate
for x = 1, 64 do
	for z = 1, 64 do
		local y = heightGenerator(x, z)