-
I would like to generate random terrain via a server script and Perlin noise. I already have a system in place, but it is rather steppy- or blocky-looking.
-
My issue is that I cannot get the terrain to look smooth when generated. This image shows the steppy nature of the terrain. I believe this is caused by the terrain being locked to a 4x4x4 grid.
- I’ve tried a few methods to try to smooth out the terrain:
a) I originally used the Terrain:FillBlock method
b) I added the Terrain:FillBall method on top of the FillBlock column; didn’t really change anything.
c) I then went through a more complicated approach by using the Terrain:WriteVoxels method so that I could manipulate the “occupancy” parameter. The thought was that by using the same noise value that decided the Y position, I could calculate the occupancy of that particular 4x4x4 grid section of terrain, with the hopes that it would smooth these edges out. It actually made it worse somehow.
Terrain:WriteVoxels()
If there are better ways to generate smooth terrain, I’d love to hear how. Any help would be greatly appreciated!
Here is my entire code, condensed as best as possible.
-- Look how many lines thise code is. Nice. ;)
local mapSizeX = 100
local mapSizeY = 25
local mapSizeZ = 100
local cellSize = 4
local noiseScale = 50
local noiseHeightScale = 100
local terrainGenerationMethod = 2 -- 1 is FillBlock; 2 is WriteVoxels
local function generateNewMap ()
for mapX=1, mapSizeX do
for mapZ=1, mapSizeZ do
-- Uses noise to calculate a cohesively random Y value
local noiseValue = math.noise(mapX/noiseScale, mapZ/noiseScale)
local yPos = noiseValue * noiseHeightScale
local cellCFrame = CFrame.new(mapX*cellSize, yPos, mapZ*cellSize)
-- Terrain - FillBlock method
if terrainGenerationMethod == 1 then
game.Workspace.Terrain:FillBlock(cellCFrame, Vector3.new(cellSize, mapSizeY, cellSize), Enum.Material.Grass)
game.Workspace.Terrain:FillBall(Vector3.new(cellCFrame.Position.X, cellCFrame.Position.Y +
cellSize/2, cellCFrame.Position.Z), cellSize/2, Enum.Material.Grass)
-- Terrain - WriteVoxels method
elseif terrainGenerationMethod == 2 then
local region = Region3.new(Vector3.new(cellCFrame.Position.X - 4, cellCFrame.Position.Y - mapSizeY, cellCFrame.Position.Z - 4),
Vector3.new(cellCFrame.Position.X, cellCFrame.Position.Y, cellCFrame.Position.Z)):ExpandToGrid(4)
local materials = {}
local occupancies = {}
for x=1, 1 do
materials[x] = {}
occupancies[x] = {}
for y=1, region.Size.Y/4 do
materials[x][y] = {}
occupancies[x][y] = {}
for z=1, 1 do
-- materials
materials[x][y][z] = Enum.Material.Grass
-- occupancies
if y < region.Size.Y/4 then -- below top layer
occupancies[x][y][z] = 1
else -- top layer
local occupancy = (noiseValue + 1)/2 -- shifts noise range of (-1 to 1) to occupancy range of (0 to 1)
occupancies[x][y][z] = occupancy
end
end
end
end
game.Workspace.Terrain:WriteVoxels(region, 4, materials, occupancies)
end
end
end
end
generateNewMap()