Skip to content

Instantly share code, notes, and snippets.

@aerialist
Last active March 6, 2022 14:15
Show Gist options
  • Save aerialist/e4a198e39c40ad8b2273281e77fb5252 to your computer and use it in GitHub Desktop.
Save aerialist/e4a198e39c40ad8b2273281e77fb5252 to your computer and use it in GitHub Desktop.
Conver Euler angles to Quaternion, in the same manner as Unity
#!/usr/bin/env python
# coding: utf-8
# This code try to produce same quaternion from euler angles as Unity
# https://docs.unity3d.com/ScriptReference/Quaternion.html
# Oritinal code is from
# https://stackoverflow.com/questions/12088610/conversion-between-euler-quaternion-like-in-unity3d-engine/12122899#12122899
import numpy as np
def euler_2_quaternion_unity(yaw, pitch, roll):
yaw = np.radians(yaw)
pitch = np.radians(pitch)
roll = np.radians(roll)
yawOver2 = yaw * 0.5
cosYawOver2 = np.cos(yawOver2)
sinYawOver2 = np.sin(yawOver2)
pitchOver2 = pitch * 0.5
cosPitchOver2 = np.cos(pitchOver2)
sinPitchOver2 = np.sin(pitchOver2)
rollOver2 = roll * 0.5
cosRollOver2 = np.cos(rollOver2)
sinRollOver2 = np.sin(rollOver2)
w = cosYawOver2 * cosPitchOver2 * cosRollOver2 + sinYawOver2 * sinPitchOver2 * sinRollOver2;
x = cosYawOver2 * sinPitchOver2 * cosRollOver2 + sinYawOver2 * cosPitchOver2 * sinRollOver2;
y = sinYawOver2 * cosPitchOver2 * cosRollOver2 - cosYawOver2 * sinPitchOver2 * sinRollOver2;
z = cosYawOver2 * cosPitchOver2 * sinRollOver2 - sinYawOver2 * sinPitchOver2 * cosRollOver2;
return (x, y, z, w)
def toQ(x, y, z):
return euler_2_quaternion_unity(y, x, z)
def toEuler(x, y, z, w):
sqw = w * w
sqx = x * x
sqy = y * y
sqz = z * z
unit = sqx + sqy + sqz + sqw # if normalised is one, otherwise is correction factor
test = x * w - y * z
if test > 0.4995*unit: # singularity at north pole
v_y = 2. * np.arctan2(y, x);
v_x = np.pi / 2;
v_z = 0;
elif test < -0.4995*unit: # singularity at south pole
v_y = -2. * np.arctan2(y, x);
v_x = -1 * np.pi / 2;
v_z = 0;
else:
v_y = np.arctan2(2. * w * y + 2. * z * x, 1 - 2. * (x * x + y * y));
v_x = np.arcsin(2. * (w * x - y * z));
v_z = np.arctan2(2. * w * z + 2. * x * y, 1 - 2. * (z * z + x * x));
return tuple(np.rad2deg(np.unwrap([v_x, v_y, v_z])))
if __name__ == "__main__":
#Quaternion.Euler(30, 0, 0) --> (0.3, 0.0, 0.0, 1.0)
#Quaternion.toString() spits out in x, y, z, w order with 1 digit
print("Try rotation of x:30, y:0, z:0")
print(toQ(30,0,0))
print(toEuler(*toQ(30,0,0)))
#Quaternion.Euler(100,55,-11) --> (0.6, 0.4, -0.4, 0.5)
print("Try rotation of x:100, y:55, z:-11")
print(toQ(100,55,-11))
print(toEuler(*toQ(100,55,-11)))
print(toQ(80, 235, 169))
print("It's same as rotation of x:80, y:235, z:169")
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment