I have a script that generates a random rubik’s cube, solves it (using a library) and makes an animation of said solution. But I have issues with the animation stage.
The cube is represented as a collection of smaller cubes.
The animation finishes with correct result but the rotations are not animated properly.
*_objects() functions are responsible for selecting cubes corresponding to faces.
#set origin to cursor
for obj in collection.objects:
obj.select_set(True)
obj.rotation_mode = "QUATERNION"
bpy.ops.object.origin_set(type='ORIGIN_CURSOR')
#animate
def rotation_animate(select_axis,angle):
#bpy.data.scenes['Scene'].frame_set(frame)
for ob in bpy.context.selected_objects:
#center = get_cube_center(ob)
#if isclose(center[select_axis], position, abs_tol=0.1):
q_axis = [0.0, 0.0, 0.0]
q_axis[select_axis] = 1.0
q_delta = Quaternion(q_axis, angle)
q = q_delta @ ob.rotation_quaternion
ob.rotation_quaternion = q
def rotate_animation(collection, rotation):
#'F', 'R', 'U', 'B', 'L', 'D', "F'", "R'", "B'", "L'", "D'"
axis = "X"
angle = 90
bpy.ops.object.select_all(action='DESELECT')
if rotation == "F":
front_objects = get_front(collection)
select_all(front_objects)
axis ="y"
angle = -90
#return front_objects
elif rotation == "R":
right_objects = get_right(collection)
select_all(right_objects)
axis = "x"
angle = 90
#return right_objects
elif rotation == "U":
top_objects = get_top(collection)
select_all(top_objects)
axis = "z"
angle = 90
#return top_objects
elif rotation == "B":
back_objects = get_back(collection)
select_all(back_objects)
axis = "y"
angle = 90
#return back_objects
elif rotation == "L":
left_objects = get_left(collection)
select_all(left_objects)
axis = "x"
angle = -90
#return left_objects
elif rotation == "D":
bottom_objects = get_bottom(collection)
select_all(bottom_objects)
axis = "z"
angle = -90
#return bottom_objects
elif rotation == "F'":
front_objects = get_front(collection)
select_all(front_objects)
axis = "y"
angle = 90
#return front_objects
elif rotation == "R'":
right_objects = get_right(collection)
select_all(right_objects)
axis = "x"
angle = -90
#return right_objects
elif rotation == "B'":
back_objects = get_back(collection)
select_all(back_objects)
axis = "y"
angle = -90
#return back_objects
elif rotation == "L'":
left_objects = get_left(collection)
select_all(left_objects)
axis = "x"
angle = 90
#return left_objects
elif rotation == "D'":
bottom_objects = get_bottom(collection)
select_all(bottom_objects)
axis = "z"
angle = 90
#return bottom_objects
elif rotation == "U'":
top_objects = get_top(collection)
select_all(top_objects)
axis = "z"
angle = -90
#return top_objects
axis_dict = {"y":1, "x":0, "z":2}
axis = axis_dict[axis]
rotation_animate(axis, angle)
selected_objects = [obj for obj in bpy.context.selected_objects]
return selected_objects
#bpy.ops.object.transform_apply(rotation=True, scale=False, location=False)
frame_start = 1
frame_duration = 10 # Number of frames for each move
current_frame = 1
idx = 0
for move in solution_moves:
selected = []
if "2" in move:
for i in range(0, 2):
idx += 1
current_frame = frame_start + idx * frame_duration
short_move = move.replace("2", "")
selected = rotate(collection, short_move)
for obj in selected:
obj.keyframe_insert(data_path="rotation_quaternion", frame=current_frame)
#obj.keyframe_insert(data_path="location", frame=current_frame)
else:
idx += 1
current_frame = frame_start + idx * frame_duration
selected = rotate(collection, move)
for obj in selected:
obj.keyframe_insert(data_path="rotation_quaternion", frame=current_frame)
#obj.keyframe_insert(data_path="location", frame=current_frame)
bpy.context.scene.frame_end = current_frame + 30