While I have been able to use perlin noise to create terrain as in the image below, I am struggling to think how I can apply it to an island in a 3D format.
local Players = game:GetService("Players")
------------------------------------------------------------------------------------------------------------------------------------------------
local BASE_HEIGHT = 10 -- The main height factor for the terrain.
local CHUNK_SCALE = 3 -- The grid scale for terrain generation. Should be kept relatively low if used in real-time.
local RENDER_DISTANCE = 120 / 4 -- The length/width of chunks in voxels that should be around the player at all times
local X_SCALE = 90 / 4 -- How much we should strech the X scale of the generation noise
local Z_SCALE = 90 / 4 -- How much we should strech the Z scale of the generation noise
local GENERATION_SEED = math.random() -- Seed for determining the main height map of the terrain.
------------------------------------------------------------------------------------------------------------------------------------------------
local chunks = {}
local function chunkExists(chunkX, chunkZ)
if not chunks[chunkX] then
chunks[chunkX] = {}
end
return chunks[chunkX][chunkZ]
end
local function mountLayer(x, heightY, z, material)
local beginY = -BASE_HEIGHT
local endY = heightY
local cframe = CFrame.new(x * 4 + 2, (beginY + endY) * 4 / 2, z * 4 + 2)
local size = Vector3.new(4, (endY - beginY) * 4, 4)
workspace.Terrain:FillBlock(cframe, size, material)
end
function makeChunk(chunkX, chunkZ)
local rootPosition = Vector3.new(chunkX * CHUNK_SCALE, 0, chunkZ * CHUNK_SCALE)
chunks[chunkX][chunkZ] = true -- Acknowledge the chunk's existance.
for x = 0, CHUNK_SCALE - 1 do
for z = 0, CHUNK_SCALE - 1 do
local cx = (chunkX * CHUNK_SCALE) + x
local cz = (chunkZ * CHUNK_SCALE) + z
local noise = math.noise(GENERATION_SEED, cx / X_SCALE, cz / Z_SCALE)
local cy = noise * BASE_HEIGHT
if cy <= 0 then return end
mountLayer(cx, cy, cz, Enum.Material.Grass)
end
end
end
function checkSurroundings(location)
local chunkX, chunkZ = math.floor(location.X / 4 / CHUNK_SCALE), math.floor(location.Z / 4 / CHUNK_SCALE)
local range = math.max(1, RENDER_DISTANCE / CHUNK_SCALE)
for x = -range, range do
for z = -range, range do
local cx, cz = chunkX + x
local cz = chunkZ + z
if not chunkExists(cx, cz) then
makeChunk(cx, cz)
end
end
end
end
while true do
for _, player in pairs(Players:GetPlayers()) do
if player.Character then
local humanoidRootPart = player.Character:FindFirstChild("HumanoidRootPart")
if humanoidRootPart then
checkSurroundings(humanoidRootPart.Position)
end
end
end
wait(1)
end
local function sineEase(val)
return math.sin(val * math.pi / 2)
end
local function cosEase(val)
return 1 - math.cos(val * math.pi / 2)
end
-- input values between -1 and 1, output value between 0 and 1
function CircularGrayscale.GetVal(xScale, yScale)
xScale, yScale = math.abs(xScale), math.abs(yScale)
local squaredDistToEdgeInXZDir = 1 + math.min(xScale, yScale)^2
local linear = 1 - math.sqrt( (xScale^2 + yScale^2) / squaredDistToEdgeInXZDir )
local val = linear ^ squaredDistToEdgeInXZDir
--val = sineEase(val)
--val = cosEase(val)
return val
end
return CircularGrayscale
The code is not mine you basically get the vale from this module script and add it with perlin 2d then you add 3d perlin
For the elevations would you just generate based on the noise value or some other method?
For example, height in this coordinate = math.Perlin(x,z, seed) * 30.
height in this coordinate = math.Perlin(x,z, seed) * 30 + CircularGrayscale.GetVal(x, z) this will allow for the heightmap, Also remember to posibly modify the function to make it accepts size value
Modified code for my plugin although i recommend you to modify it to work with no value in workspace
local CircularGrayscale = {}
local function sineEase(val)
return math.sin(val * math.pi / 2)
end
local function cosEase(val)
return 1 - math.cos(val * math.pi / 2)
end
-- input values between -1 and 1, output value between 0 and 1
function CircularGrayscale.applyGradient(voronoipart, x, z,heightMapSize)
if heightMapSize == nil then
heightMapSize = workspace:WaitForChild("Voronoi"):WaitForChild("Size").Value
end
local voronoiPos = voronoipart.Position
local distance_x = math.abs(x - voronoiPos.X * 0.5)
local distance_y = math.abs(z - voronoiPos.Z * 0.5)
local distance = math.sqrt(distance_x*distance_x + distance_y*distance_y)
local max_width = heightMapSize * 0.5 - 10.0
local delta = distance / max_width
local gradient = delta * delta
if voronoipart:FindFirstChild("Multiplyer") then
return math.max(0.0, 1.0 - gradient)*voronoipart:FindFirstChild("Multiplyer").Value
else
return math.max(0.0, 1.0 - gradient)*workspace:WaitForChild("Voronoi"):WaitForChild("Multiplyer").Value
end
end
return CircularGrayscale