"""The station's one motion, exec'd by cs_build.py after the meshes exist (needs bpy, CA, EJECT). CanisterStation_Root["eject"]: 0 = the canister seated in its drum (as in the picture), 1 = slid EJECT metres up its own axis, out of the drum, still lying in the rail's clamps and on the column's cradle. Eased (smoothstep). Drivers are simple expressions (the user's Blender runs with Python auto-run off). Timeline, 30 fps: seated at frame 1, out at 60, held to 120, seated again at 180. """ root = bpy.data.objects["CanisterStation_Root"] can = bpy.data.objects["SM_CanisterStation_Canister"] root["eject"] = 0.0 ui = root.id_properties_ui("eject") ui.update(min=0.0, max=1.0, soft_min=0.0, soft_max=1.0, description="0 canister seated, 1 slid out of its drum") seated = can.location.copy() can["closed_location"] = tuple(seated) can["open_location"] = tuple(seated + CA * EJECT) RIG = {} for i in (0, 1, 2): can.driver_remove("location", i) if abs(CA[i]) < 1e-9: continue fc = can.driver_add("location", i) d = fc.driver d.type = 'SCRIPTED' var = d.variables.new() var.name = "v" var.type = 'SINGLE_PROP' var.targets[0].id_type = 'OBJECT' var.targets[0].id = root var.targets[0].data_path = '["eject"]' d.expression = "%.6f + %.6f*smoothstep(0.0, 1.0, v)" % (seated[i], CA[i] * EJECT) if not d.is_simple_expression: d.expression = "%.6f + %.6f*min(max(v,0.0),1.0)*min(max(v,0.0),1.0)*(3-2*min(max(v,0.0),1.0))" % (seated[i], CA[i] * EJECT) for m in list(fc.modifiers): fc.modifiers.remove(m) RIG["loc%d" % i] = dict(expression=d.expression, simple=d.is_simple_expression) sc = bpy.context.scene sc.render.fps = 30 sc.frame_start, sc.frame_end = 1, 180 for fr, val in ((1, 0.0), (60, 1.0), (120, 1.0), (180, 0.0)): root["eject"] = val root.keyframe_insert('["eject"]', frame=fr) if root.animation_data and root.animation_data.action: root.animation_data.action.name = "CanisterStation | EJECT" root["eject"] = 0.0 sc.frame_set(1) root["rig"] = str(RIG)