How to get a CFrame's angles


#1

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!


#2

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.


#3

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


#4

This was what I was looking for, thanks!


#5

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…


#6

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.


#7
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?


#8

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))

#9

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


#10

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.


#11

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!


#12

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


#13

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.


#14

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.


#15

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