Model

Show Deprecated

Models are container objects, meaning they group objects together. They are best used to hold collections of BaseParts and have a number of functions that extend their functionality.

Models are intended to represent geometric groupings. If your grouping has no geometric interpretation, for instance a collection of Scripts, use a Folder instead.

Models whose constituent parts are joined together with joints (so that they can move around or be destroyed via physics simulation) usually have a PrimaryPart set, as it specifies which part within the model the pivot and bounding box will "follow" as the model moves. Static models which stay in one place do not benefit from having a primary part set.

Models have a wide range of applications, including Roblox player characters. They also have a number of unique behaviors that are important to keep in mind:

Code Samples

Basic Model Instantiation

1local function groupObjects(objectTable)
2 local model = Instance.new("Model")
3 for _, object in pairs(objectTable) do
4 object.Parent = model
5 end
6 return model
7end
8
9local objects = {
10 Instance.new("Part"),
11 Instance.new("Part"),
12}
13
14groupObjects(objects)

Summary

Properties

Sets the level of detail on Model instances when streaming is enabled.

Points to the primary part of the Model.

Editor-only property to set the orientation of the pivot. Scripts must use Model.WorldPivot instead.

NOT REPLICATED
NOT SCRIPTABLE

Editor-only property to set the position of the pivot. Scripts must use Model.WorldPivot instead.

NOT REPLICATED
NOT SCRIPTABLE

Determines where the pivot of a Model which does not have a set Model.PrimaryPart is located.

NOT REPLICATED

Events

Methods

BreakJoints(): void  

Breaks connections between BaseParts, including surface connections with any adjacent parts, WeldConstraints and all Welds and other JointInstances.


Returns a description of a volume that contains all parts of a Model.


Returns the size of the smallest bounding box that contains all of the BaseParts in the Model, aligned with the Model.PrimaryPart if it is set.

MakeJoints(): void  

Goes through all BaseParts in the Model. If any part's side has a SurfaceType that can make a joint it will create a joint with any adjacent parts.

MoveTo(position: Vector3): void  

Moves the Model.PrimaryPart to the given position. If a primary part has not been specified then the root part of the model will be used.

TranslateBy(delta: Vector3): void  

Shifts a Model by the given Vector3 offset, preserving the Model's orientation. If another BasePart or Terrain already exists at the new position then the Model will overlap said object.

Properties

LevelOfDetail

Sets the level of detail on Model instances. When Workspace.StreamingEnabled is enabled, parts outside of the streaming radius cannot be seen in live games. Using Model.LevelOfDetail, you can make these parts visible.

When set to StreamingMesh, representative meshes renders outside the streaming radius. Representative meshes, also called imposter meshes, are colored, coarse meshes that wrap around all child parts of a model.

Setting it to Disabled or Automatic (default) deletes what has been generated.

For Models with this property set to StreamingMesh, the Model Mesh, a coarse mesh representation of the Model including standard part types, mesh parts and CSG parts, is precomputed during the Studio session, and serialized and uploaded as part of the place file.

Modeling Tips:

  • Automatic update in Studio editing - Changes to the model or any of its children, e.g. adding/deleting/repositioning child parts, resetting colors, will automatically update the representative mesh.

  • Memory sharing - If you have hundreds of identical models in different sizes and orientations, it is more efficient to duplicate them over transforming to avoid individual editing unless necessary.

  • Outside of streaming radius - Streaming is distance based. We consider models crossing the boundary of the streaming sphere as outside. This requires the model size in StreamingMesh to be much smaller than the streaming radius.

  • Hierarchical models - If a model and its child or grandchild models are all set to StreamingMesh, only the ancestor, which is the top most model, will be rendered in game. For better memory performance, you may want to disable the LevelOfDetail property of child models before releasing your game.

  • Loose low-resolution wrapping - You can set a small workspace streaming radius value (e.g. 256 studs) to see representative meshes closer in Studio playsolo, but remember representative meshes are designed to be seen at a distance (1024 studs away). They may not capture model fidelity well to keep triangle count per model low.

  • Partial Streaming behavior - While a Model is not completely streamed in, the Model Mesh is rendered instead of individual parts of the model. Once all individual parts of a model are streamed in, individual parts render and the Model Mesh is ignored.

  • Physics Significance - Model Meshes have no physics significance. They act as non-existent with respect to raycasting, collision detection and physics simulation.

PrimaryPart

Points to the primary part of the Model. The primary part is the BasePart that acts as the physical reference for the pivot of the model. That is, when parts within the model are moved due to physical simulation or other means, the pivot will move in sync with the primary part. If the primary part is not set, the pivot will remain at the same location in world space even if parts within the model are moved.

Note that when setting this property, it must be a BasePart that is a descendant of the model. If you try to set Model.PrimaryPart to a BasePart that is not a descendant of the model, it will be set to that part but reset to nil during the next simulation step — this is legacy behavior to support scripts which assume they can temporarily set the primary part to a BasePart which isn't a descendant of the model.

The general rule for models is that:

  • Models whose parts are joined together via physical joints such as WeldConstraints or Motor6Ds should have a primary part assigned. For example, Roblox character models have their Model.PrimaryPart set to the HumanoidRootPart by default.
  • Static (usually Anchored) models which stay in one place unless a script explicitly moves them don't require a Model.PrimaryPart and tend not to benefit from having one set.

World Pivot Orientation

Not Replicated
Not Scriptable

Editor-only property to set the orientation of the pivot. Scripts must use Model.WorldPivot instead.

World Pivot Position

Not Replicated
Not Scriptable

Editor-only property to set the position of the pivot. Scripts must use Model.WorldPivot instead.

WorldPivot

Not Replicated

This property determines where the pivot of a Model which does not have a set Model.PrimaryPart is located. If the Model does have a PrimaryPart, the pivot of the Model is equal to the pivot of that primary part instead, and this WorldPivot property is ignored.

For a newly created Model, its pivot will be treated as the center of the bounding box of its contents until the first time its Model.WorldPivot property is set. Once the world pivot is set for the first time, it is impossible to restore this initial behavior.

Most commonly, moving the model with the Studio tools, or with a model movement function such as PVInstance:PivotTo(), Model:MoveTo(), and Model:SetPrimaryPartCFrame() will set the world pivot and thus end this new model behavior.

The purpose of this behavior is to allow Lua code to get a sensible pivot simply by creating a new model and parenting objects to it, avoiding the need to explicitly set Model.WorldPivot every time you create a model in code.


1local model = Instance.new("Model")
2workspace.BluePart.Parent = model
3workspace.RedPart.Parent = model
4model.Parent = workspace
5
6print(model:GetPivot()) -- Currently equal to the center of the bounding box containing "BluePart" and "RedPart"
7
8model:PivotTo(CFrame.new(0, 10, 0)) -- This works without needing to explicitly set "model.WorldPivot"
9

Events

Methods

BreakJoints

void

Breaks connections between BaseParts, including surface connections with any adjacent parts, WeldConstraints, and all Welds and other JointInstances.

When BreakJoints is used on a Player character Model, the character's Humanoid will die as it relies on the Neck joint.

Note that although joints produced by surface connections with adjacent Parts can technically be recreated using Model:MakeJoints(), this will only recreate joints produced by surfaces. Developers should not rely on this as following the joints being broken parts may no longer be in contact with each other.


Returns

void

Code Samples

Manual Joint Creation

1local JointsService = game:GetService("JointsService")
2
3local partA = script.Parent.PartA
4local partB = script.Parent.PartB
5
6local function join(part0, part1, jointClass, parent)
7 local newJoint = Instance.new(jointClass or "ManualWeld")
8 newJoint.Part0 = part0
9 newJoint.Part1 = part1
10 newJoint.C0 = CFrame.new()
11 newJoint.C1 = part1.CFrame:toObjectSpace(part0.CFrame)
12 newJoint.Parent = parent or part0
13
14 return newJoint
15end
16
17-- Create some joints and break them
18join(partA, partB)
19partA:BreakJoints()
20
21-- Glue joints are wobbly
22join(partA, partB, "Glue")
23partA:BreakJoints()
24
25-- Most of the time, joints ought to be put in JointsService
26join(partA, partB, "Weld", JointsService)
Break Character Joints

1local Players = game:GetService("Players")
2
3local function onCharacterAdded(character)
4 task.wait(3)
5 character:BreakJoints()
6end
7
8local function onPlayerAdded(player)
9 player.CharacterAdded:Connect(onCharacterAdded)
10end
11
12Players.PlayerAdded:Connect(onPlayerAdded)

GetBoundingBox

This function returns a description of a volume that contains all BasePart children within a Model. The volume's orientation is based on the orientation of the PrimaryPart, and matches the selection box rendered in Studio when the model is selected. The description is provided in the form of a CFrame orientation and Vector3 size.

Mirroring the behavior of Terrain:FillBlock(), it returns a CFrame representing the center of that bounding box and a Vector3 representing its size.

If there is no PrimaryPart for the model, the BoundingBox will be aligned to the world axes.

Example

Pictured below is a Model with a pink semitransparent Part whose CFrame and Size have been set to the return values of this function called on the model.

A model of an Observation Tower with a pink semitransparent part representing the volume returned by GetBoundingBox

Usage


1local model = workspace.Model
2local part = workspace.Part
3local orientation, size = model:GetBoundingBox()
4part.Size = size
5part.CFrame = orientation
6

Returns

A CFrame representing the orientation of the volume followed by a Vector3 representing the size of the volume.

GetExtentsSize

Returns the size of the smallest bounding box that contains all of the BaseParts in the Model. If Model.PrimaryPart exists then the bounding box will be aligned to that part. If a primary part has not been set then the function will chose a part in the model to align the bounding box to. As the the selection of this part is not deterministic it is recommended to set a Model.PrimaryPart to get consistent results with this function.

Note this function only returns the size of the smallest bounding box, and the developer must employ their own method to obtain the position of the bounding box.


Returns

The Vector3 extents size of the Model.

Code Samples

Model GetExtentsSize

1local model = Instance.new("Model")
2model.Parent = workspace
3
4local RNG = Random.new()
5
6for _ = 1, 5 do
7 local part = Instance.new("Part")
8 part.Anchored = true
9 part.Size = Vector3.new(RNG:NextNumber(0.05, 5), RNG:NextNumber(0.05, 5), RNG:NextNumber(0.05, 5))
10 part.Parent = model
11end
12
13print(model:GetExtentsSize())

MakeJoints

void

Deprecated

SurfaceType based joining is deprecated, do not use MakeJoints for new projects. WeldConstraints and HingeConstraints should be used instead.

Goes through all Parts in the Model and creates joints between the specified Parts and any planar touching surfaces, depending on the parts' surfaces.

  • Smooth surfaces will not create joints
  • Glue surfaces will create a Glue joint
  • Weld will create a Weld joint with any surface except for Unjoinable
  • Studs, Inlet, or Universal will each create a Snap joint with either of other the other two surfaces (e.g. Studs with Inlet and Universal)
  • Hinge and Motor surfaces create Rotate and RotateV joint instances

This function will not work if the Part is not a descendant of Workspace. Therefore developers must first ensure the Model is parented to Workspace before using MakeJoints.


Returns

void

Code Samples

Model MakeJoints

1local model = Instance.new("Model")
2
3-- create one part on top of another
4local topPart = Instance.new("Part")
5topPart.Size = Vector3.new(5, 1, 5)
6topPart.Position = Vector3.new(0, 10, 0)
7topPart.BrickColor = BrickColor.new("Bright green")
8topPart.Anchored = true -- anchor the top part
9topPart.Parent = model
10
11local bottomPart = Instance.new("Part")
12bottomPart.Size = Vector3.new(8, 1, 8)
13bottomPart.Position = Vector3.new(0, 9, 0)
14bottomPart.BrickColor = BrickColor.new("Bright green")
15bottomPart.Anchored = false -- leave bottom unanchored
16bottomPart.Parent = model
17
18topPart.BottomSurface = Enum.SurfaceType.Smooth
19topPart.TopSurface = Enum.SurfaceType.Smooth
20bottomPart.BottomSurface = Enum.SurfaceType.Smooth
21bottomPart.TopSurface = Enum.SurfaceType.Weld -- 'Weld' to create a joint
22
23model.Parent = workspace
24
25model:MakeJoints()
26
27task.wait(2)
28-- unanchor the bottom part - part does not fall
29print("Unanchored!")
30bottomPart.BrickColor = BrickColor.new("Bright red")
31bottomPart.Anchored = false
32
33task.wait(2)
34-- break the joints using an explosion - part falls
35local explosion = Instance.new("Explosion")
36explosion.Position = bottomPart.Position
37explosion.Parent = workspace
Simple Joint Creation

1local partA = script.Parent.PartA
2local partB = script.Parent.PartB
3
4-- Move PartB on top of PartA
5partB.CFrame = partA.CFrame * CFrame.new(0, partB.Size.Y / 2 + partA.Size.Y / 2, 0)
6-- Studs and Inlet will make joints
7partA.TopSurface = Enum.SurfaceType.Studs
8partB.BottomSurface = Enum.SurfaceType.Inlet
9-- Automatically create a joint between PartA and PartB
10partA:MakeJoints()

MoveTo

void

Moves the Model.PrimaryPart to the given position. If a primary part has not been specified then the root part of the model will be used. Because the root part is not deterministic, it is recommended to always set a Model.PrimaryPart when using MoveTo.

If there are any obstructions where the model is to be moved to, such as Terrain or other BaseParts, then the model will be moved up in the Y direction until there is nothing in the way. If this behavior is not desired, Model:SetPrimaryPartCFrame() should be used instead.

Note that rotation is not preserved when moving a model with MoveTo. It is recommended to use either Model:TranslateBy() or Model:SetPrimaryPartCFrame() if the current rotation of the model needs to be preserved.

Parameters

position: Vector3

The Datatype.Position the Model is to be moved to.


Returns

void

Code Samples

Model MoveTo

1local START_POSITION = Vector3.new(-20, 10, 0)
2local END_POSITION = Vector3.new(0, 10, 0)
3
4local model = Instance.new("Model")
5model.Parent = workspace
6
7local part1 = Instance.new("Part")
8part1.Size = Vector3.new(4, 4, 4)
9part1.Position = START_POSITION
10part1.Anchored = true
11part1.BrickColor = BrickColor.new("Bright yellow")
12part1.Parent = model
13
14local part2 = Instance.new("Part")
15part2.Size = Vector3.new(2, 2, 2)
16part2.Position = START_POSITION + Vector3.new(0, 3, 0)
17part2.Anchored = true
18part2.BrickColor = BrickColor.new("Bright blue")
19part2.Parent = model
20
21model.PrimaryPart = part1
22model.Parent = workspace
23
24local obstruction = Instance.new("Part")
25obstruction.Name = "Obstruction"
26obstruction.Size = Vector3.new(10, 10, 10)
27obstruction.Position = Vector3.new(0, 10, 0)
28obstruction.Anchored = true
29obstruction.BrickColor = BrickColor.new("Bright green")
30obstruction.Parent = workspace
31
32task.wait(3)
33
34model:MoveTo(END_POSITION)

TranslateBy

void

Shifts a Model by the given Vector3 offset, preserving the Model's orientation. If another BasePart or Terrain already exists at the new position then the Model will overlap said object.

The translation is applied in world space rather than object space, meaning even if the model's parts are orientated differently it will still move along the standard axis.

Parameters

delta: Vector3

The Vector3 to translate the Model by,.


Returns

void

Code Samples

Model TranslateBy

1local START_POSITION = Vector3.new(-20, 10, 0)
2local END_POSITION = Vector3.new(0, 10, 0)
3
4local model = Instance.new("Model")
5
6local part1 = Instance.new("Part")
7part1.Size = Vector3.new(4, 4, 4)
8part1.CFrame = CFrame.new(START_POSITION) * CFrame.Angles(0, math.rad(45), 0)
9part1.Anchored = true
10part1.BrickColor = BrickColor.new("Bright yellow")
11part1.Parent = model
12
13local part2 = Instance.new("Part")
14part2.Size = Vector3.new(2, 2, 2)
15part2.CFrame = part1.CFrame * CFrame.new(0, 3, 0)
16part2.Anchored = true
17part2.BrickColor = BrickColor.new("Bright blue")
18part2.Parent = model
19
20model.PrimaryPart = part1
21model.Parent = workspace
22
23local obstruction = Instance.new("Part")
24obstruction.Name = "Obstruction"
25obstruction.Size = Vector3.new(10, 10, 10)
26obstruction.Position = Vector3.new(0, 10, 0)
27obstruction.Transparency = 0.5
28obstruction.Anchored = true
29obstruction.BrickColor = BrickColor.new("Bright green")
30obstruction.Parent = workspace
31
32task.wait(3)
33-- use TranslateBy to shift the model into the obstruction
34model:TranslateBy(END_POSITION - START_POSITION)