How to do optimized Voxel Destruction?

So your system can divide one part into multiple? Could you direct me to how I could achieve something like that?

ofc,
First:
Divide the hit parts into 8 pieces.
Second:
Divide the pieces of the part that are hit into 8 pieces.
Third:
Repeat Steps 1 and 2 until you reach the desired size.
Fourth:
Turn the final touching parts into 1 by 1 by 1 cubes.
Fifth:
Unanchor or destroy the cubes
Sixth:
Greedy Mesh the unaffected parts to lower the part counts.

If this is confusing try researching these topics:
Greedy Meshing
Octrees
Splitting Parts

9 Likes

So I’ve done a bit more research into it, mainly checking these posts:

And honestly I can’t really seem to figure it out. From what I understand you just divide the parts based around the contact point of choice, and then greedy mesh everything. The issue comes with actually dividing the part. From what I can find, there isn’t any explanation or tutorial on dividing a part around a contact point. You mentioned octrees, which I believe you are using here for that, but I have no idea on how those work, or how I would even implement them here. And most resources I can find on voxel destruction and the like are either entirely unoptimized or not at all what I’m looking for.

Thank you for the suggestions though, I would really like to figure this system out, as it is something that I find really cool and would like to implement into my own game, it just seems there is a lack of community resources based around voxel destruction.

2 Likes

I’ve been trying to figure this out myself and understand your pain. If I figure something I’ll come back here.

1 Like

So far this is the best I’ve been able to do:



It uses the Vex Module. But unfortunately it isn’t very optimized for larger parts. Meaning that when the “hitboxes” touch larger parts, much more parts are created than normal. But smaller parts work significantly better for performance. I’ve been unable to implement greedy meshing into it, as I can’t really find a simple “greedy mesh function” that fits my case.

2 Likes

Sorry for the late reply! For greedy meshing, I edited this module to be able to be used in my script.

Also, not sure about the lag, either make the voxels bigger or the hitboxes smaller. I’m attempting to optimize my system but I’m kind of lost on it as well.

VDP seems to have a pretty optimized system besides the flickering, I’m trying to get there but currently, I’m not. But it seems none of their weapons spam fire, even the laser gun looks like it’s constant but if you move your mouse quickly the destruction doesn’t keep up. Maybe for moves that have to constantly destroy parts you should just increase the voxel size. I’m sure there are other optimizations you can do under the hood though.

1 Like

Thank you for the module! But after implementing it, seems like my performance is even worse now. This is mainly due to my one use case of using balls to go through parts, which fire every second meaning the part has to redivide and then remesh over and over again. If I used this for just one touch event like an explosion for example, the performance would likely be much better. Seems like the only way to do a sort of constant digging through one part with proper optimization is with octrees. Though once again, I have no idea how to use them.

1 Like

Alright, the way my octree system works is by dividing the part into 8. After that, you now have 8 parts, you choose the ones currently inside your hitbox and divide each of them into 8. Now once again you choose the ones inside your hitbox and divide them by 8, you keep repeating this until you reach a size that you can divide the final parts into 1 by 1 by 1s or whatever size you wish.

I don’t think octrees will completely solve your problem either, it does prevent the creation of unnecessary voxels though.

Also yeah, the constant digging will likely cause performance issues. It still
I’m really bad at explaining things so apologies if you don’t understand.

I’m still searching for ways to improve performance. As shown by the flickering, also depending on your use case creating voxels on the server will most likely be your best bet, I quickly found issues because parts on each client are usually in a different spot for each player(standing on floating objects).

External Media
1 Like

Thank you a lot. You’re advice helped me out. I need more optimizations but here are my results.

External Media
2 Likes

Thank you for the excellent explanation, I was able to use this to make something much more optimized, though still a bit flawed.


I’ve also been trying to incorporate greedy meshing into it, but it seems kind of redundant, as the majority of the lag is caused by instancing the parts rather than the parts existing in the workspace. And you would greedy mesh after the parts have been divided, so there is really no point in greedy meshing here as far as I’m aware.

One other thing, with parts that are uneven, when you divide them, they end up not looking like cubes, but just smaller versions of the original part. Which is obvious. Instead of just dividing the part, a better idea would be to divide the part into cubic shapes. Now how you’d go about doing this, I have no idea. But if anyone figures this out please let me know.

2 Likes

As for the odd part size, you could try finding the biggest number that can be divided into all 3 axes of a part. Effectively turning it into a bunch of cubes. However, I’m not sure how you could implement both octrees and this system. Maybe octrees aren’t necessary? Also, the smaller the voxels are the less noticeable this is.

I’m not so sure about the greedy meshing situation I’d imagine the fewer parts created the less laggy but it puts a lot of strain just to greedy mesh the parts. But if you plan on adding welding greedy meshing before you weld will reduce the strain on welding. Just depends it seems.

1 Like

keep dividing touching parts until it dimensions on x and z axis is equal to one or less ?
2x2 is probably better though
(ignoring y axis because it doesn’t have much problems with odd numbers)

Just use quadtree (i mean octree)partitioning to a small size, you’re not going to get perfect dimensions with any method unless you want to voxelize the whole part which would still give you the same effect just laggier. People aren’t gonna really notice it

edit: here is an example of octrees Dynamic Octree System - #9 by plasma_node

The question is: Why even destroy them? There’s a high chance you’ll regenerate those, so you should just turn off CanCollide and CanQuery, and set Transparency to 1, that allows u to detect if a part has been hit (by checking it’s transparency or any of the 3 properties), and allows easy regeneration; just setting back the values to their default.

phrehaps you should change this module so if the object that is destroyed is bigger the parts also become bigger and less.

I may be wrong about this but, from the examples i see on the module you linked, octree partitioning is basically the exact same as what i was already doing, which was diving the part into smaller parts, and continuously doing so for any parts touching the hit box until they reach a minimum size. In which case, i run into the same problem: Dividing uneven cuboids will result in rectangular voxels.

There’s nothing you can do for rectangular voxels (that i know of) except for dividing more so they are smaller, I’d reccomend avoiding non-cubes if you can and make sure the x and z axis are equal numbers.

My bad, I just realized the problem. https://www.youtube.com/watch?v=8AdcPD50aTQ

In this video you see they cut the rectangle in half and then make their collums. You would basically do what he does in the video, cut it in half and then divide it into collumns but in 3d. This would be like grid voxelization but on a larger scale (minimum size for an axis is x, y, z / 3, 2, 3 ), Then for the parts inside the hitbox you would do octtree partitioning. Also you could detect if its not a cube so you wouldn’t have to do this for every single one. So optimally (i think…) you would have a shape made of 3x2x3 cubes. This is a very quickly thought idea, but try it out and see if it works!

NEVERMIND I DON’T KNOW !!! IF YOU WANT THIS TO WORK THEN YOU CAN’T HAVE UNIFORM SIZES AND THE BEST OPTION IS TO JUST KEEP DIVIDING TO SMALL NUMBER

Hi again,

I haven’t played the game, does the same effect work on the trees? They seem to be rotated so it would be interesting to see if the voxel algorithms work on it.

There’s a couple of suggestions already on subdividing cubes so I’ll pitch a different idea.

You can use a union operations to get the look you’re after too.

Demo file:
UnionDestruction.rbxl (313.8 KB)

The operation is very slow on multiple parts so you’d want to use it only on 2-3 parts at most at a time. You can achieve this by unioning the entire building into 1 part. Another separate union should be done for all the glass objects if you want to preserve their transparency effect.

Added note (Parallel Processing): Unfortunately the union operations aren’t thread safe to use so we cannot speed them up by splitting it up into threads.

Lastly, that “Voxel-like” look to the explosion could be mimicked by creating a union that’s shaped like it. Although this is very tedious unfortunately.
image

Demo file:
UnionDestruction.rbxl (313.8 KB)

2 Likes

This was actually the response that helped me figure it out.
I’ve basically perfected the system that I had tried to make from the beginning:


To explain a bit, I’m using quadtree partitioning with a function sourced from this post
But before I divide the part into four, I use this function to check if the part is rectangular:

local function partCanSubdivide(part)

	-- can we run the subcubes algorithm on this part w/o artifacts?
	local largest = math.max(part.Size.X, part.Size.Y, part.Size.Z)
	local smallest = math.min(part.Size.Y, part.Size.Z)

	if smallest == part.Size.X then
		smallest = math.min(part.Size.Y, part.Size.Z)
	elseif smallest == part.Size.Y then
		smallest = math.min(part.Size.X, part.Size.Z)
	elseif smallest == part.Size.Z then
		smallest = math.min(part.Size.X, part.Size.Y)
	end

	print(largest)
	print(smallest * 1.5)
	return largest >= 1.5 * smallest
--returns true if part is rectangular. 
--Part is rectangular if the largest axis is at least 1.5x bigger than the smallest axis
end

Then I have a separate function to check what the longest axis of the part is:

local function getLargestAxis(part:Part)
	return math.max(part.Size.X, part.Size.Y, part.Size.Z)
end

Then, if it is rectangular, I cut the part in half to turn it into squares with this function:

local function CutPartinHalf(block : Part)
	local partTable = {}
	local bipolarVectorSet = {}


	local X = block.Size.X
	local Y = block.Size.Y
	local Z = block.Size.Z

	if getLargestAxis(block) == X then
		X /= 2

		bipolarVectorSet = {
			Vector3.new(1,0,0),
			Vector3.new(-1,0,0),
		}

	elseif getLargestAxis(block) == Y then
		Y/=2

		bipolarVectorSet = {
			Vector3.new(0,1,0),
			Vector3.new(0,-1,0),
		}

	elseif getLargestAxis(block) == Z then
		Z/=2

		bipolarVectorSet = {
			Vector3.new(0,0,1),
			Vector3.new(0,0,-1),
		}

	end




	local halfSize = Vector3.new(X,Y,Z)

	for _, offsetVector in pairs(bipolarVectorSet) do

		local clone = block:Clone()
		clone.Parent = workspace
		clone.Size = halfSize
		clone.CFrame += block.CFrame:VectorToWorldSpace((halfSize / 2.0) * offsetVector)
		table.insert(partTable,clone)
	end
	block:Destroy()
	return partTable
end

And otherwise if the part isn’t rectangular (meaning it’s a cube), I just use quadtree partitioning to divide the part into four, resulting in evenly shaped cubes across the entire original part.

-Which is what I would say if you could divide every possible part into perfect cubes. Because that isn’t possible, my system turns cuboids into squares in the event that fitting perfect cubes isn’t possible, and will make the smallest axis of the original part match up with the divided cubes.

-In simpler terms, if I have a thin wall and divide it with my system, since cubes can’t be perfectly made, it will instead make squares that match the thickness of the wall

And as for actually writing the function that destroys the wall based on a hitbox, I’m gonna keep that to myself, BUT it’s pretty simple. Just create a part of any shape (your ‘hitbox’), and use a loop or run service to constantly check for parts touching your hitbox. Then, continuously divide the parts that are touching your hitbox until they reach a minimum size.

Now obviously this isn’t super performant with larger destruction, but I’m just gonna chalk that up to a limitation of roblox.

and @treebee63, I ended up not using the cube division script you gave me, so sorry for the trouble with that.

18 Likes