1
$\begingroup$

So, I've got this problem where I try to rotate the faces of a Rubik's Cube. So far, I have been able to select the right faces for each turn and rotate them properly, well somewhat. On the keyframes, the rotation is completely correct, but in the interpolated frames, it messes up (see first gif). This seems to be the case because the objects are sometimes rotated on all three axes, although one should be sufficient. If the rotation is done manually (see second gif), it does indeed only rotate one axis. Copying the command for the manual rotation from the Info Context Menu (bottom left in the scripting tab) yielded the same result.

Note: You might need to open the gifs in a new tab to see the Properties Tab clearly.

incorrect

correct

In my script, I rotate the cubits with this line of code:

bpy.ops.transform.rotate(value=degrees(deg), orient_axis=axis, orient_type='GLOBAL', constraint_axis=(axis == "X", axis == "Y", axis == "Z"))

Where axis is either 'X', 'Y' or 'Z'.

Weirdly, the problem is only half as bad when using radians directly (both unnecessary axes only rotate by 45°). bpy.ops.transform.rotate(value=1.5708, orient_axis=axis, orient_type='GLOBAL', constraint_axis=(axis == "X", axis == "Y", axis == "Z"))

$\endgroup$
4
  • 1
    $\begingroup$ Looks more like a gimbal lock issue to me. $\endgroup$
    – Lauloque
    Commented Jul 7, 2023 at 22:19
  • $\begingroup$ use ScreentoGif to make clear gifs and provide your blend file. $\endgroup$
    – Karan
    Commented Jul 8, 2023 at 9:20
  • 2
    $\begingroup$ It was indeed a gimbal lock issue and I found a great video to fix it. Thank you very much, @L0Lock! @Karan, ScreentoGif is indeed very helpful and I will make sure to upload my .blend next time I ask something! $\endgroup$
    – Borusse29
    Commented Jul 8, 2023 at 13:34
  • $\begingroup$ Glad to help! Don't hesitate to post an answer to your own post and mark it as the solution. Free points for you, and people with the same issue in the future will be happy to see your answer too. $\endgroup$
    – Lauloque
    Commented Jul 10, 2023 at 4:17

1 Answer 1

0
$\begingroup$

I avoided the gimbal lock by using quaternion rotation. (An explanation of this and other solutions to gimbal locks)

import bpy, math

def insert_keyframe(objects, frame, interpolation_mode):
    for obj in objects:
        obj.keyframe_insert(data_path = "rotation_quaternion", frame = frame)

        #if you want to keep the standard bezier interpolation you can remove this part
        for fcurve in obj.animation_data.action.fcurves:
            fcurve.keyframe_points[len(fcurve.keyframe_points) - 1].interpolation = interpolation_mode

objects = bpy.data.collections["Cube"].objects
axis = "X" # has to be "X", "Y" or "Z"
deg = 90
start_frame = bpy.context.scene.frame_current
end_frame = start_frame + 10

#insert old rotation as keyframe
insert_keyframe(objects, start_frame, 'BEZIER')

#deselect all objects
bpy.ops.object.select_all(action='DESELECT')

for obj in objects:
    #select all objects that need to be rotated
    obj.select_set(True)

    #set rotation mode to quaternion
    obj.rotation_mode = "QUATERNION"

#rotate the selected objects
bpy.ops.transform.rotate(value=math.radians(deg), orient_axis=axis, orient_type='GLOBAL', constraint_axis=(axis == "X", axis == "Y", axis == "Z"))

#deselect all objects
bpy.ops.object.select_all(action='DESELECT')

#insert new rotation as keyframe
insert_keyframe(objects, end_frame, 'BEZIER')

To avoid issues when chaining multiple rotations, insert a duplicate keyframe before the start and after the end of each keyframe with constant interpolation between them, like so:

insert_keyframe(objects, start_frame - 1, 'CONSTANT')

...

insert_keyframe(objects, start_frame + 1, 'CONSTANT')
$\endgroup$

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .