Solid Modeling

Solid modeling is the process of joining parts together in unique ways to form more complex shapes known as unions or intersections. You can perform four solid modeling operations using the tools within the Model tab.

Studio's Model tab with the Solid Modeling tools highlighted.
ToolShortcutDescription
UnionShiftCtrlG (Windows)
ShiftG (Mac)
Join two or more parts together to form a single solid union.
IntersectShiftCtrlI (Windows)
ShiftI (Mac)
Intersect overlapping parts into a single solid intersection.
NegateShiftCtrlN (Windows)
ShiftN (Mac)
Negate parts, useful for making holes and indentations.
SeparateShiftCtrlU (Windows)
ShiftU (Mac)
Separate the union or intersection back into its individual parts.

Unioning Parts

The Union tool joins two or more parts together to form a single solid UnionOperation. By default, a new union respects the Color property of each of its parts, although you can enable its UsePartColor property to change the entire union to a specific color.

Block and cylinder parts overlapping

To combine parts together into a union:

  1. Select all parts to join together.

  2. Click the Union button. All of the parts combine into one solid UnionOperation with the name Union.

    Union tool indicated in Model tab

Intersecting Parts

The Intersect tool intersects overlapping parts into a single solid IntersectOperation. By default, the face colors of the resulting intersection are borrowed from the Color property of the original parts, although you can enable its UsePartColor property to change the entire intersection to a specific color.

Block and cylinder parts overlapping

To intersect overlapping parts together:

  1. Select all parts to intersect.

  2. Click the Intersect button. All of the parts combine into one solid IntersectOperation with the name Intersection.

    Intersect tool indicated in Model tab

Negating Parts

The Negate tool negates a part so that when it's unioned with another part, the shape of the negated part is subtracted from the other part.

Negated block overlapping a cylinder

To subtract a part from other overlapping parts:

  1. Select the part you would like to negate from other parts.

  2. Click Negate. The part becomes a NegateOperation with the name NegativePart and turns pink and translucent to indicate its state.

    Negate tool indicated in Model tab
  3. Select both the negated part and the parts you want to subtract it from.

  4. Click Union. The negated part is cut out from the included overlapping parts.

    Union tool indicated in Model tab

Separating Unions or Intersections

The Separate tool separates a UnionOperation back into its individual parts, essentially serving as an "undo" tool for unions and intersections.

To separate a union or intersection back into individual parts:

  1. Select a UnionOperation.

  2. Click Separate. The parts separate back into their original form.

    Separate tool indicated in Model tab

Render Fidelity

By default, new solid modeled operations will always be shown in Automatic render fidelity, meaning the part's detail is based on its distance from the camera as outlined in the following table.

Distance From CameraRender Fidelity
Less than 250 studsHighest
250-500 studsMedium
500 or more studsLowest

Smoothing Angle

A solid modeled part's SmoothingAngle property smooths angles between adjacent surfaces of the same color or material. A higher value produces a smoother appearance while a lower value produces a rougher appearance with more sharp edges.

While a value between 30 and 70 degrees usually produces a good result, values between 90 and 180 are not recommended as they may cause a "shadowing" effect on unions and intersections with sharp edges.

In-Experience Solid Modeling

In addition to the Union, Intersect, and Negate tools in Studio, you can allow players to use solid modeling operations while inside an experience through UnionAsync(), IntersectAsync(), and SubtractAsync(). All of these methods must be called on a BasePart and they all require an array of one or more parts to union with, intersect with, or subtract from the calling part.

UnionAsync()

To demonstrate UnionAsync(), the following Script uses the Part1 BasePart from the workspace, unions it together with the Part2, Part3, and Part4 BaseParts, then parents the resulting UnionOperation to the workspace at the original position of Part1.


local mainPart = workspace.Part1
local otherParts = {workspace.Part2, workspace.Part3, workspace.Part4}
-- Perform union operation
local success, newUnion = pcall(function()
return mainPart:UnionAsync(otherParts)
end)
-- If operation succeeds, position it at the same location and parent it to the workspace
if success and newUnion then
newUnion.Position = mainPart.Position
newUnion.Parent = workspace
end
-- Destroy original parts which remain intact after operation
mainPart:Destroy()
for _, part in otherParts do
part:Destroy()
end

IntersectAsync()

To demonstrate IntersectAsync(), the following Script uses the Part1 BasePart from the workspace, intersects it with the Part2 and Part3 BaseParts, then parents the resulting IntersectOperation to the workspace at the original position of Part1.


local mainPart = workspace.Part1
local otherParts = {workspace.Part2, workspace.Part3}
-- Perform intersect operation
local success, newIntersect = pcall(function()
return mainPart:IntersectAsync(otherParts)
end)
-- If operation succeeds, position it at the same location and parent it to the workspace
if success and newIntersect then
newIntersect.Position = mainPart.Position
newIntersect.Parent = workspace
end
-- Destroy original parts which remain intact after operation
mainPart:Destroy()
for _, part in otherParts do
part:Destroy()
end

SubtractAsync()

To demonstrate SubtractAsync(), the following Script uses the Part1 BasePart from the workspace, negates the Part2, Part3, and Part4 BaseParts from it, then parents the resulting UnionOperation to the workspace at the original position of Part1.


local mainPart = workspace.Part1
local otherParts = {workspace.Part2, workspace.Part3, workspace.Part4}
-- Perform subtract operation
local success, newSubtract = pcall(function()
return mainPart:SubtractAsync(otherParts)
end)
-- If operation succeeds, position it at the same location and parent it to the workspace
if success and newSubtract then
newSubtract.Position = mainPart.Position
newSubtract.Parent = workspace
end
-- Destroy original parts which remain intact after operation
mainPart:Destroy()
for _, part in otherParts do
part:Destroy()
end