How to scale the pivot point of a model

Hey guys! I’m currently making a plugin and i need a bit of help for the math behind scaling a pivot point with a model!

Scaling the model itself:

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

	for _, part in ipairs(model:GetDescendants()) do
		if part:IsA("BasePart") or part:IsA("MeshPart") 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

After yoinking someone’s code which i will later clean up, i’ve got the actually scaling the model sorted. However, the issue is, the pivot point does not follow with the scale of the model, as it does like when you normally scale with studio’s scale tool. This causes clipping:

As you can see from the video, the scale is the issue since when unscaled it works perfectly. This is due to the pivot position remaining in the same position and not scaling with the model, which i need to figure out how to do!

As you can see, studio’s tool does it perfectly. If anyone has the source code / can link it for me to check out then I’d be very grateful! Thank you for all help in advance!

Can probably move the CFrame with your fromOriginDir approach instead of my scaleToPivot fn. May just need to change position to the model:GetPivot().Position value (which uses model pivot by default or PrimaryPart pivot if there is one). If there is a PrimaryPart, then the part’s PivotOffset will need to be scaled too (otherwise the pivot ends up in wrong place after adjusting placement).

-- this finds new position value for part being scaled toward pivot
local function scaleToPivot(pivotPos, partPos, scaleFactor)
	return Vector3.new(
		(pivotPos.X + scaleFactor * (partPos.X - pivotPos.X)),
		(pivotPos.Y + scaleFactor * (partPos.Y - pivotPos.Y)),
		(pivotPos.Z + scaleFactor * (partPos.Z - pivotPos.Z))
	)
end

local function scaleModel(model, scale)
	local pivotPos = model:GetPivot().Position
	
	for _, part in ipairs(model:GetDescendants()) do
		if part:IsA("BasePart") or part:IsA("MeshPart") then
			part.Size *= Vector3.new(scale, scale, scale)
			part.Position = scaleToPivot(pivotPos, part.Position, scale)
		end
	end
	-- if using PrimaryPart, scale the PivotOffset
	if model.PrimaryPart then
		model.PrimaryPart.PivotOffset = CFrame.new(model.PrimaryPart.PivotOffset.Position * scale)
	end
end

The scaleToPivot fn was just a test based on math pulled from Homothety - Wikipedia

2 Likes

Thank you! This worked perfectly, and replaced my less elegant solution of making a fake pivot point, making that the primary part and using that instead!

Also thank you once again for the effort you put into this post, aswell as also accounting for the use of with or without primary parts! A very well deserved solution :smile:

1 Like

:grinning: You’re very welcome!

Something to note: This doesn’t adjust PivotOffset for any parts except for the PrimaryPart. You may consider modifying the code so it scales PivotOffset for any other parts inside a model that may have custom pivot placement, for completeness (prob a generalized version of the final if statement moved inside the for loop).

The plugin is looking good in the video! GL with that moving forward!

1 Like