Issue with apply lots of changes to a CFrame

So the issues is I’m trying generate gable roofs like this:

And that works fine, assuming all the nodes for the roof being generated are in a particular order and aligned to the axis. However I need to be able to handle rotated buildings, I can calculate the angle the parts need to be at just fine, but I’m struggling actually adjusting the part into the rotation because of the relative nature of CFrame rotations.

Whenever I add it in, what seems to happen is it is rotated relative to its current position, but I want to rotate it on a global axis.

Here is my current code:

roofPart.CFrame = CFrame.new((m0+roofPeak)/2)  --position it
        * CFrame.Angles(theta, 0, 0) -- add the incline
        * CFrame.new(Vector3.new(0, 0, -OVER_HANG/2))--add the overhang

To get it to work right, I just want to add in somewhere * CFrame.Angles(0, phi, 0).

My only stipulation is crucial that the overhang is removed after the incline is set, as in effect what is happening is the part is sliding down a stud in that direction.

The full function for those wanting to poke about:

function GableRoof:Generate(nodes)
    local p0, p1, p2, p3 = nodes[1].Vector3, nodes[2].Vector3, nodes[3].Vector3, nodes[4].Vector3
    local m0, m1 = (p1+p0)/2, (p3+p2)/2

    local roofCenter = ((m0+m1)/2)-- + Vector3.new(0, 3, 0)

    local vec = roofCenter - m0
    local theta = -math.atan2(ROOF_HEIGHT, vec.magnitude)-- the incline of the roof
    local phi = math.atan2(vec.z, vec.x) -- the direction the roof thingys are pointed


    local roofPart = Instance.new("Part")

    local roofPeak = roofCenter + Vector3.new(0, ROOF_HEIGHT, 0)
    roofPart.Size = Vector3.new((p1-p0).magnitude+OVER_HANG, .5, (m0-roofPeak).magnitude + OVER_HANG)
    roofPart.Anchored = true
    roofPart.Material = Enum.Material.SmoothPlastic
    roofPart.CFrame = CFrame.new((m0+roofPeak)/2)  --position it
        * CFrame.Angles(theta, 0, 0) -- add the incline
        * CFrame.new(Vector3.new(0, 0, -OVER_HANG/2))--add the overhang
         
    
    local otherPart = roofPart:Clone()
    otherPart.CFrame = CFrame.new((m1+roofPeak)/2)  --position it
         --   * CFrame.Angles(0,-phi, 0) --rotate it to face the center
        * CFrame.Angles(-theta, 0, 0)  --add incline
        * CFrame.new(Vector3.new(0, 0, OVER_HANG/2)) --remove the overhang
    roofPart.Parent = workspace
    otherPart.Parent = workspace

    local p1p2Middle = (p1+p2)/2

    local triangle0 = Triangle:Clone()
    triangle0.Size = Vector3.new(0.2, ROOF_HEIGHT, (p1-p2).magnitude/2)
    triangle0.CFrame = CFrame.new(((p1p2Middle+p1)/2) + Vector3.new(0, ROOF_HEIGHT/2, 0)) 

    local triangle1 = triangle0:Clone()
    triangle1.CFrame = CFrame.new(((p1p2Middle+p2)/2) + Vector3.new(0, ROOF_HEIGHT/2, 0)) * CFrame.Angles(0, math.pi, 0)

    local triangle2 = triangle0:Clone()
    triangle2.CFrame = triangle2.CFrame * CFrame.new(Vector3.new(-(p1-p0).magnitude, 0, 0))

    local triangle3 = triangle1:Clone()
    triangle3.CFrame = triangle3.CFrame * CFrame.new(Vector3.new((p1-p0).magnitude, 0, 0))

    triangle1.Parent = workspace
    triangle0.Parent = workspace
    triangle2.Parent = workspace
    triangle3.Parent = workspace

    local centerPart = Instance.new("Part")
    local vec = p1-p0
    centerPart.Size = Vector3.new(1, 1, (p1-p0).magnitude + OVER_HANG)
    centerPart.CFrame = CFrame.new(roofPeak) * CFrame.Angles(0, math.atan2(vec.z, vec.x) + math.pi*.5, 0)
    centerPart.Anchored = true
    centerPart.Material = Enum.Material.SmoothPlastic

    centerPart.Parent = workspace
end
2 Likes

You should put the CFrame.Angles after your cframe that moves it to the main center position and before you offset from the center position.

So basically:

CenterCFrame*Angle*OffsetFromCenterCFrame*etc...

3 Likes

Thats correct! The reason I was confused was because my math to calculate phi needed to be adjusted -90 degrees, your certainty about the solution helped out a tonne!

4 Likes