How do I rotate a model like CTRL+R does in Studio?

I’m trying to rotate an already rotated part 90 degrees via a script, however I’m not exactly sure how to go about this. I’ve tried rotating is about every axis, but I can’t get it look correct. It either ends up on its side or doing something else crazy.

This is what I’m trying to get it to do, I have the one rotated part and I want you to be able to have it in either of these 4 directions:

According to the Orientation of the parts all I have to do is rotate it about the Y axis, however when I do that via editing the CFrame using CFrame.Angles() it gets turned over on its side. I think it has something to do with global/local space CFrames, but I’m not exactly sure how those work. Any help would be appreciated, thanks!

2 Likes

Try using the different axes.

This is happening because the * CFrame operation applies in the left CFrame’s space. * CFrame.Angles(0, math.rad(90), 0) will rotate on the local or object Y axis, not the global Y axis.

It sounds like you are currently doing, even if you don’t realize it:

  1. Get current position
    1.1 Rotate it by the current rotation (implied/automatic)
  2. Rotate on Y axis

What you need to be doing is:

  1. Get current position
  2. Rotate on Y axis
  3. Rotate by original rotation

This looks like:

local function applyOnGlobalAxis(cframe, applyCFrame)
	local positionCFrame = CFrame.new(cframe.p)  -- make a new CFrame at the same position as cframe
	local rotationCFrame = cframe - cframe.p  -- subtract the positional elements and we end up with just rotation
	return positionCFrame*applyCFrame*rotationCFrame
end

-- to rotate Part on the global axis:
Part.CFrame = applyOnGlobalAxis(part.CFrame, CFrame.Angles(0, math.rad(90), 0))

If you want to rotate the part about a point or something similar, you can use the following:

local function applyAboutCFrame(baseCFrame, cframe, applyCFrame)
	local relativeCFrame = baseCFrame:toObjectSpace(cframe)  -- convert cframe to be relative to baseCFrame
	-- baseCFrame*relativeCFrame == cframe
	-- relativeCFrame is essentially a transformation we can apply to baseCFrame to get cframe
	-- we can rotate or transform baseCFrame then apply that same transformation and now cframe has been moved or rotated about a point
	return baseCFrame*applyCFrame*relativeCFrame
end

-- to rotate Part1 around Part2:
Part1.CFrame = applyAboutCFrame(Part2.CFrame, Part1.CFrame, CFrame.Angles(0, math.rad(90), 0))

You can even re-implement applyOnGlobalAxis using this…

local function applyOnGlobalAxis(cframe, applyCFrame)
	return applyAboutCFrame(CFrame.new(cframe.p), cframe, applyCFrame)
end

…because applyOnGlobalAxis is essentially rotating a part around an axis-aligned CFrame at its own position. CFrame.new(cframe.p) gets us cframe aligned to the global axis (i.e. it doesn’t have any rotation).

8 Likes

Ohey. Use Ctrl-L to toggle local rotation, and then use the rotation sphere (tip: set you rotation increment to 90 degrees)