| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152 | from mantis.node_container_common import *from mantis.xForm_containers import xFormGeometryObjectfrom bpy.types import Nodefrom .base_definitions import MantisNodedef TellClasses():                 return [              DeformerArmature,           ]def default_evaluate_input(nc, input_name):    # duped from link_containers... should be common?    # should catch 'Target', 'Pole Target' and ArmatureConstraint targets, too    if ('Target' in input_name) and input_name != "Target Space":        socket = nc.inputs.get(input_name)        if socket.is_linked:            return socket.links[0].from_node        return None            else:        return evaluate_input(nc, input_name)# semi-duplicated from link_containersdef GetxForm(nc):    trace = trace_single_line_up(nc, "Deformer")    for node in trace[0]:        if (node.__class__ in [xFormGeometryObject]):            return node    raise GraphError("%s is not connected to a downstream xForm" % nc)class DeformerArmature:    '''A node representing an armature deformer'''    def __init__(self, signature, base_tree):        self.base_tree=base_tree        self.signature = signature        self.inputs = {          "Input Relationship" : NodeSocket(is_input = True, name = "Input Relationship", node = self,),          "Target"             : NodeSocket(is_input = True, name = "Target", node = self,),          "Vertex Group"       : NodeSocket(is_input = True, name = "Vertex Group", node = self),          "Preserve Volume"    : NodeSocket(is_input = True, name = "Preserve Volume", node = self),          "Use Multi Modifier" : NodeSocket(is_input = True, name = "Use Multi Modifier", node = self),          "Use Envelopes"      : NodeSocket(is_input = True, name = "Use Envelopes", node = self),          "Use Vertex Groups"  : NodeSocket(is_input = True, name = "Use Vertex Groups", node = self),          "Skinning Method"    : NodeSocket(is_input = True, name = "Skinning Method", node = self),        }        self.outputs = {          "Deformer" : NodeSocket(is_input = False, name = "Deformer", node=self), }        self.parameters = {          "Name"               : None,          "Target"             : None,          "Vertex Group"       : None,          "Preserve Volume"    : None,          "Use Multi Modifier" : None,          "Use Envelopes"      : None,          "Use Vertex Groups"  : None,          "Skinning Method"    : None,        }        # now set up the traverse target...        self.inputs["Input Relationship"].set_traverse_target(self.outputs["Deformer"])        self.outputs["Deformer"].set_traverse_target(self.inputs["Input Relationship"])        self.node_type = "LINK"    def evaluate_input(self, input_name):        return default_evaluate_input(self, input_name)    def GetxForm(self):        return GetxForm(self)    def bExecute(self, bContext = None,):        prGreen("Executing Armature Deform Node\n")        print(self.GetxForm())        prOrange("My object: %s\n" % (self.GetxForm().bGetObject()))        prepare_parameters(self)        d = self.GetxForm().bGetObject().modifiers.new(self.evaluate_input("Name"), type='ARMATURE')        self.bObject = d        get_target_and_subtarget(self, d)        props_sockets = {        'vertex_group'       : ("Vertex Group", ""),        'use_deform_preserve_volume' : ("Preserve Volume", False),        'use_multi_modifier' : ("Use Multi Modifier", False),        'use_bone_envelopes' : ("Use Envelopes", False),        'use_vertex_groups' : ("Use Vertex Groups", False),        }        evaluate_sockets(self, d, props_sockets)           def initialize_vgroups(self, use_existing = False):        ob = self.GetxForm().bGetObject()        if use_existing == False:            ob.vertex_groups.clear()        armOb = self.evaluate_input("Target").bGetObject()        deform_bones = []        for b in armOb.data.bones:            if b.use_deform == True:                deform_bones.append(b)        for b in deform_bones:            vg = ob.vertex_groups.get(b.name)            if not vg:                vg = ob.vertex_groups.new(name=b.name)                num_verts = len(ob.data.vertices)                vg.add(range(num_verts), 0, 'REPLACE')                    def bFinalize(self, bContext=None):        if (skin_method := self.evaluate_input("Skinning Method")) == "AUTOMATIC_HEAT":            # This is reatarded and leads to somewhat unpredictable            #  behaviour, e.g. what object will be selected? What mode?            # also bpy.ops is ugly and prone to error when used in            #  scripts. I don't intend to use bpy.ops when I can avoid it.            import bpy            self.initialize_vgroups()            bContext.view_layer.depsgraph.update()            ob = self.GetxForm().bGetObject()            armOb = self.evaluate_input("Target").bGetObject()            deform_bones = []            for pb in armOb.pose.bones:                if pb.bone.use_deform == True:                    deform_bones.append(pb)                        context_override = {                                  'active_object':ob,                                  'selected_objects':[ob, armOb],                                  'active_pose_bone':deform_bones[0],                                  'selected_pose_bones':deform_bones,}            #            bpy.ops.object.mode_set({'active_object':armOb}, mode='POSE')            bpy.ops.pose.select_all(action='SELECT')            #            bpy.ops.paint.weight_paint_toggle(context_override)            bpy.ops.paint.weight_from_bones(context_override, type='AUTOMATIC')            # this is not working right now but I would like to normalize stuff.            # hmm. I think it normalizes automatically?            # bpy.ops.object.vertex_group_normalize_all({'active_object':ob}, group_select_mode='BONE_DEFORM', lock_active=False)            bpy.ops.paint.weight_paint_toggle(context_override)            #            bpy.ops.object.mode_set({'active_object':armOb}, mode='POSE')            bpy.ops.pose.select_all(action='DESELECT')            bpy.ops.object.mode_set({'active_object':armOb}, mode='OBJECT')            # TODO: modify Blender to make this available as a Python API function.        if skin_method == "EXISTING_GROUPS":            self.initialize_vgroups(use_existing = True)            def __repr__(self):        return self.signature.__repr__()    def fill_parameters(self):        fill_parameters(self)
 |