I am trying to find the angle of the head with regards to the y axis in a ARFaceAnchor
. My starting example is Apple's sample code: creating face-based AR experiences.
Given this image, I am basically searching for the angle of the green marker (from the coordinateOrigin
node) relative to the vertical axis.
The ARFaceAnchor
object inherits from ARAnchor
, providing a
transform` property:
A matrix encoding the position, orientation, and scale of the anchor relative to the world coordinate space of the AR session the anchor is placed in.
The type of such transform
is as follows:
var transform: matrix_float4x4 { get }
How do I derive angle information such as the one described from this matrix?
As Apple does not provide a quaternion to euler conversion for this class, in my case I had to compute them by hand as shown below.
Please find the reference here, which is inspired by this mathematical resource.
extension matrix_float4x4 {
// Function to convert rad to deg
func radiansToDegress(radians: Float32) -> Float32 {
return radians * 180 / (Float32.pi)
}
var translation: SCNVector3 {
get {
return SCNVector3Make(columns.3.x, columns.3.y, columns.3.z)
}
}
// Retrieve euler angles from a quaternion matrix
var eulerAngles: SCNVector3 {
get {
// Get quaternions
// http://www.euclideanspace.com/maths/geometry/rotations/conversions/matrixToQuaternion/index.htm
let qw = sqrt(1 + self.columns.0.x + self.columns.1.y + self.columns.2.z) / 2.0
let qx = (self.columns.2.y - self.columns.1.z) / (qw * 4.0)
let qy = (self.columns.0.z - self.columns.2.x) / (qw * 4.0)
let qz = (self.columns.1.x - self.columns.0.y) / (qw * 4.0)
// Deduce euler angles with some cosines
// https://en.wikipedia.org/wiki/Conversion_between_quaternions_and_Euler_angles
/// yaw (z-axis rotation)
let siny = +2.0 * (qw * qz + qx * qy)
let cosy = +1.0 - 2.0 * (qy * qy + qz * qz)
let yaw = radiansToDegress(radians:atan2(siny, cosy))
// pitch (y-axis rotation)
let sinp = +2.0 * (qw * qy - qz * qx)
var pitch: Float
if abs(sinp) >= 1 {
pitch = radiansToDegress(radians:copysign(Float.pi / 2, sinp))
} else {
pitch = radiansToDegress(radians:asin(sinp))
}
/// roll (x-axis rotation)
let sinr = +2.0 * (qw * qx + qy * qz)
let cosr = +1.0 - 2.0 * (qx * qx + qy * qy)
let roll = radiansToDegress(radians:atan2(sinr, cosr))
/// return array containing ypr values
return SCNVector3(yaw, pitch, roll)
}
}
}
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With