Minetest-WorldEditAdditions/worldeditadditions_core/utils/terrain/calculate_normals.lua

48 lines
2.2 KiB
Lua

local wea_c = worldeditadditions_core
local Vector3 = wea_c.Vector3
--- Calculates a normal map for the given heightmap.
-- Caution: This method (like worldeditadditions.make_heightmap) works on
-- X AND Z, and NOT x and y. This means that the resulting 3d normal vectors
-- will have the z and y values swapped.
-- @param heightmap table A ZERO indexed flat heightmap. See worldeditadditions.terrain.make_heightmap().
-- @param heightmap_size int[] The size of the heightmap in the form [ z, x ]
-- @return Vector[] The calculated normal map, in the same form as the input heightmap. Each element of the array is a Vector3 instance representing a normal.
local function calculate_normals(heightmap, heightmap_size)
-- print("heightmap_size: "..heightmap_size.x.."x"..heightmap_size.z)
local result = {}
for z = heightmap_size.z-1, 0, -1 do
for x = heightmap_size.x-1, 0, -1 do
-- Algorithm ref https://stackoverflow.com/a/13983431/1460422
-- Also ref Vector.mjs, which I implemented myself (available upon request)
local hi = z*heightmap_size.x + x
-- Default to this pixel's height
local up = heightmap[hi]
local down = heightmap[hi]
local left = heightmap[hi]
local right = heightmap[hi]
if z - 1 > 0 then up = heightmap[(z-1)*heightmap_size.x + x] end
if z + 1 < heightmap_size.z-1 then down = heightmap[(z+1)*heightmap_size.x + x] end
if x - 1 > 0 then left = heightmap[z*heightmap_size.x + (x-1)] end
if x + 1 < heightmap_size.x-1 then right = heightmap[z*heightmap_size.x + (x+1)] end
-- print("[normals] UP | index", (z-1)*heightmap_size.x + x, "z", z, "z-1", z - 1, "up", up, "limit", 0)
-- print("[normals] DOWN | index", (z+1)*heightmap_size.x + x, "z", z, "z+1", z + 1, "down", down, "limit", heightmap_size.x-1)
-- print("[normals] LEFT | index", z*heightmap_size.x + (x-1), "x", x, "x-1", x - 1, "left", left, "limit", 0)
-- print("[normals] RIGHT | index", z*heightmap_size.x + (x+1), "x", x, "x+1", x + 1, "right", right, "limit", heightmap_size.x-1)
result[hi] = Vector3.new(
left - right, -- x
2, -- y - Z & Y are flipped
down - up -- z
):normalise()
-- print("[normals] at "..hi.." ("..x..", "..z..") normal "..result[hi])
end
end
return result
end
return calculate_normals