How to get a CFrame's angles

Let’s say I have some arbitrary CFrame:

CFrame.new(0,0,0)*CFrame.Angles(math.pi/2, 0, 0)

How would I separate the position component from the angle component. For example I want this,

CFrame.Angles(math.pi/2, 0, 0)

and not this:

CFrame.new(0,0,0)

I’ve been stuck on this one for a while. Thanks!

8 Likes

It sounds like you want the CFrame rotation without position. You can just subtract the position to do this:

local cf = someCFrame - someCFrame.Position

Further explanation:
Using CFrame.Angles simply constructs a rotated CFrame object at the point of origin (0, 0, 0). Thus, to get a CFrame with just its rotation, you need to translate it back to the point of origin. Thankfully, the actual position is available, so we just need to subtract its position to get it back at the point of origin.

71 Likes

As @Crazyman32 said, you likely just want to get the rotation component of the CFrame but if you really need to get the values that you would use in the CFrame.Angles constructor there is an API for that.

local cf = CFrame.Angles(math.pi/2, 0, 0)
local x, y, z = cf:ToEulerAnglesYXZ()
local newCF = CFrame.Angles(x, y, z) 
-- newCF is aprox equal to cf, some loss of precision likely

This page on the devhub has a list of all the CFrame APIs:
https://developer.roblox.com/api-reference/datatype/CFrame

47 Likes

This was what I was looking for, thanks!

2 Likes

I actually am going to use your method because it says it is more accurate.

local Angle = Vector3.new(Camera.CFrame - Camera.CFrame.Position)
Angle = Vector3.new(math.deg(Angle.X), math.deg(Angle.Y), math.deg(Angle.Z))

I have this but it is just giving me 0,0,0 every time I print that angle…

4 Likes

The XYZ properties are always going to be the position coordinates, not rotation. The rotation is derived from the rest of the CFrame matrix.

I’m not very good with that stuff, but there’s a way to use some trig functions to reconstruct the rotational XYZ from the other CFrame components. However, I think that’s exactly what ToEulerAnglesYXZ() is doing.

2 Likes
if (input.UserInputType == Enum.UserInputType.MouseButton1) then
			if (self.CanFire == false or self.FPS.IsSprinting) then return end
			
			self.CanFire = false
			
			self.Recoil.angularFrequency = 20
--			local x, y, z = Camera.CFrame:ToEulerAnglesYXZ()
--			local OriginalCameraAngle = Vector3.new(math.deg(x),math.deg(y),math.deg(z))
--			local sx, sy, sz, m00, m01, m02, m10, m11, m12, m20, m21, m22 = Camera.CFrame:GetComponents()
--			local x = math.atan2(-m12, m22)
--			local y = math.asin(m02)
--			local z = math.atan2(-m01, m00)
--			local OriginalCameraAngle = Vector3.new(y,z,0)
--			local Angle = Vector3.new(Camera.CFrame - Camera.CFrame.Position)
--			Angle = Vector3.new(math.deg(Angle.X), math.deg(Angle.Y), math.deg(Angle.Z))
			
			local x, y, z = Camera.CFrame:ToEulerAnglesYXZ()
			local Angle = Vector3.new(math.deg(x),math.deg(y),math.deg(z))
			
			print(Angle)
			
			if (self.FireType == "Auto") then
				while (UserInputService:IsMouseButtonPressed(Enum.UserInputType.MouseButton1)) do
					self:Fire()
				end
			elseif (self.FireType == "Semi") then
				self:Fire()
			elseif (self.FireType == "Burst") then
				self:Fire()
				wait(.1)
				self:Fire()
				wait(.1)
				self:Fire()
			end
			
			self.Recoil.angularFrequency = 10
			self.Recoil.p = Angle
			
			self.CanFire = true
		end

Hmmm… what I am trying to do is have a gun, when it is done firing, return the camera to it’s original rotation.

This is what is looks like…

The angle gets applied like this:

Camera.CFrame = Camera.CFrame * CFrame.fromEulerAnglesYXZ(self.Recoil.p.y, self.Recoil.p.z, 0)

Am I missing something?

3 Likes

First, make sure when you using math.rad(radius) when using CFrame.Angles(). Math.rad is basically a function that takes the a number and makes it to an angle. Using this, when you do something like

part.CFrame = part.CFrame * CFrame.Angles()

you can change the angle of the part by doing

CFrame.Angles(math.rad(90),0,math.rad(180))

Switching it from CFrame.fromEulerAnglesYXZ() to CFrame.Angles does not make any difference.

That is not what math.rad function does. rad takes an angle given in degrees, and converts it to an angle given in radians. It’s a simple conversion with the following formula:

function rad(x)
    return x * math.pi / 180
end

Likewise, math.deg is its counterpart for converting angles given in radians to angles given in degrees.

3 Likes

Ahh this is a classic example of an X/Y problem.

You are trying to use a mathematical spring for rotational camera recoil. You are asking how to convert the spring to angles, but you should be asking how to interpolate a cframe with the spring code you have.

Speaking of which thats not particularly easy to do so i rcmd trying a different approach. I have a FPS guide somewhere on the devforum with an example placefile. That may help!

8 Likes

I have seen your example place file. It doesn’t have anything for the recoil returning to the original camera position.

It was awhile ago but im pretty sure in the most recent placefile i added at the bottom there’s something in there for recoil.

2 Likes

I’m not having a problem with the recoil. I need the gun to return to the original angle that was before the gun was fire, when the gun is done firing.

1 Like

You could try running a for loop twice (first for recoil, second for recovery) or you could try repeatedly using Lerp() to take the camera where you want to go.

An example of lerp would be


local angle = 0.2

for i = 1,5 do
workspace.Camera.CFrame = workspace.Camera.CFrame:Lerp(workspace.Camera.CFrame * CFrame.Angles(angle,0,0), 0.05)
wait()
end


for i = 1,5 do -- return camera to original position
workspace.Camera.CFrame = workspace.Camera.CFrame:Lerp(workspace.Camera.CFrame * CFrame.Angles(-angle,0,0), 0.05)
wait()
end

or simply

for i = 1,5 do -- return camera to original position
workspace.Camera.CFrame = workspace.Camera.CFrame * CFrame.Angles(angle,0,0)
wait()
end


for i = 1,5 do -- return camera to original position
workspace.Camera.CFrame = workspace.Camera.CFrame * CFrame.Angles(-angle,0,0)
wait()
end

Maybe you could store the original CFrame in a Variable then when the recoil is done use :Lerp function to restore it to normal

1 Like

That wouldn’t always work, the player is constantly moving their camera as well as the recoil.

I know this is a very old post, and I found it actually just looking for a way to mirror a cframe’s roation around a single axis… however, after reading all the posts…

What would probably work is having 2 CFrames for the camera, one is the Actual camera cframe, and one is the Visual camera cframe

Visual is what you will see, actual is where the camera ‘should’ be looking.
Both of these CFrames get upated every time the mouse is moved
However for recoil, only the visible cframe is given a rotation around the x? to move the view upwards
Have the view cframe always trying to lerp its way back to the actual cframe

So that as you look around, even during recoil, you will still end up with the camera returning to where the player is more currently looking.

You could also add a way to ‘unhook’ the trying to sync up the view and actual cframes, so that you could have a sort of ‘look over your shoulders’ effect, for games that might have a more ‘fixed’ actual cframe

3 Likes

been melting my brain for the past 2 or so hours trying to understand how quaternion rotations work just to do what you just said. you are a true life saver g

3 Likes

oh whoops, I thought the post was bumped already… my bad!