Model
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:
- When a Humanoid and a Part named Head are parented under a model, a name/health GUI will appear over the model; see Character Name/Health Display for details.
- If a part's position on the Y axis hits the Workspace.FallenPartsDestroyHeight value, and it was the last object inside of a Model, the model will be destroyed as well.
- When used in a place with Workspace.StreamingEnabled set to true, the value of ModelStreamingMode controls various behaviors around how the model and any descendants are replicated and/or removed from clients. In addition, the value of LevelOfDetail impacts rendering of the model.
As with all Instance types, the fact that a parent Model is replicated to a client does not guarantee that all its children are replicated. This is particularly important if these instances are being accessed by code running on the client, such as in a LocalScript. Using ModelStreamingMode with values such as Atomic can ensure that the entire model and all of its descendants are present if the parent model exists on the client, or you can use WaitForChild() when atomicity is not desired.
Code Samples
The following sample includes a basic function that takes a table of objects and parents them into a new Model, returning that Model.
local function groupObjects(objectTable)
local model = Instance.new("Model")
for _, object in pairs(objectTable) do
object.Parent = model
end
return model
end
local objects = {
Instance.new("Part"),
Instance.new("Part"),
}
groupObjects(objects)
Summary
Properties
Sets the level of detail on the model for experiences with instance streaming enabled.
Controls the model streaming behavior on Models when instance streaming is enabled.
The primary part of the Model, or nil if not explicitly set.
Editor-only property used to scale the model around its pivot. Setting this property will move the scale as though Model/ScaleTo was called on it.
Determines where the pivot of a Model which does not have a set Model.PrimaryPart is located.
Methods
Sets this model to be persistent for the specified player. Model.ModelStreamingMode must be set to PersistentPerPlayer for behavior to be changed as a result of addition.
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.
This value historically returned the CFrame of a central position in the model.
Returns the Vector3 size of the Model.
Returns all the Player objects that this model object is persistent for. Behavior varies based on whether this method is called from a Script or a LocalScript.
Returns the CFrame of the model's Model.PrimaryPart. This function will throw an error if no primary part exists for the Model.
Returns the canonical scale of the model, which defaults to 1 for newly created models and will change as it is scaled via Model/ScaleTo.
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.
Moves the PrimaryPart to the given position. If a primary part has not been specified, the root part of the model will be used.
Makes this model no longer persistent for specified player. Model.ModelStreamingMode must be set to PersistentPerPlayer for behavior to be changed as a result of removal.
Resets the rotation of the model's parts to the previously set identity rotation, which is done through the Model:SetIdentityOrientation() method.
Sets the scale factor of the model, adjusting the sizing and location of all descendant Instances such that they have that scale factor relative to their initial sizes and locations when scale factor was 1.
Sets the identity rotation of the given model, allowing you to reset the rotation of the entire model later, through the use of the ResetOrientationToIdentity method.
Sets the BasePart.CFrame of the model's Model.PrimaryPart. All other parts in the model will also be moved and will maintain their orientation and offset respective to the Model.PrimaryPart.
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.
Gets the pivot of a PVInstance.
Transforms the PVInstance along with all of its descendant PVInstances such that the pivot is now located at the specified CFrame.
Properties
LevelOfDetail
Sets the level of detail on the model for experiences with instance streaming enabled.
When set to StreamingMesh, a lower resolution "imposter" mesh (colored, coarse mesh that wraps around all child parts of the model) renders outside the streaming radius.
When set to Disabled or Automatic, lower resolution meshes will not be displayed.
ModelStreamingMode
Controls how Models are streamed in and out when instance streaming is enabled. Behavior depends on the selected enum. Has no effect when streaming is not enabled.
This property should only be changed in Studio via the Properties window when streaming is enabled, or in Scripts, but never in LocalScripts (doing so can result in undefined behavior).
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.
Note that Models do not have PrimaryPart set by default. If you are creating a model that needs to be acted upon by physics, you should manually set this property in Studio or within a script. 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.
Also 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.
Code Samples
This code sample creates and throws a dice model, then outputs whether it landed with the blue side facing up. If Model.PrimaryPart was not set, the pivot / bounding box of the dice would rotate, as the parts inside of it are physically simulated during the roll.
-- Create a dice model with two halves and attach them together
local diceModel = Instance.new("Model")
diceModel.Name = "ChanceCube"
local diceTop = Instance.new("Part")
diceTop.Size = Vector3.new(4, 2, 4)
diceTop.Position = Vector3.new(0, 1, 0)
diceTop.Color = Color3.new(0, 0, 1)
diceTop.Parent = diceModel
local diceBottom = diceTop:Clone()
diceBottom.Position = Vector3.new(0, -1, 0)
diceBottom.Color = Color3.new(1, 0, 0)
diceBottom.Parent = diceModel
local weld = Instance.new("WeldConstraint")
weld.Part0 = diceTop
weld.Part1 = diceBottom
weld.Parent = diceModel
-- Put the dice up in the air above the workspace origin (does not require a primary part)
diceModel.Parent = workspace
diceModel:PivotTo(CFrame.new(0, 10, 0))
-- Assign the primary part before physical simulation
-- Without this line, the script will always output the same thing and the bounding box of the model will not change orientation
diceModel.PrimaryPart = diceTop
-- Wait a bit before rolling the dice (let it settle onto the floor)
for i = 5, 1, -1 do
print("Rolling dice in...", i)
task.wait(1)
end
diceTop:ApplyAngularImpulse(Vector3.new(15000, 1000, 5000))
diceTop:ApplyImpulse(Vector3.new(0, 3000, 0))
task.wait(1)
-- Wait for the roll to complete
while diceTop.AssemblyLinearVelocity.Magnitude > 0.1 or diceTop.AssemblyAngularVelocity.Magnitude > 0.1 do
task.wait()
end
-- Get the dice orientation, impacted by the primary part
local orientation = diceModel:GetBoundingBox()
if orientation.YVector.Y > 0.5 then
print("It's the boy!")
else
print("It's his mother!")
end
Scale
Setting this property in the properties pane will scale the model as though Model/ScaleTo was called on it, scaling all descendant Instances in the model such that the model has the specified scale factor relative to its original size.
This property is only available in Studio and will throw an error if used in a Script or LocalScript. Model/ScaleTo and Model/GetScale should be used from scripts.
WorldPivot
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 model movement functions such as PVInstance:PivotTo() and Model:MoveTo(), will set the world pivot and thus end this new model behavior.
The purpose of this behavior is to allow Luau 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.
local Workspace = game:GetService("Workspace")local model = Instance.new("Model")Workspace.BluePart.Parent = modelWorkspace.RedPart.Parent = modelmodel.Parent = Workspaceprint(model:GetPivot()) -- Currently equal to the center of the bounding box containing "BluePart" and "RedPart"model:PivotTo(CFrame.new(0, 10, 0)) -- This works without needing to explicitly set "model.WorldPivot"
Code Samples
This code sample shows a custom function for resetting the pivot of a model back to the center of that model's bounding box.
local function resetPivot(model)
local boundsCFrame = model:GetBoundingBox()
if model.PrimaryPart then
model.PrimaryPart.PivotOffset = model.PrimaryPart.CFrame:ToObjectSpace(boundsCFrame)
else
model.WorldPivot = boundsCFrame
end
end
resetPivot(script.Parent)
Methods
BreakJoints
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
Code Samples
In this sample the joints in every Player character Model added will be broken 3 seconds after spawning. Breaking these joints will cause the Humanoid to die.
local Players = game:GetService("Players")
local function onCharacterAdded(character)
task.wait(3)
character:BreakJoints()
end
local function onPlayerAdded(player)
player.CharacterAdded:Connect(onCharacterAdded)
end
Players.PlayerAdded:Connect(onPlayerAdded)
This code sample demonstrates manual creation of joints on two parts that are siblings of the script (PartA and PartB). It creates a joints on two touching parts with compatible surface types (Studs and Inlet).
local JointsService = game:GetService("JointsService")
local partA = script.Parent.PartA
local partB = script.Parent.PartB
local function join(part0, part1, jointClass, parent)
local newJoint = Instance.new(jointClass or "ManualWeld")
newJoint.Part0 = part0
newJoint.Part1 = part1
newJoint.C0 = CFrame.new()
newJoint.C1 = part1.CFrame:toObjectSpace(part0.CFrame)
newJoint.Parent = parent or part0
return newJoint
end
-- Create some joints and break them
join(partA, partB)
partA:BreakJoints()
-- Glue joints are wobbly
join(partA, partB, "Glue")
partA:BreakJoints()
-- Most of the time, joints ought to be put in JointsService
join(partA, partB, "Weld", JointsService)
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. 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 bounding box will be aligned to the world axes.
local Workspace = game:GetService("Workspace")local model = Workspace.Modellocal part = Workspace.Partlocal orientation, size = model:GetBoundingBox()-- Resize and position part equal to bounding box of modelpart.Size = sizepart.CFrame = orientation
Returns
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 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
Code Samples
The code sample below demonstrates how Model.GetExtentsSize can be used to get the size of the bounding box containing the parts.
local model = Instance.new("Model")
model.Parent = workspace
local RNG = Random.new()
for _ = 1, 5 do
local part = Instance.new("Part")
part.Anchored = true
part.Size = Vector3.new(RNG:NextNumber(0.05, 5), RNG:NextNumber(0.05, 5), RNG:NextNumber(0.05, 5))
part.Parent = model
end
print(model:GetExtentsSize())
GetModelCFrame
This value historically returned the CFrame of a central position in the model.
Returns
GetModelSize
The GetModelSize function returns the Vector3 size of the Model.
Returns
Code Samples
This code would create a model, put some parts in it, position them randomly, and then print its size:
local model = Instance.new("Model")
model.Parent = workspace
local RNG = Random.new()
for _ = 1, 5 do
local part = Instance.new("Part")
part.Parent = model
part.Anchored = true
part.Size = Vector3.new(RNG:NextNumber(0.05, 5), RNG:NextNumber(0.05, 5), RNG:NextNumber(0.05, 5))
end
print(model:GetModelSize())
GetPersistentPlayers
When this method is called from a Script, it returns all the Player objects that this model is persistent for. When called from a LocalScript, this method only checks if this model is persistent for the LocalPlayer.
Returns
A table with all the Player objects that this model object is persistent for.
GetPrimaryPartCFrame
This function has been superseded by PVInstance:GetPivot() which acts as a replacement and does not change your code's behavior. Use PVInstance:GetPivot() for new work and migrate your existing Model:GetPrimaryPartCFrame() calls when convenient.
Returns the CFrame of the model's Model.PrimaryPart.
This function is equivalent to the following.
Model.PrimaryPart.CFrame
Note this function will throw an error if no primary part exists for the Model. If this behavior is not desired developers can do the following, which will be equal to nil if there is no primary part.
local cFrame = Model.PrimaryPart and Model.PrimaryPart.CFrame
Returns
Code Samples
The following code demonstrates how GetPrimaryPartCFrame and SetPrimaryPartCFrame can be used to rotate a model.
A simple model is created in the Workspace and a loop is started that will rotate the model 10 degrees around the Y axis every 0.2 seconds.
local START_POSITION = Vector3.new(0, 10, 0)
local model = Instance.new("Model")
local part1 = Instance.new("Part")
part1.Size = Vector3.new(4, 4, 4)
part1.CFrame = CFrame.new(START_POSITION)
part1.Anchored = true
part1.BrickColor = BrickColor.new("Bright yellow")
part1.Parent = model
local part2 = Instance.new("Part")
part2.Size = Vector3.new(2, 2, 2)
part2.CFrame = part1.CFrame * CFrame.new(0, 3, 0)
part2.Anchored = true
part2.BrickColor = BrickColor.new("Bright blue")
part2.Parent = model
-- set the primary part
model.PrimaryPart = part1
model.Parent = workspace
while true do
local primaryPartCFrame = model:GetPrimaryPartCFrame()
local newCFrame = primaryPartCFrame * CFrame.Angles(0, math.rad(1), 0)
model:SetPrimaryPartCFrame(newCFrame)
task.wait()
end
GetScale
Models contain a persistent canonical scale factor, which starts out at 1 for newly created models and changes as the model is scaled by calling Model/ScaleTo. This function returns the current canonical scale factor of the model.
The current scale factor does not directly impact the size of Instances under the model. It is used for content authoring and scripting purposes to remember how the model has been scaled relative to its original size.
Within a given session, the model will cache the precise original size information of the descendant Instances after the first Model/ScaleTo call. This means that calling ScaleTo(x) followed by ScaleTo(1) will get you back exactly the original configuration of the model with no floating point drift. Avoiding floating point drift is the motivation for having a ScaleTo function instead of a ScaleBy function.
The scale factor does impact engine behavior in one way: The scale factor of a model will be applied to joint offsets of animations played on an AnimationController under that model, so that animated rigs will correctly play back animations even when scaled.
Returns
The current canonical scale factor of the model.
Code Samples
This code sample demonstrates substituting in a replacement for all the copies of a tree model using PivotTo and ScaleTo. The pivot and scale of the models are used as a reference ensuring that the relative sizes and locations of the replacement models match those of the originals.
local CollectionService = game:GetService("CollectionService")
local ReplicatedStorage = game:GetService("ReplicatedStorage")
-- Find all the models with the tag we want to replace
local items = CollectionService:GetTagged("Tree")
local newModel = ReplicatedStorage.FancyTreeReplacementModel
for _, item in items do
-- Make the new item and scale / position it where the old one was
local newItem = newModel:Clone()
newItem:ScaleTo(item:GetScale())
newItem:PivotTo(item:GetPivot())
-- Add the same tag to the replacement
CollectionService:AddTag(newItem, "Tree")
-- Delete the old item and parent the new one
newItem.Parent = item.Parent
item:Destroy()
end
MakeJoints
SurfaceType based joining is deprecated. Don't use MakeJoints for new projects. Use WeldConstraints and HingeConstraints 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)
This function doesn't work if the Part is not a descendant of Workspace. Therefore, you must first ensure the Model is parented to Workspace before using MakeJoints.
Returns
Code Samples
This code sample demonstrates how joints can be made using the Model:MakeJoints function.
A model is instanced, with two parts on top of each other. The top part is anchored and the bottom part is not. Normally, when parented to the Workspace the bottom part would fall to the Baseplate.
However, as TopSurface property of the bottom part is set to Enum.SurfaceType.Weld, this means that when Model:MakeJoints is ran a connection is made between them.
Therefore the bottom part does not drop until the joints in the model are broken. This is often done using Model:BreakJoints, but in this example the connection is broken using an explosion.
local model = Instance.new("Model")
-- create one part on top of another
local topPart = Instance.new("Part")
topPart.Size = Vector3.new(5, 1, 5)
topPart.Position = Vector3.new(0, 10, 0)
topPart.BrickColor = BrickColor.new("Bright green")
topPart.Anchored = true -- anchor the top part
topPart.Parent = model
local bottomPart = Instance.new("Part")
bottomPart.Size = Vector3.new(8, 1, 8)
bottomPart.Position = Vector3.new(0, 9, 0)
bottomPart.BrickColor = BrickColor.new("Bright green")
bottomPart.Anchored = false -- leave bottom unanchored
bottomPart.Parent = model
topPart.BottomSurface = Enum.SurfaceType.Smooth
topPart.TopSurface = Enum.SurfaceType.Smooth
bottomPart.BottomSurface = Enum.SurfaceType.Smooth
bottomPart.TopSurface = Enum.SurfaceType.Weld -- 'Weld' to create a joint
model.Parent = workspace
model:MakeJoints()
task.wait(2)
-- unanchor the bottom part - part does not fall
print("Unanchored!")
bottomPart.BrickColor = BrickColor.new("Bright red")
bottomPart.Anchored = false
task.wait(2)
-- break the joints using an explosion - part falls
local explosion = Instance.new("Explosion")
explosion.Position = bottomPart.Position
explosion.Parent = workspace
This code sample demonstrates creation of joints on two parts that are siblings of the script (PartA and PartB). It uses MakeJoints on two touching parts with compatible surface types (Studs and Inlet).
local partA = script.Parent.PartA
local partB = script.Parent.PartB
-- Move PartB on top of PartA
partB.CFrame = partA.CFrame * CFrame.new(0, partB.Size.Y / 2 + partA.Size.Y / 2, 0)
-- Studs and Inlet will make joints
partA.TopSurface = Enum.SurfaceType.Studs
partB.BottomSurface = Enum.SurfaceType.Inlet
-- Automatically create a joint between PartA and PartB
partA:MakeJoints()
MoveTo
Moves the PrimaryPart to the given position. If a primary part has not been specified, the root part of the model will be used, but the root part is not deterministic and it is recommended that you always set a primary part when using MoveTo().
If there are any obstructions where the model is to be moved, such as Terrain or other BaseParts, the model will be moved vertically upward until there is nothing in the way. If this behavior is not desired, PVInstance:PivotTo() should be used instead.
Note that rotation is not preserved when moving a model with MoveTo(). It is recommended to use either TranslateBy() or PVInstance:PivotTo() if the current rotation of the model needs to be preserved.
Parameters
Returns
Code Samples
This sample demonstrates how Model:MoveTo avoids collisions.
A simple two part Model is created, and its PrimaryPart is set. An large obstruction part is placed next to it.
After 5 seconds Model:MoveTo is used to direct the model to move inside the obstruction part. However, as MoveTo will not move a model inside of an obstruction the Model is moved up on the Y axis and placed above the obstruction.
local START_POSITION = Vector3.new(-20, 10, 0)
local END_POSITION = Vector3.new(0, 10, 0)
local model = Instance.new("Model")
model.Parent = workspace
local part1 = Instance.new("Part")
part1.Size = Vector3.new(4, 4, 4)
part1.Position = START_POSITION
part1.Anchored = true
part1.BrickColor = BrickColor.new("Bright yellow")
part1.Parent = model
local part2 = Instance.new("Part")
part2.Size = Vector3.new(2, 2, 2)
part2.Position = START_POSITION + Vector3.new(0, 3, 0)
part2.Anchored = true
part2.BrickColor = BrickColor.new("Bright blue")
part2.Parent = model
model.PrimaryPart = part1
model.Parent = workspace
local obstruction = Instance.new("Part")
obstruction.Name = "Obstruction"
obstruction.Size = Vector3.new(10, 10, 10)
obstruction.Position = Vector3.new(0, 10, 0)
obstruction.Anchored = true
obstruction.BrickColor = BrickColor.new("Bright green")
obstruction.Parent = workspace
task.wait(3)
model:MoveTo(END_POSITION)
ResetOrientationToIdentity
Resets the rotation of the model's parts to the previously set identity rotation, which is done through the Model:SetIdentityOrientation() method.
Returns
ScaleTo
Models contain a persistent canonical scale factor, which starts out at 1 for newly created models. This function scales the model, around the pivot location, relative to how it would look at a scale factor of 1. To accomplish this it does two things:
- Sets the current scale factor of the model to the specified value
- Resizes and repositions all descendant Instances accordingly
The scaling of locations is done around the pivot location.
All "geometric" properties of descendant Instances will be scaled. That obviously includes the sizes of parts, but here are some other examples of properties which are scaled:
- The length of joints like WeldConstraints, and Class.Rope|Ropes
- Physical velocities and forces like Hinge.MaxServoTorque
- Visual properties like sizes of particle emitters
- Other length properties like Sound.RollOffMinDistance
Parameters
Returns
SetIdentityOrientation
Sets the identity rotation of the given model, allowing you to reset the rotation of the entire model later, through the use of the ResetOrientationToIdentity method.
Returns
SetPrimaryPartCFrame
This function has been superseded by PVInstance:PivotTo() which acts as a more performant replacement and does not change your code's behavior. Use PVInstance:PivotTo() for new work and migrate your existing Model:SetPrimaryPartCFrame() calls when convenient.
Sets the BasePart.CFrame of the model's Model.PrimaryPart. All other parts in the model will also be moved and will maintain their orientation and offset respective to the Model.PrimaryPart.
Note, this function will throw an error if no Model.PrimaryPart exists for the model. This can cause issues if, for example, the primary part was never set or has been destroyed.
Parameters
Returns
TranslateBy
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
Returns
Code Samples
This sample demonstrates how Model:TranslateBy ignores collisions and respects the orientation of the model.
A simple two part Model is created, rotated 45 degrees on the Y axis, and its PrimaryPart is set. An large obstruction part is placed next to it.
After 5 seconds Model:TranslateBy is used to direct the model to move inside the obstruction part. The model will move inside of the obstruction and maintain it's current orientation.
local START_POSITION = Vector3.new(-20, 10, 0)
local END_POSITION = Vector3.new(0, 10, 0)
local model = Instance.new("Model")
local part1 = Instance.new("Part")
part1.Size = Vector3.new(4, 4, 4)
part1.CFrame = CFrame.new(START_POSITION) * CFrame.Angles(0, math.rad(45), 0)
part1.Anchored = true
part1.BrickColor = BrickColor.new("Bright yellow")
part1.Parent = model
local part2 = Instance.new("Part")
part2.Size = Vector3.new(2, 2, 2)
part2.CFrame = part1.CFrame * CFrame.new(0, 3, 0)
part2.Anchored = true
part2.BrickColor = BrickColor.new("Bright blue")
part2.Parent = model
model.PrimaryPart = part1
model.Parent = workspace
local obstruction = Instance.new("Part")
obstruction.Name = "Obstruction"
obstruction.Size = Vector3.new(10, 10, 10)
obstruction.Position = Vector3.new(0, 10, 0)
obstruction.Transparency = 0.5
obstruction.Anchored = true
obstruction.BrickColor = BrickColor.new("Bright green")
obstruction.Parent = workspace
task.wait(3)
-- use TranslateBy to shift the model into the obstruction
model:TranslateBy(END_POSITION - START_POSITION)