New Roblox In-Game CSG API is now available

modeling

#1

Hi everyone,

The In-Game CSG API we’ve been recently working on is now available. We’d like you to try it out and report issues in this thread. Its performance is acceptable for performing simple modifications on relatively simple CSG objects.

We are working on more comprehensive documentation and an announcement, so consider this an opportunity to try it out early and help us find and fix problems.

The API can be called from Scripts (but not LocalScripts). The API consists of two new methods which can be called in-game on part types already supported by the CSG engine.

PartInstance:UnionAsync(partsToUnion, [optional] collisionFidelity = "Default")
PartInstance:SubtractAsync(partsToSubtract, [optional] collisionFidelity = "Default")

The operations throw an exception if there was a problem in computing the result (too many triangles, unsupported part types, the usual). If the result is an empty mesh, they return nil. If everything went well, they return a PartOperation representing the computed result, which can be used in subsequent operations if necessary.

The operation leaves all involved parts unmodified, which will continue to be simulated and rendered normally if they were parented to the workspace. The resulting PartOperation is always un-parented and based on positions of the parts as they were when the operation was started. If the result is intended to replace its constituent parts in rendering and simulation, this needs to be performed explicitly in the script. Replication of the result will start once it is parented to the datamodel, and becomes visible after being parented to workspace.

For the time being, at least one of the supplied parts must be parented to a datamodel (not necessarily the workspace, if it is important to keep the parts hidden).

The part on which the method is called is the base part, from which things like material properties are inherited, and the first argument must be an array containing the other parts. The second argument is an optional parameter specifying the otherwise un-scriptable CollisionFidelity property. SubtractAsync will subtract all parts in the list from the base part, and UnionAsync unions them with the base part.

Thank you in advance!


Creating a hole in an object without having to make a bunch of small parts
#2

YES THANK YOU

I’ve been waiting for this for a long time now!


#3

I’ve been waiting for this for so long! woot!

Edit: Locard sniped my words, what the heck


#4

The day has finally come!


#5

Does this also mean that we will be able to create and set meshpart mesh ID’s soon too?


#6

HOLY SMOKES

This is an awesome birthday present


#7

It appears if you stop a simulation while UnionAsync or SubtractAsync is working, you can cause something to crash - Studio will throw up the “unexpected error occurred” dialog.

Studio will continue to work fine but will close if you click OK. If you ignore this dialog and attempt another simulation, these functions are dead and will no longer work.

Start a simulation and stop it again roughly one second after the first negate happens.
Baseplate.rbxl (13.6 KB)


#8

thanks, I’ve created a ticket for this.


#9

Don’t know how optimized this is yet but bullet holes can finally be a thing.

https://gyazo.com/ea9c53ef1cd64e0849a5db1952b52a1e


#10

For those with problems using the new API, it creates a new Union object and doesn’t change the original parts.

local newPart = Origin:SubtractAsync({Part table to subtract}, Enum.CollisionFidelity.CollisionFidelityOfChoice)
newPart .Parent = workspace

#11

:clap:


#12

YES, THE GODS HAVE ANSWERED US! I have to have a complete sentence to post :/.


#13

OH, SO MANY POSSIBILITIES :clap:


#14

YES!

This will make so many things possible!

I’m excited to try it!


#15

:weary::sweat_drops: y e s


#16

I must say, I felt really negated without this feature. I’m glad you guys unioned up to create something so awesome!

Seriously though, I remember a few years ago when something like this was unthinkable with CSG.


#18

thank%20you

This update is much appreciated and will definitely be very helpful with making games feel more realistic.


#19

WOO! Finally! This is going to be a game changer, I just hope it’s very optimised on a larger scale. If not, that’s perfectly fine.


#20

Here’s a code sample that I wrote for in-game CSG a few weeks ago.
It makes explosions carve spheres out of nearby parts!

----------------------------------------------------------------------------------------------
-- @CloneTrooper1019, 2018 <3
-- SwissCheese.lua
----------------------------------------------------------------------------------------------
 
local function createRegion3FromPart(part)
	local pos = part.Position
	local size = part.Size
	
	local corner0 = pos - (size/2)
	local corner1 = pos + (size/2)
	
	return Region3.new(corner0, corner1)
end

local function onExplosion(explosion)
	-- Ignore visual-only explosions
	if explosion.BlastPressure == 0 then
		return
	end
	
	-- Create the sphere that will be subtracted with this explosion.
	local radius = explosion.BlastRadius
	local negateSphere = Instance.new("Part")
	negateSphere.CFrame = CFrame.new(explosion.Position)
	negateSphere.Size = Vector3.new(radius, radius, radius)
	negateSphere.Shape = "Ball"
	
	-- Cast negateSphere into the 'Objects' type.
	local subtractor = {negateSphere}

	-- Capture the parts within a Region3 formed by the sphere.
	local region = createRegion3FromPart(negateSphere)
	local parts = workspace:FindPartsInRegion3(region)
	
	for _,part in pairs(parts) do
		local success, result = pcall(function ()
			return part:SubtractAsync(subtractor)
		end)
		
		if success then
			-- Move the children of the old part into the new part.
			for _,child in pairs(part:GetChildren()) do
				child.Parent = result
			end
			
			-- Swap out the part with the union.
			result.Parent = part.Parent
			result.CFrame = part.CFrame
			part:Destroy()
		else
			warn("SubtractAsync failed because:", result)
		end
	end
end

-- Listen for explosions being added to the workspace
local function onDescendantAdded(desc)
	if desc:IsA("Explosion") then
		onExplosion(desc)
	end
end

workspace.DescendantAdded:Connect(onDescendantAdded)
----------------------------------------------------------------------------------------------

#21

How often does real time CSG error compared to CSG in studio?