I want to make it so that first the grass is generated and then the soil from fractal noise, but in the end I get that everything consists of soil.
local TerrainGeneratorService = {}
TerrainGeneratorService.__index = TerrainGeneratorService
local MAP_SIZE = Vector3.new(6144, 0, 6144)
local RESOLUTION = 4
local CHUNK_SIZE = 256
local TERRAIN_LAYERS = {
Grass = 1,
Ground = 2
}
local MATERIAL_LAYERS = {
{
name = "Ground",
noiseScale = 90,
threshold = {-0.5, -0.1},
material = Enum.Material.Ground,
occupancy = 1.0
}
}
function TerrainGeneratorService.new()
local self = setmetatable({}, TerrainGeneratorService)
local seed = math.random(0, os.time())
math.randomseed(seed)
self.services = {
Workspace = game:GetService("Workspace"),
UserInputService = game:GetService("UserInputService")
}
self.terrain = self.services.Workspace.Terrain
self:ConnectEvents()
self:Generate()
return self
end
function TerrainGeneratorService:ConnectEvents()
self.services.UserInputService.InputBegan:Connect(function(input, gameProcessed)
if input.UserInputType == Enum.UserInputType.Keyboard and not gameProcessed then
if input.KeyCode == Enum.KeyCode.N then
self:Generate()
end
end
end)
end
function TerrainGeneratorService:FractalNoise(x, z, octaves, persistence)
local total = 0
local frequency = 1
local amplitude = 1
local maxValue = 0
for _ = 1, octaves do
total = total + math.noise(x * frequency, z * frequency) * amplitude
maxValue += amplitude
amplitude *= persistence
end
return total / maxValue
end
function TerrainGeneratorService:GetMaterial(x, z)
local selectedMaterial = MATERIAL_LAYERS[1].material
local selectedOccupancy = MATERIAL_LAYERS[1].occupancy
local offset = math.random(0, 255)
for _, layer in ipairs(MATERIAL_LAYERS) do
local nx = (x + offset) / layer.noiseScale
local nz = (z + offset) / layer.noiseScale
local noiseValue = self:FractalNoise(nx, nz, 1, 0.5)
if noiseValue > layer.threshold[1] and noiseValue < layer.threshold[2] then
selectedMaterial = layer.material
selectedOccupancy = layer.occupancy
end
end
return selectedMaterial, selectedOccupancy
end
function TerrainGeneratorService:Generate()
local voxelsPerChunk = CHUNK_SIZE / RESOLUTION
for layer, _ in pairs(TERRAIN_LAYERS) do
for x = -MAP_SIZE.X, MAP_SIZE.X, CHUNK_SIZE do
for z = -MAP_SIZE.Z, MAP_SIZE.Z, CHUNK_SIZE do
local materials = {}
local occupancies = {}
for i = 1, voxelsPerChunk do
materials[i] = {}
occupancies[i] = {}
materials[i][1] = {}
occupancies[i][1] = {}
for j = 1, voxelsPerChunk do
if layer == TERRAIN_LAYERS.Grass then
materials[i][1][j] = Enum.Material.Grass
occupancies[i][1][j] = 1.0
else
local material, occupancy = self:GetMaterial(x, z)
materials[i][1][j] = material
occupancies[i][1][j] = occupancy
end
end
end
local minPos = Vector3.new(x, 0, z)
local maxPos = Vector3.new(x + CHUNK_SIZE, 1, z + CHUNK_SIZE)
local region = Region3.new(minPos, maxPos):ExpandToGrid(RESOLUTION)
self.terrain:WriteVoxels(region, RESOLUTION, materials, occupancies)
end
end
end
end
return TerrainGeneratorService