"""The feeder's one motion, exec'd by nf_build.py after the meshes exist (needs bpy, NOZZLE_TRAVEL, NEEDLE_TRAVEL). NutritionFeeder_Root["inject"]: 0 = needle away (nozzle up inside the collar, needle inside the nozzle), 1 = as in the picture (nozzle out, needle down to the palm). The nozzle runs 0 .. 0.55, the needle 0.55 .. 1, each eased. The meshes are built in the picture's pose; each moving part keeps ["closed_location"] (inject 0). Drivers are simple expressions (the user's Blender runs with Python auto-run off). Timeline, 30 fps: away at frame 1, out at 60, held to 120, away again at 180. """ root = bpy.data.objects["NutritionFeeder_Root"] nozzle = bpy.data.objects["SM_NutritionFeeder_Nozzle"] needle = bpy.data.objects["SM_NutritionFeeder_Needle"] root["inject"] = 0.0 ui = root.id_properties_ui("inject") ui.update(min=0.0, max=1.0, soft_min=0.0, soft_max=1.0, description="0 needle away, 1 needle out (as in the picture)") RIG = {} for ob, travel, a, b in ((nozzle, NOZZLE_TRAVEL, 0.0, 0.55), (needle, NEEDLE_TRAVEL, 0.55, 1.0)): z_out = ob.location.z z_closed = z_out + travel ob["closed_location"] = (ob.location.x, ob.location.y, z_closed) ob["open_location"] = (ob.location.x, ob.location.y, z_out) ob.location.z = z_closed ob.driver_remove("location", 2) fc = ob.driver_add("location", 2) 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 = '["inject"]' d.expression = "%.6f - %.6f*smoothstep(%.2f, %.2f, v)" % (z_closed, travel, a, b) if not d.is_simple_expression: t = "min(max((v-%.2f)/%.2f,0.0),1.0)" % (a, b - a) d.expression = "%.6f - %.6f*%s*%s*(3-2*%s)" % (z_closed, travel, t, t, t) for m in list(fc.modifiers): fc.modifiers.remove(m) RIG[ob.name] = dict(expression=d.expression, simple=d.is_simple_expression, closed_z=z_closed, open_z=z_out) 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["inject"] = val root.keyframe_insert('["inject"]', frame=fr) if root.animation_data and root.animation_data.action: root.animation_data.action.name = "NutritionFeeder | INJECT" sc.frame_set(1) root["rig"] = str(RIG)