How to improve my terrain generation module

local TERRAIN_HEIGHT_COLORS = {
	[-100] = Color3.fromRGB(216, 204, 157); -- sand yellow
	[-50] = Color3.fromRGB(72, 113, 58); -- grassy green
	[0] = Color3.fromRGB(72, 113, 58); -- grassy green
	[75] = Color3.fromRGB(227, 240, 255); -- stone grey mountain
}
local X, Z = 4, 4
local WIDTH_SCALE = 15
local HEIGHT_SCALE = 100
local TERRAIN_SMOOTHNESS = 50
local MIN_TREE_SPAWN_HEIGHT = -20
local MAX_TREE_SPAWN_HEIGHT = 20
local TREE_DENSITY = 2
local MODEL_DENSITY = .1
local MODEL_DENSITY = 100000000
local SEED = workspace.SEED.Value

local wedge = Instance.new("WedgePart");
wedge.Anchored = true;
wedge.TopSurface = Enum.SurfaceType.Smooth;
wedge.BottomSurface = Enum.SurfaceType.Smooth;

local function draw3dTriangle(a, b, c)
	local ab, ac, bc = b - a, c - a, c - b;
	local abd, acd, bcd = ab:Dot(ab), ac:Dot(ac), bc:Dot(bc);

	if (abd > acd and abd > bcd) then
		c, a = a, c;
	elseif (acd > bcd and acd > abd) then
		a, b = b, a;
	end

	ab, ac, bc = b - a, c - a, c - b;

	local right = ac:Cross(ab).unit;
	local up = bc:Cross(right).unit;
	local back = bc.unit;

	local height = math.abs(ab:Dot(up));

	local w1 = wedge:Clone();
	w1.Size = Vector3.new(0, height, math.abs(ab:Dot(back)));
	w1.CFrame = CFrame.fromMatrix((a + b)/2, right, up, back);
	w1.Parent = workspace;

	local w2 = wedge:Clone();
	w2.Size = Vector3.new(0, height, math.abs(ac:Dot(back)));
	w2.CFrame = CFrame.fromMatrix((a + c)/2, -right, up, -back);
	w2.Parent = workspace;

	return w1, w2;
end

local function getHeight(chunkPosX, chunkPosZ, x, z)
	local height = math.noise(
		(X/TERRAIN_SMOOTHNESS * chunkPosX) + x/TERRAIN_SMOOTHNESS,
		(Z/TERRAIN_SMOOTHNESS * chunkPosZ) + z/TERRAIN_SMOOTHNESS,
		SEED
	) * HEIGHT_SCALE

	if height > 20 then
		local difference = height - 20
		height += (difference * 1.2)
	end

	if height < -20 then
		local difference = height - -20
		height += (difference * 1.2)
	end

	return height
end

local function getPosition(chunkPosX, chunkPosZ, x, z)
	return Vector3.new(
		chunkPosX*X*WIDTH_SCALE + x*WIDTH_SCALE,
		getHeight(chunkPosX, chunkPosZ, x, z),
		chunkPosZ*Z*WIDTH_SCALE + z*WIDTH_SCALE
	)
end

local function paintWedge(wedge)
	local wedgeHeight = wedge.Position.Y

	local color
	local lowerColorHeight
	local higherColorHeight

	for height, heightColor in pairs(TERRAIN_HEIGHT_COLORS) do
		if wedgeHeight == height then
			color = heightColor
			break
		end

		if (wedgeHeight < height) and (not higherColorHeight or height < higherColorHeight) then
			higherColorHeight = height
		end

		if (wedgeHeight > height) and (not lowerColorHeight or height > lowerColorHeight) then
			lowerColorHeight = height
		end
	end

	if not color then
		if higherColorHeight == nil then
			color = TERRAIN_HEIGHT_COLORS[lowerColorHeight]
		elseif lowerColorHeight == nil then
			color = TERRAIN_HEIGHT_COLORS[higherColorHeight]
		else
			local alpha = (wedgeHeight - lowerColorHeight) / (higherColorHeight - lowerColorHeight)
			local lowerColor = TERRAIN_HEIGHT_COLORS[lowerColorHeight]
			local higherColor = TERRAIN_HEIGHT_COLORS[higherColorHeight]

			color = lowerColor:lerp(higherColor, alpha)
		end
	end

	wedge.Material = Enum.Material.Grass
	wedge.Color = color
end








local function addWater(chunk)
	local cframe = CFrame.new(
		(chunk.x + .5) * chunk.WIDTH_SIZE_X,
		-70,
		(chunk.z + .5) * chunk.WIDTH_SIZE_Z
	)

	local size = Vector3.new(
		chunk.WIDTH_SIZE_X,
		20,
		chunk.WIDTH_SIZE_Z
	)

	workspace.Terrain:FillBlock(cframe, size, Enum.Material.Water)

	chunk.waterCFrame = cframe
	chunk.waterSize = size
end

local function addTrees(chunk)
	local posGrid = chunk.positionGrid
	local instances = chunk.instances
	local chunkPosX = chunk.x
	local chunkPosZ = chunk.z

	for x = 0, X-1 do
		for z = 0, Z-1 do
			local pos = posGrid[x][z]

			if pos.Y >= MIN_TREE_SPAWN_HEIGHT and pos.Y <= MAX_TREE_SPAWN_HEIGHT then
				local random = math.random(1, 5)
				math.randomseed(x * (chunkPosX+SEED) + z * (chunkPosZ+SEED))
				if random < TREE_DENSITY then
					local tree = game.ReplicatedStorage.Tree:Clone()
					local cframe = CFrame.new(pos)
						* CFrame.new(
							math.random() * math.random(-10, 10),
							0,
							math.random() * math.random(-10, 10)
						)
						* CFrame.Angles(0, 2 * math.pi * math.random(), 0)

					tree:SetPrimaryPartCFrame(cframe)
					tree.Parent = workspace

					table.insert(instances, tree)
				end

			end
		end
	end
end

local function addModels(chunk)
	local posGrid = chunk.positionGrid
	local instances = chunk.instances
	local chunkPosX = chunk.x
	local chunkPosZ = chunk.z

	for x = 0, X-1 do
		for z = 0, Z-1 do
			local pos = posGrid[x][z]

			if pos.Y >= MIN_TREE_SPAWN_HEIGHT and pos.Y <= MAX_TREE_SPAWN_HEIGHT then
				local random = math.random()
				math.randomseed(x * (chunkPosX+SEED) + z * (chunkPosZ+SEED))
				if random < MODEL_DENSITY then
					local tree = game.ReplicatedStorage.Camp:Clone()
					print(random)
					local cframe = CFrame.new(pos)
						* CFrame.new(
							math.random() * math.random(-10, 10),
							0,
							math.random() * math.random(-10, 10)
						)
						* CFrame.Angles(0, 2 * math.pi * math.random(), 0)

					tree:SetPrimaryPartCFrame(cframe)
					tree.Parent = workspace

					table.insert(instances, tree)
				end

			end
		end
	end
end

local Chunk = {}
Chunk.__index = Chunk

Chunk.WIDTH_SIZE_X = X * WIDTH_SCALE
Chunk.WIDTH_SIZE_Z = Z * WIDTH_SCALE

function Chunk.new(chunkPosX, chunkPosZ)
	local chunk = {
		instances = {};
		positionGrid = {};
		x = chunkPosX;
		z = chunkPosZ;
	}

	setmetatable(chunk, Chunk)

	local positionGrid = chunk.positionGrid

	for x = 0, X do
		positionGrid[x] = {}

		for z = 0, Z do
			positionGrid[x][z] = getPosition(chunkPosX, chunkPosZ, x, z)
		end
	end

	for x = 0, X-1 do
		for z = 0, Z-1 do
			local a = positionGrid[x][z]
			local b = positionGrid[x+1][z]
			local c = positionGrid[x][z+1]
			local d = positionGrid[x+1][z+1]

			local wedgeA, wedgeB = draw3dTriangle(a, b, c)
			local wedgeC, wedgeD = draw3dTriangle(b, c, d)

			paintWedge(wedgeA)
			paintWedge(wedgeB)
			paintWedge(wedgeC)
			paintWedge(wedgeD)

			table.insert(chunk.instances, wedgeA)
			table.insert(chunk.instances, wedgeB)
			table.insert(chunk.instances, wedgeC)
			table.insert(chunk.instances, wedgeD)
		end
	end

	addWater(chunk)
	addTrees(chunk)
	addModels(chunk)
	return chunk
end

function Chunk:Destroy()
	for index, instance in ipairs(self.instances) do
		instance:Destroy()
	end

	workspace.Terrain:FillBlock(self.waterCFrame, self.waterSize, Enum.Material.Air)
end

return Chunk

This is my chunk generation module script

1 Like