Scripting Helpers is winding down operations and is now read-only. More info→
Ad
Log in to vote
0

How can I make this noise method more efficient?

Asked by 4 years ago
Edited 4 years ago

I am doing terrain generation on a chunk by chunk basis and I have converted a module for Cellular Noise in order to do cave generation, but my problem is that it is quite slow on a large scale, a large scale being about 256 times per second. So if someone could help me make this more efficient that would mean a great ordeal!

The main noise method:

function CellularNoise.noise(x, y, z)
    local x = x or 0
    local y = y or 0
    local z = z or 0

    local input = Vector3.new(x, y, z)

    local lastRandom, numPoints = 0, 0
    local randomDiff, featurePoint = Vector3.new()
    local cubeX, cubeY, cubeZ = 0, 0, 0

    local noiseArray = {6666}

    local evalCubeX = math.floor(x)
    local evalCubeY = math.floor(y)
    local evalCubeZ = math.floor(z)

    for i = -1, 1 do
        wait() -- I don't really like having this here as it slows down generation greatly, I want an alternative, the best would be more efficient calculations.
        for j = -1, 1 do
            for k = -1, 1 do
                cubeX = evalCubeX + i
                cubeY = evalCubeY + j
                cubeZ = evalCubeZ + k

                lastRandom = lcgRandom(hash(cubeX, cubeY, cubeZ))
                numPoints = probLookup(lastRandom)

                for l = 1, numPoints do
                    lastRandom = lcgRandom(lastRandom)
                    randomDiff = randomDiff * Vector3.new(0, 1, 1) + Vector3.new(lastRandom / 0x100000000, 0, 0)

                    lastRandom = lcgRandom(lastRandom)
                    randomDiff = randomDiff * Vector3.new(1, 0, 1) + Vector3.new(0, lastRandom / 0x100000000, 0)

                    lastRandom = lcgRandom(lastRandom)
                    randomDiff = randomDiff * Vector3.new(1, 1, 0) + Vector3.new(0, 0, lastRandom / 0x100000000)

                    featurePoint = Vector3.new(randomDiff.X + cubeX, randomDiff.Y + cubeY, randomDiff.Z + cubeZ)

                    insert(noiseArray, math.clamp((featurePoint - input).Magnitude * 2, 0, 1))
                end
            end
        end
    end

    return noiseArray[1]
end

Other methods used:

-- linear congruential generator
local function lcgRandom(lastValue)
    return math.floor((110351245 * lastValue + 12345) % 0x100000000)
end

local OFFSET_BASIS = 2166136261
local FNV_PRIME = 16777619

-- FNV hash
local function hash(i, j, k)
    return bit.bxor(bit.bxor(bit.bxor(OFFSET_BASIS, i) * FNV_PRIME, j) * FNV_PRIME, k) * FNV_PRIME
end

-- possion distribution
local function probLookup(value)
    if value < 393325350 then return 1 end
    if value < 1022645910 then return 2 end
    if value < 1861739990 then return 3 end
    if value < 2700834071 then return 4 end
    if value < 3372109335 then return 5 end
    if value < 3819626178 then return 6 end
    if value < 4075350088 then return 7 end
    if value < 4203212043 then return 8 end
    return 9
end

-- insertion sort
local function insert(arr, value)
    local temp, l = 0, #arr
    for i=l, 1, -1 do
        if value > arr[i] then break end
        temp = arr[i]
        arr[i] = value
        if (i+1 < l) then arr[i+1] = temp end
    end
end

Any help would be great! Thanks.

0
why don't u use Perlin noise? (math.noise()) Luka_Gaming07 534 — 4y
0
this is for cave generation https://love2d.org/forums/viewtopic.php?t=78266 however I feel the code either doesn't do what it says, or I am using it wrong, because currently I am just getting consecutive circles SynthetickDev 188 — 4y
0
perlin isn't the best for caves SynthetickDev 188 — 4y

Answer this question