mirror of
https://gitlab.com/gaelysam/mapgen_rivers.git
synced 2024-12-28 03:40:39 +01:00
terrainlib_lua: Hardcode flow_local for performance
as it is unlikely that it will be changed one day. This results in a drastic performance improvement (x4 speed for step 1)
This commit is contained in:
parent
d00295600d
commit
0bc100030c
@ -134,7 +134,7 @@ local rivermapper = dofile(modpath .. "rivermapper.lua")
|
||||
local gaussian = dofile(modpath .. "gaussian.lua")
|
||||
|
||||
local function flow(model)
|
||||
model.dirs, model.lakes = rivermapper.flow_routing(model.dem, model.dirs, model.lakes, 'semirandom')
|
||||
model.dirs, model.lakes = rivermapper.flow_routing(model.dem, model.dirs, model.lakes)
|
||||
model.rivers = rivermapper.accumulate(model.dirs, model.rivers)
|
||||
end
|
||||
|
||||
|
@ -10,50 +10,18 @@
|
||||
-- Big thanks to them for releasing this paper under a free license ! :)
|
||||
|
||||
-- The algorithm here makes use of most of the paper's concepts, including the Planar Borůvka algorithm.
|
||||
-- Only flow_local and accumulate_flow are custom algorithms.
|
||||
|
||||
|
||||
local function flow_local_semirandom(plist)
|
||||
-- Determines how water should flow at 1 node scale.
|
||||
-- The straightforward approach would be "Water will flow to the lowest of the 4 neighbours", but here water flows to one of the lower neighbours, chosen randomly, but probability depends on height difference.
|
||||
-- This makes rivers better follow the curvature of the topography at large scale, and be less biased by pure N/E/S/W directions.
|
||||
-- 'plist': array of downward height differences (0 if upward)
|
||||
local sum = 0
|
||||
for i=1, #plist do
|
||||
sum = sum + plist[i] -- Sum of probabilities
|
||||
end
|
||||
|
||||
if sum == 0 then
|
||||
return 0
|
||||
end
|
||||
local r = math.random() * sum
|
||||
for i=1, #plist do
|
||||
local p = plist[i]
|
||||
if r < p then
|
||||
return i
|
||||
end
|
||||
r = r - p
|
||||
end
|
||||
return 0
|
||||
end
|
||||
|
||||
-- Maybe implement more flow methods in the future?
|
||||
local flow_methods = {
|
||||
semirandom = flow_local_semirandom,
|
||||
}
|
||||
|
||||
-- Applies all steps of the flow routing, to calculate flow direction for every node, and lake surface elevation.
|
||||
-- It's quite a hard piece of code, but we will go step by step and explain what's going on, so stay with me and... let's goooooooo!
|
||||
local function flow_routing(dem, dirs, lakes, method) -- 'dirs' and 'lakes' are optional tables to reuse for memory optimization, they may contain any data.
|
||||
method = method or 'semirandom'
|
||||
local flow_local = flow_methods[method] or flow_local_semirandom
|
||||
|
||||
local function flow_routing(dem, dirs, lakes) -- 'dirs' and 'lakes' are optional tables to reuse for memory optimization, they may contain any data.
|
||||
dirs = dirs or {}
|
||||
lakes = lakes or {}
|
||||
|
||||
-- Localize for performance
|
||||
local tremove = table.remove
|
||||
local mmax = math.max
|
||||
local mrand = math.random
|
||||
|
||||
local X, Y = dem.X, dem.Y
|
||||
dirs.X = X
|
||||
@ -74,14 +42,29 @@ local function flow_routing(dem, dirs, lakes, method) -- 'dirs' and 'lakes' are
|
||||
for y=1, Y do
|
||||
for x=1, X do
|
||||
local zi = dem[i]
|
||||
local plist = { -- Get the height difference of the 4 neighbours (and 0 if uphill)
|
||||
y<Y and mmax(zi-dem[i+X], 0) or 0, -- Southward
|
||||
x<X and mmax(zi-dem[i+1], 0) or 0, -- Eastward
|
||||
y>1 and mmax(zi-dem[i-X], 0) or 0, -- Northward
|
||||
x>1 and mmax(zi-dem[i-1], 0) or 0, -- Westward
|
||||
}
|
||||
-- Determine how water should flow at 1 node scale.
|
||||
-- The straightforward approach would be "Water will flow to the lowest of the 4 neighbours", but here water flows to one of the lower neighbours, chosen randomly, with probability depending on height difference.
|
||||
-- This makes rivers better follow the curvature of the topography at large scale, and be less biased by pure N/E/S/W directions.
|
||||
local pSouth = y<Y and mmax(zi-dem[i+X], 0) or 0
|
||||
local pEast = x<X and mmax(zi-dem[i+1], 0) or 0
|
||||
local pNorth = y>1 and mmax(zi-dem[i-X], 0) or 0
|
||||
local pWest = x>1 and mmax(zi-dem[i-1], 0) or 0
|
||||
|
||||
local d = 0
|
||||
local sum = pSouth + pEast + pNorth + pWest
|
||||
local r = mrand() * sum
|
||||
if sum > 0 then
|
||||
if r < pSouth then
|
||||
d = 1
|
||||
elseif r-pSouth < pEast then
|
||||
d = 2
|
||||
elseif r-pSouth-pEast < pNorth then
|
||||
d = 3
|
||||
else
|
||||
d = 4
|
||||
end
|
||||
end
|
||||
|
||||
local d = flow_local(plist)
|
||||
-- 'dirs': Direction toward which water flow
|
||||
-- 'dirs2': Directions from which water comes
|
||||
dirs[i] = d
|
||||
@ -438,5 +421,4 @@ end
|
||||
return {
|
||||
flow_routing = flow_routing,
|
||||
accumulate = accumulate,
|
||||
flow_methods = flow_methods,
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user