By rounding my scale to the nearest 0.1 and caching the results, it has improved performance by +30%. Higher memory usage of course, but nothing crazy.
Server is generating about 13,000 items in 1.4 seconds consistently.
By rounding my scale to the nearest 0.1 and caching the results, it has improved performance by +30%. Higher memory usage of course, but nothing crazy.
Server is generating about 13,000 items in 1.4 seconds consistently.
What’s your code so far? Are you CFraming before or after parenting?
Before. Each foliage prefab has a different ‘transformation’ function that applies the object to a given position (i.e. rocks and trees need to be placed/rotated differently). All transformations are done before parenting. Final parenting of the whole folder is last, and thus allows server to replicate all items to the client however it sees best.
Yes
CFrame operations can be batched, which appears to speed things up around 2x for me. I’ve found that grouping operations into batches of ~1000 offers the greatest speedup on my machine. To multiply a tuple of Vector3s by another CFrame, just do cf:PointToWorldSpace(…).
Also, you can store the scale and the object space transformation as a single CFrame, since CFrames by themselves aren’t required to be orthogonal:
local mPts,mSizes
local cf = primaryCf:inverse()
local ScaleMatrix = CFrame.new(0,0,0,scale,0,0,0,scale,0,0,0,scale)
cf=cf*ScaleMatrix
mPts = {cf:PointToWorldSpace(unpack(mPts))}
mSizes = {ScaleMatrix:VectorToWorldSpace(unpack(mSizes))}
Where mPts and mSizes are defined appropriately.
Edit: On second thought, this might not meet your needs if you’re only transforming 2-3 parts per model. It’s worth a try, though.
I feel like GetChildren would be faster than GetDescendants, although if it is, probably not enough to impact performance.
Maybe only scale half of the models? If variation is what you want, do you really need to scale every single one of them?
Also, you could maybe make a variable for primaryCf:inverse() as well. Means it would be called/calculated 2 to 3 times less often. Optionally use pointToObjectSpace like suremark suggested (not sure which would be faster).
And finally, do you really need to return the model? I mean, if you’re passing it in the function, I imagine you wouldn’t need another reference to it.
Interesting. This isn’t documented anywhere, but it works
Mind blown. Thanks for teaching me a new cframe method
It was on the old wiki 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.
How do you handle welds in your models? Don’t all the welds break when rescaling the parts?
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
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.
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
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!
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
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.
Cool, yep, I knew about that, but I need to resize Models at runtime with script.