Un petit script bien pratique réalisé par Andreas Esau qui aide à mettre en place très facilement une animation de type morphing. Dans la vidéo suivante, il montre comment faire sourire un personnage.
Le script est le suivant: il suffit de faire un copier-coller dans un fichier texte (extension .py), de le placer dans votre répertoire scripts\addons et de l’activer sous Blender (Ctrl+Alt+U –> Volet « Add-Ons »)
bl_info = { "name": "Driver to Bone Constraint", "author": "Andreas Esau", "version": (1, 0), "blender": (2, 7, 4), "location": "Operator Search -> Driver Constraint", "description": "This Operator lets you create a shape driver constraint to a bone with one single dialog operator. Quick and easy.", "warning": "", "wiki_url": "", "tracker_url": "", "category": "Rigging"} import bpy from math import radians,degrees class CreateDriverConstraint(bpy.types.Operator): """Tooltip""" bl_idname = "object.create_driver_constraint" bl_label = "Driver Constraint" def shapes(self,context): shapes = [] i=0 object = bpy.context.selected_objects[1] shape_keys = object.data.shape_keys.key_blocks for shape in shape_keys: if shape.relative_key != shape: shapes.append((shape.name,shape.name,shape.name,'SHAPEKEY_DATA',i)) i+=1 return shapes shape_name = bpy.props.EnumProperty(items = shapes, name = "Shape") type_values = [] type_values.append(("LOC_X","X Location","X Location","None",0)) type_values.append(("LOC_Y","Y Location","Y Location","None",1)) type_values.append(("LOC_Z","Z Location","Z Location","None",2)) type_values.append(("ROT_X","X Rotation","X Rotation","None",3)) type_values.append(("ROT_Y","Y Rotation","Y Rotation","None",4)) type_values.append(("ROT_Z","Z Rotation","Z Rotation","None",5)) type_values.append(("SCALE_X","X Scale","X Scale","None",6)) type_values.append(("SCALE_Y","Y Scale","Y Scale","None",7)) type_values.append(("SCALE_Z","Z Scale","Z Scale","None",8)) type = bpy.props.EnumProperty(name = "Type",items=type_values) space_values = [] space_values.append(("WORLD_SPACE","World Space","World Space","None",0)) space_values.append(("TRANSFORM_SPACE","Transform Space","Transform Space","None",1)) space_values.append(("LOCAL_SPACE","Local Space","Local Space","None",2)) space = bpy.props.EnumProperty(name = "Space",items=space_values) min_value = bpy.props.FloatProperty(name = "Min Value",default=0.0) max_value = bpy.props.FloatProperty(name = "Max Value",default=1.0) @classmethod def poll(cls, context): return context.active_object is not None def execute(self, context): object = bpy.context.selected_objects[1] shape = object.data.shape_keys.key_blocks[self.shape_name] curve = shape.driver_add("value") if len(curve.driver.variables) < 1: curve_var = curve.driver.variables.new() else: curve_var = curve.driver.variables[0] if len(curve.modifiers) > 0: curve.modifiers.remove(curve.modifiers[0]) curve.driver.type = "SUM" curve_var.type = "TRANSFORMS" curve_var.targets[0].id = bpy.context.active_object curve_var.targets[0].bone_target = bpy.context.active_pose_bone.name curve_var.targets[0].transform_space = self.space curve_var.targets[0].transform_type = self.type if self.type in ["ROT_X","ROT_Y","ROT_Z"]: min_value = radians(self.min_value) max_value = radians(self.max_value) else: min_value = self.min_value max_value = self.max_value delete_len = 0 for point in curve.keyframe_points: delete_len += 1 for i in range(delete_len): curve.keyframe_points.remove(curve.keyframe_points[0]) point_a = curve.keyframe_points.insert(min_value,0) point_a.interpolation = "LINEAR" point_b = curve.keyframe_points.insert(max_value,1) point_b.interpolation = "LINEAR" msg = "Shape: "+ self.shape_name +" constraint to Bone: " + context.active_pose_bone.name self.report({'INFO'},msg) return {'FINISHED'} def invoke(self, context, event): wm = context.window_manager if len(context.selected_objects) != 2: self.report({'WARNING'},'Select a Mesh Object and then a Pose Bone') return{'FINISHED'} if context.selected_objects[0].type != "ARMATURE": self.report({'WARNING'},'Select a Mesh Object and then a Pose Bone') return{'FINISHED'} if context.selected_objects[1].type != "MESH": self.report({'WARNING'},'Select a Mesh Object and then a Pose Bone') return{'FINISHED'} if context.active_pose_bone == None: self.report({'WARNING'},'Select a Mesh Object and then a Pose Bone') return{'FINISHED'} if wm.driver_constraint_run_first_time: wm.driver_constraint_run_first_time = False self.type = "LOC_Y" self.space = "LOCAL_SPACE" return wm.invoke_props_dialog(self) def register(): bpy.utils.register_class(CreateDriverConstraint) bpy.types.WindowManager.driver_constraint_run_first_time = bpy.props.BoolProperty(default=True) def unregister(): bpy.utils.unregister_class(CreateDriverConstraint) if __name__ == "__main__": register()
Juste impressionnant ce qu’ils arrivent a faire !