Euler to Quaternion and back, but with respect to rotation_mode

How do I respect rotation_mode property on Object when turning rotation_euler into a Quaternion and back?

I have tried understanding the maths. I do not understand the maths.

Quaternion.to_euler() can take a rotation mode:

rot.to_euler(obj.rotation_mode)

But the other way round, there is no such thing:

obj.rotation_euler.to_quaternion()

Depending on what the rotation_mode is, I’ll get wildly different broken behavior. Should I just leave this broken? Does anyone actually use the non-XYZ euler rotation modes?

I have tried grepping the Python sources, but the amount of results is too overwhelming.

You can rotate a matrix pretty easy, what are you trying to do?

I’m trying to get the correct rotation of an object as quaternion even when the user has rotation_mode XZY, YXZ, YZX, ZXY or ZYX selected, modify it, then apply this rotation to the object again. I.e., fix whatever the bug is in the last line of each of these two functions:

def getObjectRotationQuaternion(obj: bpy.types.Object) -> Quaternion:
    if obj.rotation_mode == "QUATERNION":
        return Quaternion(obj.rotation_quaternion)
    elif obj.rotation_mode == "AXIS_ANGLE":
        return Quaternion(Vector((obj.rotation_axis_angle[1], obj.rotation_axis_angle[2], obj.rotation_axis_angle[3])), obj.rotation_axis_angle[0])
    return obj.rotation_euler.to_quaternion()

def setObjectRotationQuaternion(obj: bpy.types.Object, rot: Quaternion):
    if obj.rotation_mode == "QUATERNION":
        obj.rotation_quaternion = rot
    elif obj.rotation_mode == "AXIS_ANGLE":
        axis, angle = rot.to_axis_angle()
        obj.rotation_axis_angle = [angle, axis[0], axis[1], axis[2]]
    else:
        obj.rotation_euler = rot.to_euler(obj.rotation_mode)

why not simply rotate it’s matrix and set that?

I may be naïve, but what good is the other vector modes?

It isn’t clear to me why working with Matrix would be more simple than working with Quaternion. At least, accessing and writing obj.matrix_local seems to give the correct behavior for once. There is matrix.decompose() to get the components, but reassembling them requires some knowledge. This seems to work:

axis, angle = rot.to_axis_angle()
mat = mathutils.Matrix.Translation(pos) @ mathutils.Matrix.Rotation(angle, 4, axis) @ mathutils.Matrix.Diagonal(Vector((scale[0], scale[1], scale[2], 1)))
1 Like