From f066694f734fb0db9183375ec7d211aa07414010 Mon Sep 17 00:00:00 2001 From: Gael-de-Sailly Date: Fri, 21 Sep 2018 22:37:55 +0200 Subject: [PATCH] Rewritten elevation function for spawnplayer It can now adapt to 2D/3D river noise --- init.lua | 2 +- mapgen.lua | 66 ++++++++++++++++++++++++++++++++---------------------- 2 files changed, 40 insertions(+), 28 deletions(-) diff --git a/init.lua b/init.lua index 0582d1c..bfe6704 100644 --- a/init.lua +++ b/init.lua @@ -53,7 +53,7 @@ function pos3d(pos, alt) if type(pos) == "number" then return {x = pos, y = pos, z = pos} elseif pos.z then - return {x = pos.x, y = pos.z, z = pos.z} + return {x = pos.x, y = pos.y, z = pos.z} else return {x = pos.x, y = alt, z = pos.y} end diff --git a/mapgen.lua b/mapgen.lua index 10d5fa9..a1d71a8 100644 --- a/mapgen.lua +++ b/mapgen.lua @@ -152,6 +152,7 @@ end -- river: whether there is a river here -- This function is executed for every vertical row in the case of 2D noise rivers, and for every node for 3D noise rivers. It allows local function calculate_terrain_at_point(base_ground, v2, v3, v4, v5) + v2 = math.abs(v2) - river_size -- v2 is distance from a river, so I'd like a positive value. local river = v2 < 0 -- the rivers are placed where v2 is negative, so where the original v2 value is close to zero. local valleys = v3 * (1 - math.exp(- (v2 / v4) ^ 2)) -- use the curve of the function 1−exp(−(x/a)²) to modelise valleys. Making "a" varying 0 < a ≤ 1 changes the shape of the valleys. Try it with a geometry software ! (here x = v2 and a = v4). This variable represents the height of the terrain, from the rivers. local mountain_ground = base_ground + valleys -- approximate height of the terrain at this point (could be slightly modified by the 3D noise #6) @@ -165,7 +166,7 @@ local function calculate_terrain_at_point(base_ground, v2, v3, v4, v5) slopes = 0 -- noise #6 has not any influence on rivers end - return mountain_ground, slopes, river + return mountain_ground, slopes, river, v2 end local data = {} @@ -326,8 +327,8 @@ function vmg.generate(minp, maxp, seed) local v2, mountain_ground, slopes, river if not use_3d_rivers then - v2 = math.abs(n2[i2d]) - river_size -- v2 is distance from a river, so I'd like a positive value. - mountain_ground, slopes, river = calculate_terrain_at_point(base_ground, v2, v3, v4, v5) + v2 = n2[i2d] + mountain_ground, slopes, river, v2 = calculate_terrain_at_point(base_ground, v2, v3, v4, v5) end -- Choose biome, by default normal dirt @@ -394,8 +395,8 @@ function vmg.generate(minp, maxp, seed) local v8, v9, v10, v11, v12 if use_3d_rivers then - v2 = math.abs(n2[i3d_sup]) - river_size - mountain_ground, slopes, river = calculate_terrain_at_point(base_ground, v2, v3, v4, v5) + v2 = n2[i3d_sup] + mountain_ground, slopes, river, v2 = calculate_terrain_at_point(base_ground, v2, v3, v4, v5) end local in_ground = v6 * slopes > y - mountain_ground @@ -753,33 +754,44 @@ end function vmg.get_elevation(pos) local v1 = vmg.get_noise(pos, 1) -- base ground - local v2 = math.abs(vmg.get_noise(pos, 2)) - river_size -- valleys + local v2, mountain_ground, slopes, river local v3 = vmg.get_noise(pos, 3) ^ 2 -- valleys depth - local base_ground = v1 + v3 - if v2 < 0 then -- river - return math.ceil(base_ground), true - end local v4 = vmg.get_noise(pos, 4) -- valleys profile local v5 = vmg.get_noise(pos, 5) -- inter-valleys slopes - -- Same calculation than in vmg.generate + local base_ground = v1 + v3 - local valleys = v3 * (1 - math.exp(- (v2 / v4) ^ 2)) - local mountain_ground = base_ground + valleys - local pos = pos3d(pos, round(mountain_ground)) -- For now we don't know the elevation. We will test some y values. Set the position to montain_ground which is the most probable value. - local slopes = v5 * valleys - if vmg.get_noise(pos, 6) * slopes > pos.y - mountain_ground then -- Position is in the ground, so look for air higher - pos.y = pos.y + 1 - while vmg.get_noise(pos, 6) * slopes > pos.y - mountain_ground do - pos.y = pos.y + 1 - end -- End of the loop when there is air - return pos.y, false -- Return position of the first air node, and false because that's not a river + local epos = pos3d(pos, math.ceil(base_ground)) -- Position with elevation (3D) + v2 = vmg.get_noise(use_3d_rivers and epos or pos, 2) -- Use 2D or 3D position according to use_3d_rivers + + mountain_ground, slopes, river = calculate_terrain_at_point(base_ground, v2, v3, v4, v5) -- Calculate terrain parameters + if river then + return math.ceil(base_ground), true + end + + epos = pos3d(pos, math.ceil(mountain_ground)) -- set epos to mountain_ground (most probable ground level) to optimize + if use_3d_rivers then + v2 = vmg.get_noise(epos, 2) + mountain_ground, slopes, river = calculate_terrain_at_point(base_ground, v2, v3, v4, v5) -- Recalculate + end + + if vmg.get_noise(epos, 6) * slopes > epos.y - mountain_ground then -- Position is in the ground, so look for air higher + repeat + epos.y = epos.y + 1 + if use_3d_rivers then + v2 = vmg.get_noise(epos, 2) + mountain_ground, slopes, river = calculate_terrain_at_point(base_ground, v2, v3, v4, v5) + end + until vmg.get_noise(epos, 6) * slopes <= epos.y - mountain_ground -- End of the loop when there is air + return epos.y, river -- Return position of the first air node else -- Position is not in the ground, so look for dirt lower - pos.y = pos.y - 1 - while vmg.get_noise(pos, 6) * slopes <= pos.y - mountain_ground do - pos.y = pos.y - 1 - end -- End of the loop when there is dirt (or any ground) - pos.y = pos.y + 1 -- We have the latest dirt node and we want the first air node that is just above - return pos.y, false -- Return position of the first air node, and false because that's not a river + repeat + epos.y = epos.y - 1 + if use_3d_rivers then + v2 = vmg.get_noise(epos, 2) + mountain_ground, slopes, river = calculate_terrain_at_point(base_ground, v2, v3, v4, v5) + end + until vmg.get_noise(epos, 6) * slopes > epos.y - mountain_ground -- End of the loop when there is dirt (or any ground) + return epos.y+1, river -- Return position of the first air node end end