What is wrong with the code for my greedy mesher

Hi, I’m trying to make a voxel game with 1 dimensional tables to store chunks
It works fine when creating flat terrain, but when i remove one block inside a flat surface it is messed up:


this is what happened when i deleted a block at the coordinate (5,1,5).

here is my code:

local v = require(game.ReplicatedStorage.VariablesServer)
local mapsize = 2
local chunksize = 16
local speed = 50
local cheight = 16
local height = 5
local seed = 69420

local map = {}

local sides = {
	{1,0,0}, -- right
	{-1,0,0}, -- left
	{0,0,1}, -- forward
	{0,0,-1}, -- backward
}

local function queueBlock(t,c)
	table.insert(c,t)
end

local function blockOffset(x,y,z) 
	return (x + (chunksize) * (z + (chunksize) * y)) +1
end

local function findBlock(x,y,z)
	local off = blockOffset(x,y,z)
	if x > chunksize-1 or z > chunksize-1 then
		return false
	end
	return off
end

local function createBlock(t,x,z,x1,z1,y,f,n)
	local function resizeBlock(b,v,sx,sy,sz)
		b.Size += Vector3.new(math.round(math.max(sx-0.5,0)), sy, math.round(math.max(sz-0.5,0)))*4
		--b.Position = v + Vector3.new(sx/2,sy/2,sz/2)
	end

	local block = v.rep.Blocks:FindFirstChild(t)
	local clone = block:Clone()
	clone.Parent = workspace.Map

	local sx = (x1-x)
	local sz = (z1-z)

	clone.Position = Vector3.new(x+sx/2+0.5,y,z+sz/2+0.5)*4
	--clone.Size = snapv(Vector3.new(sx+0.5,1,sz+0.5),1)
	resizeBlock(clone,clone.Position,sx,0,sz)
	clone.Parent = f
	if t == "Debug" then
		clone:WaitForChild("BillboardGui").TextLabel.Text = tostring(n)
	end
end

local function getChunk(px,pz)
	return (pz*mapsize)+px+1
end

local function createBlockAtGrid(t,x,y,z)
	local px = math.floor(x/chunksize)
	local pz = math.floor(z/chunksize)
	local chunkdata = map[getChunk(px,pz)]
	local chunk = chunkdata[2]
	chunk[blockOffset(x,y,z)] = t
	meshing(px,pz,chunkdata[1],chunk)
end

function meshing(px,pz,folder,chunk)
	folder:ClearAllChildren()
	
	local startx = 0
	local startz = 0
	local endx = 0
	local endz = 0
	
	local begin = true
	
	local ox = (px*chunksize)
	local oz = (pz*chunksize)
	
	local zlast = 0
	local zfound = false
	
	local merges = 0
	
	for y=0, chunksize-1 do
		for x=0, chunksize-1 do
			for z=0, chunksize-1 do
				if chunk[findBlock(x,y,z)] then -- found block
					if begin then
						startx = x
						startz = z
						zlast = 0
						zfound = false
						begin = false
					end
					if not zfound then
						if not chunk[findBlock(x,y,z+1)] and z+1 < 15 then -- no found neighbor for z
							zlast = z -- found last z, now searching x
							zfound = true
						end
						if z+1 > 15 then -- at edge of chunk
							zfound = true
							zlast = z -- found last z, now searching x
						end
					end
					if zfound then -- search z axis because last x is found
						if not chunk[findBlock(x+1,y,z)] and x+1 < 15 then  -- no found neighbor for x
							endx = x
							begin = true
							merges += 1
							createBlock("Debug",startx+ox,startz+oz,endx+ox,zlast+oz,y,folder,merges)
							break
						end
						if x+1 > 15 then -- at edge of chunk
							endx = x
							begin = true
							merges += 1
							createBlock("Debug",startx+ox,startz+oz,endx+ox,zlast+oz,y,folder,merges)
							break
						end
					end
				end
			end
		end
	end
end

function snapv(v,d)
	return Vector3.new(math.round(v.x/d)*4,math.round(v.y/d)*4,math.round(v.z/d)*4)
end

local function snap(n)
	return math.round(n/4)*4
end

local function createMap()
	for z=1, mapsize do
		for x=1, mapsize do
			table.insert(map,{})
		end
	end
end

local function createChunk(px ,pz)
	local chunkFolder = Instance.new("Folder")
	chunkFolder.Parent = workspace.Map
	chunkFolder.Name = "chunk_"..px.."_"..pz
	
	local chunk = {}
	
	for y=0, chunksize-1 do
		for z=0, chunksize-1 do
			for x=0, chunksize-1 do
				queueBlock(y==1,chunk)
			end
		end
	end
	--queueBlock(true)
	--queueBlock(true)
	--queueBlock(true)
	meshing(px,pz,chunkFolder,chunk)
	map[getChunk(px, pz)] = {chunkFolder,chunk}
end

createMap()
createChunk(0,0)
createBlockAtGrid(false,5,1,5) -- destroy one block on flat surface

I would like to know the problem and what code i should add to fix it. thanks in advance

Any help is appreciated. i couldnt get this to work for several months so i would be very very happy if i could at least make some progress, so please give me something to work with

Try to use print messages to check if all the functions are running properly. I’m not exactly very experienced with meshing so I’ll try to help as much as I can.

Hi, thank you for responding. i have done this before (printing) and have also made a 1d mesher version that works (script above is for 2d meshing)

1d greedy mesher:

local v = require(game.ReplicatedStorage.VariablesServer)
local mapsize = 2
local chunksize = 16
local speed = 50
local cheight = 16
local height = 5
local seed = 69420

local map = {}

local sides = {
	{1,0,0}, -- right
	{-1,0,0}, -- left
	{0,0,1}, -- forward
	{0,0,-1}, -- backward
}

local function queueBlock(t,c)
	table.insert(c,t)
end

local function blockOffset(x,y,z) 
	return (x + (chunksize) * (z + (chunksize) * y)) +1
end

local function findBlock(x,y,z)
	local off = blockOffset(x,y,z)
	if x > chunksize-1 or z > chunksize-1 then
		return false
	end
	return off
end

local function createBlock(t,x,z,x1,z1,y,f)
	local function resizeBlock(b,v,sx,sy,sz)
		b.Size += Vector3.new(math.round(math.max(sx-0.5,0)), sy, math.round(math.max(sz-0.5,0)))*4
		--b.Position = v + Vector3.new(sx/2,sy/2,sz/2)
	end

	local block = v.rep.Blocks:FindFirstChild(t)
	local clone = block:Clone()
	clone.Parent = workspace.Map

	local sx = (x1-x)
	local sz = (z1-z)

	clone.Position = Vector3.new(x+sx/2+0.5,y,z+sz/2+0.5)*4
	--clone.Size = snapv(Vector3.new(sx+0.5,1,sz+0.5),1)
	resizeBlock(clone,clone.Position,sx,0,sz)
	clone.Parent = f
end

local function getChunk(px,pz)
	return (pz*mapsize)+px+1
end

local function createBlockAtGrid(t,x,y,z)
	local px = math.floor(x/chunksize)
	local pz = math.floor(z/chunksize)
	local chunkdata = map[getChunk(px,pz)]
	local chunk = chunkdata[2]
	chunk[blockOffset(x,y,z)] = t
	meshing(px,pz,chunkdata[1],chunk)
end

function meshing(px,pz,folder,chunk)
	folder:ClearAllChildren()
	
	local startx = 0
	local startz = 0
	local endx = 0
	local endz = 0
	
	local begin = true
	
	local ox = (px*chunksize)
	local oz = (pz*chunksize)
	
	for y=0, chunksize-1 do
		for x=0, chunksize-1 do
			for z=0, chunksize-1 do
				if chunk[findBlock(x,y,z)] then -- found block
					if begin then
						startx = x
						startz = z
						begin = false
					end
					if not chunk[findBlock(x,y,z+1)] and z+1 < 15 then -- no found neighbor
						endx = x
						endz = z
						begin = true
						createBlock("Grass",startx+ox,startz+oz,endx+ox,endz+oz,y,folder)
					end
					if z+1 > 15 then -- at edge of chunk
						endx = x
						endz = z
						begin = true
						createBlock("Grass",startx+ox,startz+oz,endx+ox,endz+oz,y,folder)
						break
					end
				end
			end
		end
	end
end

function snapv(v,d)
	return Vector3.new(math.round(v.x/d)*4,math.round(v.y/d)*4,math.round(v.z/d)*4)
end

local function snap(n)
	return math.round(n/4)*4
end

local function createMap()
	for z=1, mapsize do
		for x=1, mapsize do
			table.insert(map,{})
		end
	end
end

local function createChunk(px ,pz)
	local chunkFolder = Instance.new("Folder")
	chunkFolder.Parent = workspace.Map
	chunkFolder.Name = "chunk_"..px.."_"..pz
	
	local chunk = {}
	
	for y=0, chunksize-1 do
		for z=0, chunksize-1 do
			for x=0, chunksize-1 do
				queueBlock(y==1,chunk)
			end
		end
	end
	--queueBlock(true)
	--queueBlock(true)
	--queueBlock(true)
	meshing(px,pz,chunkFolder,chunk)
	map[getChunk(px, pz)] = {chunkFolder,chunk}
end

createMap()
createChunk(0,0)
createBlockAtGrid(false,5,1,5) -- deleting one block

so I know some parts are working correctly, but i cant make print functions for everything and even if i did i wouldnt know what to do. like i said, thank you for respoding but i have already done this. maybe i should have made a post about extending my 1d mesher to 2d instead of doing it myself

From the image I see that, if coordinates start from 0,0 at the bottom left corner and there’s only 1 y level starting at 1. Then the block at 5,1,5 is gone but so is everything with x,y,z coordinates greater than or equal to 5. Is that the exact problem in that it deleted more than you want to? What are the labels on 1 and 2 you’ve put on this image?

Just clarifying so that the issue is explicitly laid out for everyone reading

Hi, i know that the blocks behind 5,1,5 are gone, and that’s my problem, so i should have asked on how to fix that, sorry. labels 1 and 2 are billboard guis to show the order of meshes.

This code breaks the z loop when it sees the first block that doesn’t exist at the next z. This means it would immediately skip to the next x coordinate and being traversing z from there.

If I’m understanding this correctly, you want to continue looking at z’s after the first one that gives us an empty block, just have it not be a part of this “merge”. It looks like your code already does this, but I imagine you would want “continue” instead of “break” here since it will look past that z still

you’re right. but when i remove the first break it does this:


the two quads intersect each other

maybe this is the right step, but I don’t know where to go on from here.

What was your code change? I was thinking both of those break statements should be continues

I removed the break, i didnt add a continue. let me see what happens when i add a continue

1 Like

it resulted with this:
image

at least there’s a new quad. i think we’re getting somewhere

(also for my 1D mesher i used break)

What if both of the break statements were continues? There were two of them, the second being for when x+1 goes over the chunk border.

It’s difficult to say if this is the issue or not there may be other problems. This was just the only thing I could think of going through the code step by step

yeah, the result is the same thing as the picture above. maybe i should just follow a tutorial. but the problem is that they dont use 1d chunk storage, and i can’t seem to understand their code.