Fix river shape in confluences (less sharp riverbeds when a small rivers joins a big one)

Also cleaned and commented the code
This commit is contained in:
Gael-de-Sailly 2022-01-19 17:58:46 +01:00
parent fce6a33818
commit 02f9805507
2 changed files with 51 additions and 44 deletions

View File

@ -46,50 +46,57 @@ local function heightmaps(minp, maxp)
-- = 0: on riverbank -- = 0: on riverbank
-- > 0: inside river -- > 0: inside river
local depth_factors = { local depth_factors = {
r_west - xf, r_west - xf , -- West edge (1)
r_north - zf, r_north - zf , -- North edge (2)
xf - r_east, r_east - (1-xf), -- East edge (3)
zf - r_south, r_south - (1-zf), -- South edge (4)
c_NW-xf-zf, c_NW - xf - zf , -- North-West corner (5)
xf-zf-c_NE, c_NE - (1-xf) - zf , -- North-East corner (6)
xf+zf-c_SE, c_SE - (1-xf) - (1-zf), -- South-East corner (7)
zf-xf-c_SW, c_SW - xf - (1-zf), -- South-West corner (8)
} }
-- Find the maximal depth factor and determine to which river it belongs -- Find the maximal depth factor, which determines to which of the 8 river sections (4 edges + 4 corners) the current point belongs.
local depth_factor_max = 0 -- If imax is still at 0, it means that we are not in a river.
local dpmax = 0
local imax = 0 local imax = 0
for i=1, 8 do for i=1, 8 do
if depth_factors[i] > depth_factor_max then if depth_factors[i] > dpmax then
depth_factor_max = depth_factors[i] dpmax = depth_factors[i]
imax = i imax = i
end end
end end
-- Transform the coordinates to have xf and zf = 0 or 1 in rivers (to avoid rivers having lateral slope and to accomodate the surrounding smoothly) -- Transform the coordinates to have xfc and zfc = 0 or 1 in rivers (to avoid rivers having lateral slope and to accomodate the riverbanks smoothly)
if imax == 0 then local xfc, zfc
local x0 = max(r_west, c_NW-zf, zf-c_SW) -- xfc:
local x1 = min(r_east, c_NE+zf, c_SE-zf) if imax == 0 or imax == 2 or imax == 4 then -- river segment does not constrain X coordinate, so accomodate xf in function of other river sections
local z0 = max(r_north, c_NW-xf, xf-c_NE) local x0 = max(r_west-dpmax, c_NW-zf-dpmax, c_SW-(1-zf)-dpmax, 0) -- new xf will be bounded to 0 by western riverbank
local z1 = min(r_south, c_SW+xf, c_SE-xf) local x1 = 1-max(r_east-dpmax, c_NE-zf-dpmax, c_SE-(1-zf)-dpmax, 0) -- and bounded to 1 by eastern riverbank
xf = (xf-x0) / (x1-x0) if x0 >= x1 then
zf = (zf-z0) / (z1-z0) xfc = 0.5
elseif imax == 1 then else
xf = 0 xfc = (xf-x0) / (x1-x0)
elseif imax == 2 then end
zf = 0 elseif imax == 1 or imax == 5 or imax == 8 then -- river at the western side of the polygon
elseif imax == 3 then xfc = 0
xf = 1 else -- 3, 6, 7 : river at the eastern side of the polygon
elseif imax == 4 then xfc = 1
zf = 1 end
elseif imax == 5 then
xf, zf = 0, 0 -- Same for zfc:
elseif imax == 6 then if imax == 0 or imax == 1 or imax == 3 then -- river segment does not constrain Z coordinate, so accomodate zf in function of other river sections
xf, zf = 1, 0 local z0 = max(r_north-dpmax, c_NW-xf-dpmax, c_NE-(1-xf)-dpmax, 0) -- new zf will be bounded to 0 by northern riverbank
elseif imax == 7 then local z1 = 1-max(r_south-dpmax, c_SW-xf-dpmax, c_SE-(1-xf)-dpmax, 0) -- and bounded to 1 by southern riverbank
xf, zf = 1, 1 if z0 >= z1 then
elseif imax == 8 then zfc = 0.5
xf, zf = 0, 1 else
zfc = (zf-z0) / (z1-z0)
end
elseif imax == 2 or imax == 5 or imax == 6 then -- river at the northern side of the polygon
zfc = 0
else -- 4, 7, 8 : river at the southern side of the polygon
zfc = 1
end end
-- Determine elevation by interpolation -- Determine elevation by interpolation
@ -99,12 +106,12 @@ local function heightmaps(minp, maxp)
vdem[2], vdem[2],
vdem[3], vdem[3],
vdem[4], vdem[4],
xf, zf xfc, zfc
)) ))
-- Spatial gradient of the interpolation -- Spatial gradient of the interpolation
local slope_x = zf*(vdem[3]-vdem[4]) + (1-zf)*(vdem[2]-vdem[1]) < 0 local slope_x = zfc*(vdem[3]-vdem[4]) + (1-zfc)*(vdem[2]-vdem[1]) < 0
local slope_z = xf*(vdem[3]-vdem[2]) + (1-xf)*(vdem[4]-vdem[1]) < 0 local slope_z = xfc*(vdem[3]-vdem[2]) + (1-xfc)*(vdem[4]-vdem[1]) < 0
local lake_id = 0 local lake_id = 0
if slope_x then if slope_x then
if slope_z then if slope_z then
@ -121,8 +128,8 @@ local function heightmaps(minp, maxp)
end end
local lake_height = max(floor(poly.lake[lake_id]), terrain_height) local lake_height = max(floor(poly.lake[lake_id]), terrain_height)
if imax > 0 and depth_factor_max > 0 then if imax > 0 and dpmax > 0 then
terrain_height = min(max(lake_height, sea_level) - floor(1+depth_factor_max*riverbed_slope), terrain_height) terrain_height = min(max(lake_height, sea_level) - floor(1+dpmax*riverbed_slope), terrain_height)
end end
terrain_height_map[i] = terrain_height terrain_height_map[i] = terrain_height

View File

@ -236,15 +236,15 @@ local function make_polygons(minp, maxp)
end end
end end
polygon.river_corners = {riverA, 1-riverB, 2-riverC, 1-riverD} polygon.river_corners = {riverA, riverB, riverC, riverD}
-- Flow directions -- Flow directions
local dirA, dirB, dirC, dirD = dirs[iA], dirs[iB], dirs[iC], dirs[iD] local dirA, dirB, dirC, dirD = dirs[iA], dirs[iB], dirs[iC], dirs[iD]
-- Determine the river flux on the edges, by testing dirs values -- Determine the river flux on the edges, by testing dirs values
local river_west = (dirA==1 and riverA or 0) + (dirD==3 and riverD or 0) local river_west = (dirA==1 and riverA or 0) + (dirD==3 and riverD or 0)
local river_north = (dirA==2 and riverA or 0) + (dirB==4 and riverB or 0) local river_north = (dirA==2 and riverA or 0) + (dirB==4 and riverB or 0)
local river_east = 1 - (dirB==1 and riverB or 0) - (dirC==3 and riverC or 0) local river_east = (dirB==1 and riverB or 0) + (dirC==3 and riverC or 0)
local river_south = 1 - (dirD==2 and riverD or 0) - (dirC==4 and riverC or 0) local river_south = (dirD==2 and riverD or 0) + (dirC==4 and riverC or 0)
polygon.rivers = {river_west, river_north, river_east, river_south} polygon.rivers = {river_west, river_north, river_east, river_south}
end end