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.
Tool | Shortcut | Description |
---|---|---|
Union | ShiftCtrlG (Windows) Shift⌘G (Mac) | Join two or more parts together to form a single solid union. |
Intersect | ShiftCtrlI (Windows) Shift⌘I (Mac) | Intersect overlapping parts into a single solid intersection. |
Negate | ShiftCtrlN (Windows) Shift⌘N (Mac) | Negate parts, useful for making holes and indentations. |
Separate | ShiftCtrlU (Windows) Shift⌘U (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.
To combine parts together into a union:
Select all parts to join together.
Click the Union button. All of the parts combine into one solid UnionOperation with the name Union.
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.
To intersect overlapping parts together:
Select all parts to intersect.
Click the Intersect button. All of the parts combine into one solid IntersectOperation with the name Intersection.
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.
To subtract a part from other overlapping parts:
Select the part you would like to negate from other parts.
Click Negate. The part becomes a NegateOperation with the name NegativePart and turns pink and translucent to indicate its state.
Select both the negated part and the parts you want to subtract it from.
Click Union. The negated part is cut out from the included overlapping parts.
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:
Select a UnionOperation.
Click Separate. The parts separate back into their original form.
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 Camera | Render Fidelity |
---|---|
Less than 250 studs | Highest |
250-500 studs | Medium |
500 or more studs | Lowest |
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