Why is instance generation so slow?

Hello. I’ve been wanting to make a voxel game, and I’ve already made a greedy mesher, and culler for it. But I’ve been benchmarking things, and I’ve noticed that generating, or even setting the size / position, or parent of parts is really slow. For the sake of writing this topic, I’ve written 31 lines of code to show how long it takes to generate a 16x16x16 chunk of world.

local seed = math.random(-1000, 1000)
local t0 = 0
local t2 = 0
for x = 1, 24 do
	task.wait()
	for y = 1, 24 do
		for z = 1, 24 do
			local t3 = os.clock()
			local noise = math.noise((x + seed) / 12, (y + seed) / 12, (z + seed) / 12) - ((y - 12) / 24)
			t2 += os.clock() - t3
			if noise >= 0 then
				local t1 = os.clock()
				local p = Instance.new("Part")
				p.Anchored = true
				p.Parent = workspace
				p.Size = Vector3.new(1, 1, 1)
				p.CFrame = CFrame.new(x, y, z)
				t0 += os.clock() - t1
			end
		end
	end
end
print("Instance generation took "..tostring(t0*1000).." ms")
print("Or")
print("Instance generation took "..tostring(t0).." sec")

print("Noise calculation took "..tostring(t2*1000).." ms")
print("Or")
print("Noise calculation took "..tostring(t2).." sec")

It takes almost one second to generate this. Keep in mind, that I already have a script that can do this exact same thing but in around 29 milliseconds, because it generates a table that says what coordinates will have blocks, and which coordinates don’t have blocks. And then it greedy meshes, and culls the world while generating the world, and it also uses pre-generated instances from a pool so it doesn’t have to use Instance.new("Part"). And the reason this is faster is because it doesn’t have to generate as many parts.

Why does instance generation / instance manipulation take so long, and is there anything I can do to make it any faster besides using greedy meshing, instance pooling, and culling?

Cloning is faster, also you should check out algorithms that break down voxels into big rectangles so they can create the exact same result cubes would create but with the smallest amount of parts possible.

I saw a post about that exact algorithm on the forum a while back, but I can’t find it now, if anyone finds it reply with it.

Also you could add statements for the task.wait so it runs per amount of cycles, example:

if x%4 == 0 then task.wait() end --waits every 4 loop cycles
1 Like

That shouldn’t affect it because the code that is measuring how long it is taking to generate is running outside of this wait. If I remove this wait, I could risk getting an exhausted allowed execution time error.

Ok. I could try that.

I believe that is called “Greedy Meshing”. And as stated in my post, I have already done that in a different script, but I haven’t posted that script here.

I want to know if there are any other optimizations besides greedy meshing, culling, and instance pooling that I could use to make it faster.

Try this:

if x%4 == 0 then task.wait() end --waits every 4 loop cycles

Basically, your loop is currently yielding per 1 cycle, you can use the mod operator and an if statement to increase the cycles(in this example, 4), and you can keep increasing the cycles until you notice lag on lower-end devices. If you increase cycles too much you get lag, if you have them too low you get slow code execution(like the one you describe above).

2 Likes