Parts inside of a model gradually move out of place while cframing the primarypart

Hello, so this is a weird issue I’ve come across and I was wondering if anyone knows how to avoid running into this problem. So, I have a renderstep that constantly rotates the primarypartcframe of a model. and i’ve noticed, gradually overtime the parts end up going out of place:


It should be like this:

This is my code:

game:GetService("RunService").RenderStepped:Connect(function(deltaTime)
    local Angles =  CFrame.Angles(0, 0.0025 * deltaTime * 60, 0)
    local Billboard = workspace.Billboard

    Billboard:SetPrimaryPartCFrame(Billboard.PrimaryPart.CFrame * Angles)
end)

I only noticed this when I AFK’ed in-game for around 15 minutes and came back to find this weird occurrence

1 Like

I experienced the same problem. But when I’ve used CFrame.fromEulerAnglesXYZ instead of CFrame.Angles, the parts either didn’t move out of place at all or only a slightly bit. Other than that, I still don’t know a perfect solution to that.

This is what I had been using originally, then I used CFrame.Angles with the same exact results.

The only thing I could think of is using Welds. If that doesn’t work out, then I’ve got nothing else to say.

edit: Actually, this is probably wrong. I think you’re running into a limitation of SetPrimaryPartCFrame. I agree with @uhHappier, either use welds or do the relative offsets yourself.

You’re experiencing floating point precision errors, probably. Don’t set the next frame’s CFrame based on the last frame’s. Try something like this:

local angle = 0
local billboard = workspace.Billboard
local base = billboard.PrimaryPart.CFrame
local rotPerSecond = 0.02

game:GetService("RunService").RenderStepped:Connect(function(dt)
    angle = angle + 2 * math.pi * rotPerSecond * dt
    billboard:SetPrimaryPartCFrame(base * CFrame.Angles(0, angle, 0));
end)
1 Like

Here’s a better method that welds the parts together at the start of the game, then just manipulates the primary part’s CFrame directly (not tested).

local billboard = workspace.Billboard
local primaryPart = billboard.PrimaryPart
local rotPerSecond = 0.02

-- welds all the parts in `model` to `primaryPart` without moving them.
local function WeldTogether(model, primaryPart)
    local inv = primaryPart.CFrame:Inverse()
    local children = model:GetDescendants()
    
    for i = 1, #children do
        local child = children[i]
        if (child ~= primaryPart and child:IsA("BasePart")) then
            
            local weld = Instance.new("Weld")
            weld.Part0 = primaryPart
            weld.Part1 = child
            weld.C1 = child.CFrame * inv
            weld.Name = "Weld_" .. primaryPart.Name .. "_" .. child.Name
            weld.Parent = primaryPart
            
        end
    end
end

local angle = 0

-- automatically weld the model together when the game starts. You could do this
-- manually, too (or even call WeldTogether from the command line while building)
WeldTogether(billboard, primaryPart)

local initCFrame = primaryPart.CFrame

game:GetService("RunService").RenderStepped:Connect(function(dt)
    angle = angle + 2 * math.pi * rotPerSecond * dt
    billboard.PrimaryPart.CFrame = initCFrame * CFrame.Angles(0, angle, 0)   
end)
2 Likes