More robust and faster code for grid twisting on the Lua side.

At chunkgen init, build a list of the polygons instead of calculating them for every node.
This commit is contained in:
Gael-de-Sailly 2020-04-12 16:42:03 +02:00
parent e227755531
commit 30cbc14302
2 changed files with 71 additions and 65 deletions

View File

@ -18,13 +18,13 @@ local function transform_quadri(X, Y, x, y)
local x1, x2, x3, x4 = unpack(X) local x1, x2, x3, x4 = unpack(X)
local y1, y2, y3, y4 = unpack(Y) local y1, y2, y3, y4 = unpack(Y)
local d12 = distance_to_segment(x1,y1,x2,y2,x,y)
local d34 = distance_to_segment(x3,y3,x4,y4,x,y)
local xc = d12 / (d12+d34)
local d23 = distance_to_segment(x2,y2,x3,y3,x,y) local d23 = distance_to_segment(x2,y2,x3,y3,x,y)
local d41 = distance_to_segment(x4,y4,x1,y1,x,y) local d41 = distance_to_segment(x4,y4,x1,y1,x,y)
local yc = d41 / (d23+d41) local xc = d41 / (d23+d41)
local d12 = distance_to_segment(x1,y1,x2,y2,x,y)
local d34 = distance_to_segment(x3,y3,x4,y4,x,y)
local yc = d12 / (d12+d34)
return xc, yc return xc, yc
end end

126
init.lua
View File

@ -62,7 +62,7 @@ end
local data = {} local data = {}
local blocksize = 20 local blocksize = 12
local sea_level = 1 local sea_level = 1
local min_catchment = 25 local min_catchment = 25
@ -96,72 +96,77 @@ local function generate(minp, maxp, seed)
local a = VoxelArea:new({MinEdge = emin, MaxEdge = emax}) local a = VoxelArea:new({MinEdge = emin, MaxEdge = emax})
local ystride = a.ystride -- Tip : the ystride of a VoxelArea is the number to add to the array index to get the index of the position above. It's faster because it avoids to completely recalculate the index. local ystride = a.ystride -- Tip : the ystride of a VoxelArea is the number to add to the array index to get the index of the position above. It's faster because it avoids to completely recalculate the index.
local chulens = maxp.z - minp.z + 1
for x = minp.x, maxp.x do local polygon_number = {}
for z = minp.z, maxp.z do local polygons = {}
local xb = x/blocksize local xpmin, xpmax = math.max(math.floor(minp.x/blocksize - 0.5), 0), math.min(math.ceil(maxp.x/blocksize), X-2)
local zb = z/blocksize local zpmin, zpmax = math.max(math.floor(minp.z/blocksize - 0.5), 0), math.min(math.ceil(maxp.z/blocksize), Z-2)
local xc = math.floor(xb+0.5) local n = 1
local zc = math.floor(zb+0.5) local n_filled = 0
for xp = xpmin, xpmax do
for zp=zpmin, zpmax do
local iA = index(xp, zp)
local iB = index(xp+1, zp)
local iC = index(xp+1, zp+1)
local iD = index(xp, zp+1)
local poly_x = {offset_x[iA]+xp, offset_x[iB]+xp+1, offset_x[iC]+xp+1, offset_x[iD]+xp}
local poly_z = {offset_z[iA]+zp, offset_z[iB]+zp, offset_z[iC]+zp+1, offset_z[iD]+zp+1}
local x0, z0 local bounds = {}
if xc >= 0 and zc >= 0 and xc < X and zc < Z then local xmin = math.max(math.floor(blocksize*math.min(unpack(poly_x)))+1, minp.x)
local xoff, zoff = get_point_location(xc, zc) local xmax = math.min(math.floor(blocksize*math.max(unpack(poly_x))), maxp.x)
local north, east, south, west for x=xmin, xmax do
if xc > 0 then bounds[x] = {}
local x1off, z1off = get_point_location(xc-1, zc) end
west = geometry.area({xoff, x1off, xb}, {zoff, z1off, zb}) <= 0
else
west = zb > zoff
end
if zc > 0 then
local x2off, z2off = get_point_location(xc, zc-1)
north = geometry.area({xoff, x2off, xb}, {zoff, z2off, zb}) <= 0
else
north = xb > xoff
end
if xc < X-1 then
local x3off, z3off = get_point_location(xc+1, zc)
east = geometry.area({xoff, x3off, xb}, {zoff, z3off, zb}) <= 0
else
east = zb < zoff
end
if zc < Z-1 then
local x4off, z4off = get_point_location(xc, zc+1)
south = geometry.area({xoff, x4off, xb}, {zoff, z4off, zb}) <= 0
else
south = xb < xoff
end
if west and not north then local i1 = 4
x0, z0 = xc-1, zc-1 for i2=1, 4 do -- Loop on 4 edges
elseif north and not east then local x1, x2 = poly_x[i1], poly_x[i2]
x0, z0 = xc, zc-1 local lxmin = math.floor(blocksize*math.min(x1, x2))+1
elseif east and not south then local lxmax = math.floor(blocksize*math.max(x1, x2))
x0, z0 = xc, zc if lxmin <= lxmax then
elseif south and not west then local z1, z2 = poly_z[i1], poly_z[i2]
x0, z0 = xc-1, zc local a = (z1-z2) / (x1-x2)
else local b = blocksize*(z1 - a*x1)
x0, z0 = xc, zc for x=math.max(lxmin, minp.x), math.min(lxmax, maxp.x) do
table.insert(bounds[x], a*x+b)
end
end
i1 = i2
end
for x=xmin, xmax do
local xlist = bounds[x]
table.sort(xlist)
local c = math.floor(#xlist/2)
for l=1, c do
local zmin = math.max(math.floor(xlist[l*2-1])+1, minp.z)
local zmax = math.min(math.floor(xlist[l*2]), maxp.z)
local i = (x-minp.x) * chulens + (zmin-minp.z) + 1
for z=zmin, zmax do
polygon_number[i] = n
i = i + 1
n_filled = n_filled + 1
end
end end
end end
if x0 and z0 and x0 >= 0 and x0 < X-1 and z0 >= 0 and z0 < Z-1 then polygons[n] = {x=poly_x, z=poly_z, i={iA, iB, iC, iD}}
local x1 = x0+1 n = n + 1
local z1 = z0+1 end
local xf, zf end
do
local xA, zA = get_point_location(x0, z0)
local xB, zB = get_point_location(x0, z1)
local xC, zC = get_point_location(x1, z1)
local xD, zD = get_point_location(x1, z0)
xf, zf = geometry.transform_quadri({xA, xB, xC, xD}, {zA, zB, zC, zD}, xb, zb)
end
local i00 = index(x0,z0) local i = 1
local i01 = index(x1,z0) for x = minp.x, maxp.x do
local i10 = index(x0,z1) for z = minp.z, maxp.z do
local i11 = index(x1,z1) local npoly = polygon_number[i]
if npoly then
local poly = polygons[npoly]
local xf, zf = geometry.transform_quadri(poly.x, poly.z, x/blocksize, z/blocksize)
if xf < 0 or xf > 1 or zf < 0 or zf > 1 then
print(xf, zf, x, z)
end
local i00, i01, i11, i10 = unpack(poly.i)
local terrain_height = math.floor(interp( local terrain_height = math.floor(interp(
dem[i00], dem[i00],
@ -230,6 +235,7 @@ local function generate(minp, maxp, seed)
end end
end end
end end
i = i + 1
end end
end end