From 997eb4d1018f7e9087c11f62c505009158519074 Mon Sep 17 00:00:00 2001 From: Starbeamrainbowlabs Date: Fri, 21 Aug 2020 15:21:10 +0100 Subject: [PATCH] fix all the crashes with the new erosion algorithm ......but it doesn't look like it's functioning as intended just yet --- worldeditadditions/lib/erode/erode.lua | 7 ++- worldeditadditions/lib/erode/snowballs.lua | 61 ++++++++++++------- worldeditadditions/utils/strings.lua | 2 +- worldeditadditions/utils/terrain.lua | 14 +++-- .../commands/erode.lua | 4 +- 5 files changed, 54 insertions(+), 34 deletions(-) diff --git a/worldeditadditions/lib/erode/erode.lua b/worldeditadditions/lib/erode/erode.lua index 4e87ffe..5c49784 100644 --- a/worldeditadditions/lib/erode/erode.lua +++ b/worldeditadditions/lib/erode/erode.lua @@ -27,13 +27,14 @@ function worldeditadditions.erode.run(pos1, pos2, algorithm, params) return false, "Error: Unknown algorithm '"..algorithm.."'. Currently implemented algorithms: snowballs (2d; hydraulic-like). Ideas for algorithms to implement are welcome!" end - local success, msg = worldeditadditions.apply_heightmap_changes( + local success, stats = worldeditadditions.apply_heightmap_changes( pos1, pos2, area, data, heightmap, heightmap_eroded, heightmap_size ) - if not success then return success, msg end - + if not success then return success, stats end worldedit.manip_helpers.finish(manip, data) + print("[erode] stats") + print(worldeditadditions.map_stringify(stats)) return true, stats end diff --git a/worldeditadditions/lib/erode/snowballs.lua b/worldeditadditions/lib/erode/snowballs.lua index 0cf2b7c..e5b8398 100644 --- a/worldeditadditions/lib/erode/snowballs.lua +++ b/worldeditadditions/lib/erode/snowballs.lua @@ -1,46 +1,48 @@ +-- Test command: //multi //fp set1 1312 5 5543 //fp set2 1336 18 5521 //erode//multi //fp set1 1312 5 5543 //fp set2 1336 18 5521 //erode + local function snowball(heightmap, normalmap, heightmap_size, startpos, params) - local offset = { -- Random jitter - apparently helps to avoid snowballs from entrenching too much - x = (math.random() * 2 - 1) * params.radius, - z = (math.random() * 2 - 1) * params.radius - } local sediment = 0 local pos = { x = startpos.x, z = startpos.z } local pos_prev = { x = pos.x, z = pos.z } local velocity = { x = 0, z = 0 } local heightmap_length = #heightmap + -- print("[snowball] startpos ("..pos.x..", "..pos.z..")") + for i = 1, params.snowball_max_steps do - local hi = math.floor(pos.z+offset.z+0.5)*heightmap_size[1] + math.floor(pos.x+offset.x+0.5) - if hi > heightmap_length then break end - + local x = pos.x + local z = pos.z + local hi = math.floor(z+0.5)*heightmap_size[1] + math.floor(x+0.5) -- Stop if we go out of bounds - if offset.x < 0 or offset.z < 0 - or offset.x >= heightmap[1] or offset.z >= heightmap[0] then - break + if x < 0 or z < 0 + or x >= heightmap[1]-1 or z >= heightmap[0]-1 then + -- print("[snowball] hit edge; stopping at ("..x..", "..z.."), (bounds @ "..heightmap_size[1]..", "..heightmap_size[0]..")") + return end + -- print("[snowball] now at ("..x..", "..z..") (bounds @ "..heightmap_size[1]..", "..heightmap_size[0]..")") + if hi > heightmap_length then print("[snowball] out-of-bounds on the array, hi: "..hi..", heightmap_length: "..heightmap_length) return end + + -- print("[snowball] sediment", sediment, "rate_deposit", params.rate_deposit, "normalmap[hi].z", normalmap[hi].z) local step_deposit = sediment * params.rate_deposit * normalmap[hi].z local step_erode = params.rate_erosion * (1 - normalmap[hi].z) * math.min(1, i*params.scale_iterations) + local step_diff = step_deposit - step_erode + -- Erode / Deposit, but only if we are on a different node than we were in the last step - if math.floor(pos_prev.x) ~= math.floor(pos.x) - and math.floor(pos_prev.z) ~= math.floor(pos.z) then - heightmap[hi] = heightmap[hi] + (deposit - erosion) + if math.floor(pos_prev.x) ~= math.floor(x) + and math.floor(pos_prev.z) ~= math.floor(z) then + heightmap[hi] = heightmap[hi] + step_diff end velocity.x = params.friction * velocity.x + normalmap[hi].x * params.speed velocity.z = params.friction * velocity.z + normalmap[hi].y * params.speed - pos_prev.x = pos.x - pos_prev.z = pos.z + pos_prev.x = x + pos_prev.z = z pos.x = pos.x + velocity.x pos.z = pos.z + velocity.z - end - - -- Round everything to the nearest int, since you can't really have - -- something like .141592671 of a node - for i,v in ipairs(heightmap) do - heightmap[i] = math.floor(heightmap[i] + 0.5) + sediment = sediment + step_diff end end @@ -64,12 +66,27 @@ function worldeditadditions.erode.snowballs(heightmap, heightmap_size, params) snowball_count = 50000 }, params) + print("[erode/snowballs] params: "..worldeditadditions.map_stringify(params)) + local normals = worldeditadditions.calculate_normals(heightmap, heightmap_size) for i = 1, params.snowball_count do snowball( heightmap, normals, heightmap_size, - { x = math.random() } + { + x = math.random() * (heightmap_size[1] - 1), + z = math.random() * (heightmap_size[0] - 1) + }, + params ) end + + -- Round everything to the nearest int, since you can't really have + -- something like .141592671 of a node + -- Note that we do this after *all* the erosion is complete + for i,v in ipairs(heightmap) do + heightmap[i] = math.floor(heightmap[i] + 0.5) + end + + return true, params.snowball_count.." snowballs simulated" end diff --git a/worldeditadditions/utils/strings.lua b/worldeditadditions/utils/strings.lua index f3e75fa..673eef9 100644 --- a/worldeditadditions/utils/strings.lua +++ b/worldeditadditions/utils/strings.lua @@ -231,7 +231,7 @@ end function worldeditadditions.map_stringify(map) local result = {} for key, value in pairs(map) do - table.insert(key.."\t"..value) + table.insert(result, key.."\t"..value) end return table.concat(result, "\n") end diff --git a/worldeditadditions/utils/terrain.lua b/worldeditadditions/utils/terrain.lua index c941608..d4353b6 100644 --- a/worldeditadditions/utils/terrain.lua +++ b/worldeditadditions/utils/terrain.lua @@ -62,16 +62,18 @@ function worldeditadditions.calculate_normals(heightmap, heightmap_size) if x - 1 > 0 then left = heightmap[z*heightmap_size[1] + (x-1)] end if x + 1 < heightmap_size[1]-1 then right = heightmap[z*heightmap_size[1] + (x+1)] end - print("[normals] UP | index", (z-1)*heightmap_size[1] + x, "z", z, "z-1", z - 1, "up", up, "limit", 0) - print("[normals] DOWN | index", (z+1)*heightmap_size[1] + x, "z", z, "z+1", z + 1, "down", down, "limit", heightmap_size[1]-1) - print("[normals] LEFT | index", z*heightmap_size[1] + (x-1), "x", x, "x-1", x - 1, "left", left, "limit", 0) - print("[normals] RIGHT | index", z*heightmap_size[1] + (x+1), "x", x, "x+1", x + 1, "right", right, "limit", heightmap_size[1]-1) + -- print("[normals] UP | index", (z-1)*heightmap_size[1] + x, "z", z, "z-1", z - 1, "up", up, "limit", 0) + -- print("[normals] DOWN | index", (z+1)*heightmap_size[1] + x, "z", z, "z+1", z + 1, "down", down, "limit", heightmap_size[1]-1) + -- print("[normals] LEFT | index", z*heightmap_size[1] + (x-1), "x", x, "x-1", x - 1, "left", left, "limit", 0) + -- print("[normals] RIGHT | index", z*heightmap_size[1] + (x+1), "x", x, "x+1", x + 1, "right", right, "limit", heightmap_size[1]-1) result[hi] = worldeditadditions.vector.normalize({ x = left - right, y = 2, -- Z & Y are flipped z = down - up }) + + -- print("[normals] at "..hi.." ("..x..", "..z..") normal "..worldeditadditions.vector.tostring(result[hi])) end end return result @@ -85,9 +87,9 @@ function worldeditadditions.apply_heightmap_changes(pos1, pos2, area, data, heig for x = heightmap_size[1], 0, -1 do local hi = z*heightmap_size[1] + x - local height_old = heightmap[hi] + local height_old = heightmap_old[hi] local height_new = heightmap_new[hi] - -- print("[conv/save] hi", hi, "height_old", heightmap[hi], "height_new", heightmap_new[hi], "z", z, "x", x, "pos1.y", pos1.y) + -- print("[conv/save] hi", hi, "height_old", heightmap_old[hi], "height_new", heightmap_new[hi], "z", z, "x", x, "pos1.y", pos1.y) -- Lua doesn't have a continue statement :-/ if height_old == height_new then diff --git a/worldeditadditions_commands/commands/erode.lua b/worldeditadditions_commands/commands/erode.lua index 81b98e1..8b13003 100644 --- a/worldeditadditions_commands/commands/erode.lua +++ b/worldeditadditions_commands/commands/erode.lua @@ -37,7 +37,7 @@ worldedit.register_command("erode", { ) local time_taken = worldeditadditions.get_ms_time() - start_time - minetest.log("action", name .. " used //erode "..algorithm.." at " .. worldeditadditions.vector.tostring(worldedit.pos1[name]) .. ", replacing " .. changes.replaced .. " nodes and skipping " .. changes.skipped_columns .. " columns in " .. time_taken .. "s") - return true, changes.replaced .. " nodes replaced and " .. changes.skipped_columns .. " columns skipped in " .. worldeditadditions.human_time(time_taken) + minetest.log("action", name .. " used //erode "..algorithm.." at " .. worldeditadditions.vector.tostring(worldedit.pos1[name]) .. ", adding " .. stats.added .. " nodes and removing " .. stats.removed .. " nodes in " .. time_taken .. "s") + return true, stats.added .. " nodes added and " .. stats.removed .. " nodes removed in " .. worldeditadditions.human_time(time_taken) end })