Is this the best way to scale a model?

Mind blown. Thanks for teaching me a new cframe method :smile:

1 Like

It was on the old wiki :smiley: I discovered it last week and have been trying to think of some useful applications for it that aren’t already handled by the ROBLOX engine, but you’d be the first to give me such an idea.

By the way, it works for all of the ToWorldSpace and ToObjectSpace methods, i.e. those plus the ones for points and vectors.

3 Likes

How do you handle welds in your models? Don’t all the welds break when rescaling the parts?

1 Like

Yeah they would probably break, or otherwise just put things in the wrong position. You would have to scale the C0/C1 properties of the welds.

If you’re auto-welding, I would recommend scaling first before welding

3 Likes

All the parts from my model have scaled, but their positions appear to remain the same. As a result, there are gaps between all my parts (I am scaling down). I do have welds connecting some parts together since it is a moving object. Solutions would be appreciated.

1 Like

I had the same issue, but I figured it out.

local function scaleModel(model, scale)
	local PrimaryPart = model.PrimaryPart
	local PrimaryPartCFrame = model:GetPrimaryPartCFrame()
	
	--Destroy welds
	for _,object in pairs(model:GetDescendants()) do
		if object:IsA('BasePart') then
			for _,object in pairs(object:GetDescendants()) do
				if object:IsA('Weld') or object:IsA('ManualWeld') or object:IsA('WeldConstraint') then
					pcall(function()
						object.Part0.Anchored = true
						object.Part1.Anchored = true
					end)
					object:Destroy()
				end
			end
		end
	end
	
	--Scale BaseParts
	for _,object in pairs(model:GetDescendants()) do
		if object:IsA('BasePart') then	
			object.Size = object.Size*scale
			
			local distance = (object.Position - PrimaryPartCFrame.p)
			local rotation = (object.CFrame - object.Position)
			object.CFrame = (CFrame.new(PrimaryPartCFrame.p + distance*scale) * rotation)
		end
	end
end

https://imgur.com/a/8rf0gKW

26 Likes

Hello guys,

I asked @KoxuVBC in a private message for a solution where the parts of the model are not anchored. He then gave me this advise:

This is my implementation, which works. I want to share it with you. Maybe even someone has a suggestion for improvement.

local function scaleModel(model, scale)
local PrimaryPart = model.PrimaryPart
local PrimaryPartCFrame = model:GetPrimaryPartCFrame()

--Destroy welds
for _,object in pairs(model:GetDescendants()) do
	if object:IsA('Weld') or object:IsA('ManualWeld') or object:IsA('WeldConstraint') then
		object:Destroy()			
	end		
end
for _,object in pairs(model:GetDescendants()) do
	if object:IsA('BasePart') then
		for _,object2 in pairs(model:GetDescendants()) do
			if object2:IsA('BasePart') then
				if object ~= object2 then
					local constraint = Instance.new("WeldConstraint")
					constraint.Part0 = object
					constraint.Part1 = object2
					constraint.Parent = object
				end
			end		
		end			
	end		
end

--Scale BaseParts
for _,object in pairs(model:GetDescendants()) do
	if object:IsA('BasePart') then	
		object.Size = object.Size*scale
		
		local distance = (object.Position - PrimaryPartCFrame.p)
		local rotation = (object.CFrame - object.Position)
		object.CFrame = (CFrame.new(PrimaryPartCFrame.p + distance*scale) * rotation)
	end
end

end

Greetings!

8 Likes

I don’t think that works well with R16: image

However it works great with R6:

1 Like

For some reason, OP’s code doesn’t work for a model I was trying to scale. If you get weird scaling behavior in the future when trying to use the code, this code works for me:

function scaleModel(model, scale)
	local origin = model.PrimaryPart.Position
	
	for _, part in ipairs(model:GetDescendants()) do
		if part:IsA("BasePart") then
			local pos = part.Position
			local rotCf = part.CFrame - pos
			local fromOriginDir = pos - origin
			part.Size *= Vector3.new(scale, scale, scale)
			part.CFrame = rotCf + origin + fromOriginDir*scale
		end
	end
end
25 Likes

I made @rbxts package for scale-model because this could be a little tricky. It needs to scale bunch of different kinds of sub-objects. For example, my package can scale Fire, Attachments, and even a NumberSequence inside of a ParticleEmitter.

You can install it to roblox-ts solution with npm i @rbxts/scale-model
Sourcecode in Typescript could be found on my Github

I made a roblox-ts Playground which will show the sourcecode compiled to Lua, however it’s not very human-friendly.

3 Likes

There is a scale model plugin that I use. Model Resize Plugin 2.1 [ DRAG TO RESIZE! ] - Roblox

Cool, yep, I knew about that, but I need to resize Models at runtime with script.

3 Likes

I’m using model:GetBoundingBox() as the primaryCf. I run the function the first time to scale it down, and then tween it back to its original size using the same function.

And for some reason the model always ends up rotated 180 degrees, is there a way to fix this? I’m not really experienced in Cframes so I would really appreciate it if someone could fix it…

How can I adjust this to work “down-up”?
Like if the scale would be adjusted with the scale tool in studio

Sorry for the bump, but I revised the functions mentioned here to also account for welded models. In this thread there are functions that delete the welds altogether, but that is not practical if those welds are needed. I simply adjust the offset of the joints’ C0 and C1 values based on the scale variable.

Thought this may be useful for others, so here it is:

function scaleModelWithJoints(model, scale)
	local origin = model.PrimaryPart.Position

	for _, obj in ipairs(model:GetDescendants()) do
		if obj:IsA("BasePart") then
			obj.Size = obj.Size*scale

			local distance = (obj.Position - model:GetPrimaryPartCFrame().p)
			local rotation = (obj.CFrame - obj.Position)
			obj.CFrame = (CFrame.new(model:GetPrimaryPartCFrame().p + distance*scale) * rotation)
		elseif obj:IsA("JointInstance") then
			local c0NewPos = obj.C0.p*scale
			local c0RotX, c0RotY, c0RotZ = obj.C0:ToEulerAnglesXYZ()
			
			local c1NewPos = obj.C1.p*scale
			local c1RotX, c1RotY, c1RotZ = obj.C1:ToEulerAnglesXYZ()

			obj.C0 = CFrame.new(c0NewPos)*CFrame.Angles(c0RotX, c0RotY, c0RotZ)
			obj.C1 = CFrame.new(c1NewPos)*CFrame.Angles(c1RotX, c1RotY, c1RotZ)
		end
	end
end

This function also allows the function to be scaled to a larger size which is what some of the functions listed in this thread were unable to do.

14 Likes

You could use multiple threads to speed it up

For some reason I used this code and I have an issue where a union welded onto a model would be in the wrong orientation when using this function

Do you have any plans to add ‘bones’ to the scaling? I am trying to scale a mesh with bones at runtime, and though it scales perfect, with the studio scaling tool, when I try to do it myself in code, I can’t get the bones to scale correctly.

As of March 2023, we now have the Model.Scale property, which can be set within Roblox Studio. We also have the Model:ScaleTo(scale) and Model:GetScale() methods, which can be used during runtime (and in Studio).

A lot of people reference this post, so I wanted to make one final post here about the official way to scale a model.

9 Likes

This topic was automatically closed 14 days after the last reply. New replies are no longer allowed.