local DEFAULT, RIDGED, BILLOWED = 1, 2, 3 local LINEAR, EXPONENTIAL, SIGMOID = 1, 2, 3 local function CalculateNoise(params) -- Unpack parameters with default values local gradientStrength = params.gradientStrength or 0 local worldx = params.worldx local worldy = params.worldy local worldz = params.worldz or 0 local seed = params.seed or 0 local octaves = params.octaves or 4 local scale = params.scale or 100 local noiseType = params.noiseType or DEFAULT local amplitudeFunction = params.amplitudeFunction or LINEAR local persistance = params.persistance or 0.5 local lacunarity = params.lacunarity or 2 local amplitude = 1 local frequency = 1 local noiseHeight = 0 local offset = 0.1 -- Small offset local noisex = (worldx + offset) / scale local noisey = (worldy + offset) / scale local noisez = (worldz + offset) / scale + (seed * 1000) for i = 1, octaves do --[[ Get noise value and derivatives Not really analytical derivatives, but just simple slope calculation Erosion is faked by reducing the influence of layers based on steepness --]] local nx = noisex * frequency local ny = noisey * frequency local nz = noisez * frequency local noise,derivativeX,derivativeY = nil,nil,nil local function noiseFunction(x,y,z) -- Calls math.noise which returns a value from -1 to 1, we want it from 0 to 1 though local val = math.noise(x,y,z) val = (val + 1) / 2 return val end local h = 1e-4 -- smoll value -- Compute noise at (nx, ny, nz) noise = noiseFunction(nx,ny,nz) -- Compute noise at (nx + h, ny, nz) local noise_x1 = noiseFunction(nx + h, ny, nz) -- Compute noise at (nx - h, ny, nz) local noise_x2 = noiseFunction(nx - h, ny, nz) derivativeX = (noise_x1 - noise_x2) / (2 * h) -- Compute noise at (nx, ny + h, nz) local noise_y1 = noiseFunction(nx, ny + h, nz) -- Compute noise at (nx, ny - h, nz) local noise_y2 = noiseFunction(nx, ny - h, nz) derivativeY = (noise_y1 - noise_y2) / (2 * h) local gradMagnitude = math.sqrt(derivativeX * derivativeX + derivativeY * derivativeY) local gradientMult = 1 if amplitudeFunction == LINEAR then gradientMult = 1 / (1 + gradientStrength * gradMagnitude) else gradientMult = math.exp(-gradientStrength * gradMagnitude ^ 2) end -- Accumulate noise contribution noiseHeight = noiseHeight + noise * amplitude amplitude = amplitude * persistance * gradientMult frequency = frequency * lacunarity end -- Adjust noise based on the selected noise type if noiseType == RIDGED then noiseHeight = 1 - math.abs(noiseHeight) elseif noiseType == BILLOWED then noiseHeight = math.abs(noiseHeight) end local minHeight = 0 noiseHeight = math.max(noiseHeight, minHeight) return noiseHeight end local Noise = CalculateNoise -- Use noise to warp input coordinates local function Warp(x,y,seed,factor) local warpOctaves = 2 local warpScale = 200 local noise1 = Noise{ gradientStrength = 0, worldx = x, worldy = y, seed = seed + 1000, octaves = warpOctaves, scale = warpScale } local noise2 = Noise{ gradientStrength = 0, worldx = x, worldy = y, seed = seed + 2000, octaves = warpOctaves, scale = warpScale } local perturbedX = x + factor * noise1 local perturbedY = y + factor * noise2 return perturbedX,perturbedY end -- local function lerp(a, b, t) return a + (b - a) * t end local function ComputeNoise(worldX,worldZ) --[[ Quick temporary thing to make a not super hideous map , not finalized ]] local seed = 2 local scale = 2 local gradientStrength = 1 local warpFactor = 50 local octaves = 6 -- Warped input coordinates, to make some areas more random local warpX,warpY = Warp(worldX,worldZ,seed+1,warpFactor) -- --[[ Medium height rolling hills ]] local hillsNoise = Noise{ noiseType = BILLOWED, gradientStrength = gradientStrength, amplitudeFunction = EXPONENTIAL, worldx = warpX, worldy = warpY, seed = seed + 10, octaves = octaves, scale = 150 * scale } * 0.5 --[[ Low flatter plains ]] local plainsNoise = Noise{ noiseType = DEFAULT, gradientStrength = gradientStrength, amplitudeFunction = EXPONENTIAL, worldx = warpX, worldy = warpY, seed = seed + 3, octaves = octaves, scale = 250 * scale } * 0.1 --[[ Tall ridged mountains ]] local mountainNoise = Noise{ noiseType = RIDGED, gradientStrength = 0, -- Don't perform erosion amplitudeFunction = EXPONENTIAL, worldx = worldX, worldy = worldZ, seed = seed + 2, octaves = octaves, scale = 120 * scale } ^ 2 --[[ Low octave noise map to blend the biomes together ]] local blendMap = Noise{ noiseType = DEFAULT, gradientStrength = 0, -- Don't perform erosion worldx = worldX, worldy = worldZ, seed = seed + 11, octaves = 3, scale = 300 } -- local blend_min = 0.4 local blend_mid = 0.6 local blend_max = 1 local finalValue = 0 if blendMap < blend_min then finalValue = plainsNoise elseif blendMap < blend_mid then local blendFactor = (blendMap - blend_min) / (blend_mid - blend_min) finalValue = lerp(plainsNoise, hillsNoise, blendFactor) elseif blendMap < blend_max then local blendFactor = (blendMap - blend_mid) / (blend_max - blend_mid) finalValue = lerp(hillsNoise, mountainNoise, blendFactor) end return finalValue end --[[ Erosion stuff worked fine when I just had ComputeNoise return this local finalValue = Noise{ noiseType = DEFAULT, amplitudeFunction = EXPONENTIAL, gradientStrength = gradientStrength, worldx = worldX, worldy = worldZ, seed = seed, octaves = 6, scale = 150 } ]] return ComputeNoise