CSG destruction?

I’m trying to achieve some realistic destruction , similar to rainbow six siege or other games similar, where you can shoot / knife a wall and it’ll create a little hole you can peek through and shoot from.

I’m trying this using csg and it’s going really odd. for some reason it’s just really slow and not as efficent.

are there other methods I can use to achieve realistic destruction?

if hitPart and isWood(hitPart) then
			local original = hitPart
			local originalCF = original.CFrame
			local hitPos = hitPoint or original.Position


			if not (original:IsA("Part") or original:IsA("UnionOperation") or original:IsA("MeshPart")) then
				warn("Hit part is not a valid target :", original.ClassName)
				return
			end

	--small point to make hole
			local sphere = Instance.new("Part")
			sphere.Shape = Enum.PartType.Ball
			sphere.Size = Vector3.new(0.8, 0.8, 0.8)
			sphere.CFrame = CFrame.new(hitPos)
			sphere.Anchored = true
			sphere.CanCollide = false
			sphere.Transparency = 1 
			sphere.Name = "CraterSphere"
			sphere.Parent = workspace
game:GetService("Debris"):AddItem(sphere,0.4)

			task.wait()
			local options = {
				CollisionFidelity = Enum.CollisionFidelity.PreciseConvexDecomposition,
				RenderFidelity = Enum.RenderFidelity.Automatic,
				SplitApart = true,
			}
			-- CSG subtract crater from the wood part
			local success, result = pcall(function()
				return GeometryService:SubtractAsync(original, {sphere},options)
			end)

			if success and result and #result > 0 then
				for _, part in ipairs(result) do
			
				end

				original:SubstituteGeometry(result[1])
				task.wait(0.09)
				sphere:Destroy()
			else
				warn(" Reason----  ", result)
			end

			sphere:Destroy()
		end
External Media External Media

is this on the server or client?
try repalcing local sphere = Instance.new("Part") with premade parts
and remove every task.wait(...) i don’t think you really need them they only seem to slow your code or simulate lag ?

its on the client, and i removed the task.wait but it still persists with being slow and not registering some of the holes

same as the video ? or just a bit different.
give me a sec I’ll try it in studio

I mean, CSG (unions) are pretty slow to begin with, even when editing in studio. (and imprecise too)
have you tried turning the wall into voxels upon hit, and replace affected ones with premade debris?

1 Like

I thought this was lag or something wrong with the code, but yeah “pretty slow” maybe there is still something wrong with the code for it to be > than 2 seconds, but still.

		local start = os.clock()
		local success, result = pcall(function()
			return GeometryService:SubtractAsync(original, {sphere},options)
		end)
		print(os.clock() - start)


@SryupExtract

  • you’re better of using another way
  • or phenix_rider1 way
  • or maybe create thin layers of wood and use Enum.CollisionFidelity.Default the code a bit faster ( but I don’t think will be better for long term performance )
Video for Enum.CollisionFidelity.Default Speed difference

3rd way (layers of wood)

the code I used if you want it
local DestroyAfter = game:GetService("Debris")
local GeometryService = game:GetService("GeometryService")

local plr = game.Players.LocalPlayer
local char = plr.Character
local camera = workspace.CurrentCamera
local mouse = plr:GetMouse()

local rayParams = RaycastParams.new()
rayParams.FilterType = Enum.RaycastFilterType.Exclude
rayParams.FilterDescendantsInstances = {char}

local cached = {}

function CreateSphares(count)
	local storage = Instance.new("Folder")
	storage.Parent = workspace
	for i=1,count do
		local sphere = Instance.new("Part")
		sphere.Shape = Enum.PartType.Ball
		sphere.Size = Vector3.one *1.5
		sphere.CFrame = CFrame.new(Vector3.new(0,5000,0))
		sphere.Anchored = true
		sphere.CanCollide = true
		sphere.Transparency = 1 
		sphere.Name = "CraterSphere"
		sphere.Parent = storage
		
		table.insert(cached,sphere)
	end
end

function GetSphare()	
	local sphare = cached[#cached]
	cached[#cached] = nil
	return sphare
end

function StartFiring()
	local CamCF = camera.CFrame
	
	local newRay = workspace:Raycast(
		CamCF.Position,
		CamCF.LookVector * 50,
		rayParams
	)
	
	if not newRay then return end
	
	local hitPart = newRay.Instance
	--print(hitPart)
	if hitPart then
		local original = hitPart
		local originalCF = original.CFrame
		local hitPos = newRay.Position
		
		-- [!]
		local sphere = GetSphare()
		sphere.Transparency = 1
		sphere.CFrame = CFrame.new(hitPos)

		local options = {
			CollisionFidelity = Enum.CollisionFidelity.Default,
			RenderFidelity = Enum.RenderFidelity.Automatic,
			SplitApart = true,
		}
		-- CSG subtract crater from the wood part
		local start = os.clock()
		local success, result = pcall(function()
			return GeometryService:SubtractAsync(original, {sphere},options)
		end)
		print(string.sub(os.clock() - start,1,5).."s")
		--print(success,result)
		if success and result then
			for i,newPart: PartOperation in result do
				newPart.Parent = original.Parent
				newPart.CFrame = original.CFrame
				newPart.Anchored = original.Anchored
			end

			original.Parent = nil
			original:Destroy()
			for _, otherPart in pairs({sphere}) do
				otherPart.Parent = nil
				otherPart:Destroy()
			end
		end
	end
end

CreateSphares(100)

mouse.Button1Down:Connect(function()
	StartFiring()
end)
1 Like

Note that if you use layers of wood, you might need to do precise (concave) collision on each layer separately or something… which can be slow…
(in fact, concave collision is slowest type I think… and is correlated to the amount of triangles (I think, I could be wrong) so more holes = slower)
Union speed is also correlated to the amount of triangles intersecting, that’s why thinner layers are faster.

unless collisions doesn’t matter

why?
it works great on my end using Enum.CollisionFidelity.Default
and it still allows for collisions to pass trough it.

Can you explain further? I think I may have misunderstood.

Well if it works it works, but the documentation specifically mentioned to not to use it for holes…

if it works great then it works I guess…

1 Like

but may not be highly accurate, especially for holes, doorways, and cavities in general.

oh yeah you’re correct, didn’t see it.
OP has to give up something up to gain performance anyway, they can try it in their game and if it doesn’t fit ( or need more accuracy ) they will have to think of another way.
or try this one

1 Like

hmm maybe, i like the plates of wood idea, should I switch to just negative unions instead of csg? also Im trying to go for more realistic looking destruction

If you want a more complicated shape for the hole via the union method, instead of doing instance.new you can do template:Clone() (you can make a custom negative union(s) to your desired detail, although more triangles are correlated with a slower union operation.)

^ that

try and see how it goes … but what’s csg?

you don’t have to make it realistic when destructing the wall but after.
for now just focus on making it work and performant then add the “realistic” part .I.E. Effects / Textures / Dust / Sounds and so on

CSG stands for constructive solid geometry (also known as unions)
the way godot document their CSG is more intuitive (in my opinion) (documentation)

Op saying realistic might be refering to the shape of the hole, which is why I recommended a template union of the desired hole shape.

2 Likes

Update : I created my own destruction system with indepth calculations. I got really over the top on this when theres probably some simpler one out there… It doesnt have the voxel features although but here it is.

1 Like