--- title: Solid modeling description: Solid modeling is the process of joining parts together to form complex shapes. --- **Solid modeling** is the process of joining [parts](../parts/index.md) 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 toolbar. Solid modeling tools highlighted in Studio's toolbar.
Tool Shortcut Description
[Union](#union-parts) ShiftCtrlG (Windows)
Shift⌘G (Mac)
Join two or more parts together to form a single solid union.
[Intersect](#intersect-parts) ShiftCtrlI (Windows)
Shift⌘I (Mac)
Intersect overlapping parts into a single solid intersection.
[Negate](#negate-parts) ShiftCtrlN (Windows)
Shift⌘N (Mac)
Negate parts, useful for making holes and indentations.
[Separate](#separate-unions-or-intersections) ShiftCtrlU (Windows)
Shift⌘U (Mac)
Separate the union or intersection back into its individual parts.
## Union parts The **Union** tool joins two or more parts together to form a single solid `Class.UnionOperation`. By default, a new union respects the `Class.BasePart.Color|Color` property of each of its parts, although you can enable its `Class.PartOperation.UsePartColor|UsePartColor` property to change the entire union to a specific color. Block and cylinder parts overlapping Parts joined together into a single solid union To combine parts together into a union: 1. Select all parts that you want to join together. 2. Click the **Union** button. All of the parts combine into one solid `Class.UnionOperation` with the name **Union**. ## Intersect parts The **Intersect** tool intersects overlapping parts into a single solid `Class.IntersectOperation`. By default, the face colors of the resulting intersection are borrowed from the `Class.BasePart.Color|Color` property of the original parts, although you can enable its `Class.PartOperation.UsePartColor|UsePartColor` property to change the entire intersection to a specific color.
Block and cylinder parts overlapping
Parts intersected into a new solid model
To intersect overlapping parts together: 1. Select all parts that you want to intersect. 2. Click the **Intersect** button. All of the parts combine into one solid `Class.IntersectOperation` with the name **Intersection**. ## Negate parts The **Negate** tool negates a part so that when it's [unioned with another part](#union-parts), the shape of the negated part is **subtracted** from the other part.
Negated block overlapping a cylinder
Negated part subtracted from cylinder
To subtract a part from other overlapping parts: 1. Select the part you want to negate from other parts. 1. Click **Negate**. The part becomes a `Class.NegateOperation` with the name **NegativePart** and turns pink and translucent to indicate its state. 1. Select both the negated part and the parts you want to subtract it from. 1. Click **Union**. The negated part is cut out from the included overlapping parts. ## Separate unions or intersections The **Separate** tool separates a `Class.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 the union or intersection. 1. Click **Separate**. The parts separate back into their original form. ## Render fidelity By default, new solid modeled operations will always be shown in `Enum.RenderFidelity.Automatic|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 `Class.PartOperation.SmoothingAngle|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.
Solid modeled part with SmoothingAngle of 0
`Class.PartOperation.SmoothingAngle|SmoothingAngle` = 0
Solid modeled part with SmoothingAngle of 50
`Class.PartOperation.SmoothingAngle|SmoothingAngle` = 50
## 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 `Class.BasePart:UnionAsync()|UnionAsync()`, `Class.BasePart:IntersectAsync()|IntersectAsync()`, and `Class.BasePart:SubtractAsync()|SubtractAsync()`. All of these methods must be called on a `Class.BasePart` and they all require an array of one or more parts to union with, intersect with, or subtract from the calling part. In-experience solid modeling operations are asynchronous, meaning they can impact performance. For best results, you should not perform a large series of `Class.BasePart:UnionAsync()|UnionAsync()`, `Class.BasePart:IntersectAsync()|IntersectAsync()`, or `Class.BasePart:SubtractAsync()|SubtractAsync()` calls in quick succession. When performing a `Class.BasePart:UnionAsync()|UnionAsync()`, `Class.BasePart:IntersectAsync()|IntersectAsync()`, or `Class.BasePart:SubtractAsync()|SubtractAsync()` operation, the following properties from the calling part are applied to the resulting union: `Class.BasePart.Color|Color`, `Class.BasePart.Material|Material`, `Class.BasePart.MaterialVariant|MaterialVariant`, `Class.BasePart.Reflectance|Reflectance`, `Class.BasePart.Transparency|Transparency`, `Class.BasePart.Anchored|Anchored`, `Class.BasePart.CanCollide|CanCollide`, `Class.BasePart.Density|Density`, `Class.BasePart.Elasticity|Elasticity`, `Class.BasePart.ElasticityWeight|ElasticityWeight`, `Class.BasePart.Friction|Friction`, and `Class.BasePart.FrictionWeight|FrictionWeight`. ### UnionAsync() To demonstrate `Class.BasePart:UnionAsync()|UnionAsync()`, the following `Class.Script` uses the **Part1** `Class.BasePart` from the workspace, unions it together with the **Part2**, **Part3**, and **Part4** `Class.BasePart|BaseParts`, then parents the resulting `Class.UnionOperation` to the workspace at the original position of **Part1**. ```lua highlight="6" local Workspace = game:GetService("Workspace") 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 `Class.BasePart:IntersectAsync()|IntersectAsync()`, the following `Class.Script` uses the **Part1** `Class.BasePart` from the workspace, intersects it with the **Part2** and **Part3** `Class.BasePart|BaseParts`, then parents the resulting `Class.IntersectOperation` to the workspace at the original position of **Part1**. ```lua highlight="6" local Workspace = game:GetService("Workspace") 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 `Class.BasePart:SubtractAsync()|SubtractAsync()`, the following `Class.Script` uses the **Part1** `Class.BasePart` from the workspace, negates the **Part2**, **Part3**, and **Part4** `Class.BasePart|BaseParts` from it, then parents the resulting `Class.UnionOperation` to the workspace at the original position of **Part1**. ```lua highlight="6" local Workspace = game:GetService("Workspace") 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 ```