"""Opens and closes the pressure door from one slider: PressureDoor_Root["open"] (0 shut, 1 open). 0.00 - 0.20 the hand wheel turns 90 deg (anticlockwise seen from the front) 0.12 - 0.32 the six bolts slide 0.28 m back into the leaf, out of the frame's keepers 0.35 - 1.00 leaf and arm swing 100 deg about the hinge pin (eased in and out) Drivers are simple expressions (this Blender has Python auto-run off; simple expressions run without Python). Timeline: shut at frame 1, open at 100, shut again at 260 (30 fps). Action: "PressureDoor | OPEN_CLOSE". Each moving part keeps its shut transform in ["closed_location"] / ["closed_rotation"] (the project's convention). """ import bpy, math ROOT = "PressureDoor_Root" W0, W1 = 0.00, 0.20 B0, B1 = 0.12, 0.32 S0, S1 = 0.35, 1.00 def ramp(a, b): return "min(max((open-%.4f)/%.4f,0),1)" % (a, b - a) def eased(a, b): r = ramp(a, b) return "%s*%s*(3-2*%s)" % (r, r, r) def drive(ob, path, index, expr, root): ob.driver_remove(path, index) fc = ob.driver_add(path, index) d = fc.driver d.type = 'SCRIPTED' v = d.variables.new() v.name = "open" v.type = 'SINGLE_PROP' v.targets[0].id_type = 'OBJECT' v.targets[0].id = root v.targets[0].data_path = '["open"]' d.expression = expr return d def rig(): root = bpy.data.objects[ROOT] root["open"] = 0.0 ui = root.id_properties_ui("open") ui.update(min=0.0, max=1.0, soft_min=0.0, soft_max=1.0, default=0.0, description="0 shut, 1 open") leaf = bpy.data.objects["SM_PressureDoor_Leaf"] wheel = bpy.data.objects["SM_PressureDoor_Wheel"] report = [] for ob in (leaf, wheel): ob["closed_location"] = list(ob.location) ob["closed_rotation"] = list(ob.rotation_euler) d = drive(leaf, "rotation_euler", 2, "%s*%.6f" % (eased(S0, S1), math.radians(100.0)), root) report.append((leaf.name, d.is_simple_expression, d.is_valid)) d = drive(wheel, "rotation_euler", 1, "%s*%.6f" % (eased(W0, W1), -math.radians(90.0)), root) report.append((wheel.name, d.is_simple_expression, d.is_valid)) for ob in sorted((o for o in bpy.data.objects if o.name.startswith("SM_PressureDoor_Bolt_")), key=lambda o: o.name): phi = math.radians(ob["phi_deg"]) cx, cy, cz = ob["closed_location"] ob.location = (cx, cy, cz) s = eased(B0, B1) d1 = drive(ob, "location", 0, "%.6f-%.6f*%s" % (cx, 0.28 * math.cos(phi), s), root) d2 = drive(ob, "location", 2, "%.6f-%.6f*%s" % (cz, 0.28 * math.sin(phi), s), root) report.append((ob.name, d1.is_simple_expression and d2.is_simple_expression, d1.is_valid and d2.is_valid)) # timeline sc = bpy.context.scene sc.render.fps = 30 sc.frame_start, sc.frame_end = 1, 260 root.animation_data_clear() for f, v in ((1, 0.0), (100, 1.0), (160, 1.0), (260, 0.0)): root["open"] = v root.keyframe_insert('["open"]', frame=f) act = root.animation_data.action act.name = "PressureDoor | OPEN_CLOSE" try: from bpy_extras.anim_utils import action_get_channelbag_for_slot for fc in action_get_channelbag_for_slot(act, root.animation_data.action_slot).fcurves: for kp in fc.keyframe_points: kp.interpolation = 'LINEAR' except Exception as ex: report.append(("interpolation", str(ex), False)) root["open"] = 0.0 sc.frame_set(1) return report def set_open(v): root = bpy.data.objects[ROOT] root["open"] = float(v) root.update_tag() for o in bpy.data.objects: if o.name.startswith("SM_PressureDoor_") and o.animation_data: o.update_tag() bpy.context.view_layer.update()