Bladeren bron

init geometry attribute constraint

Trung 3 maanden geleden
bovenliggende
commit
2cdf7bea7d
6 gewijzigde bestanden met toevoegingen van 190 en 19 verwijderingen
  1. 1 0
      __init__.py
  2. 22 0
      link_nodes.py
  3. 29 0
      link_nodes_ui.py
  4. 31 0
      link_socket_templates.py
  5. 20 19
      ops_generate_tree.py
  6. 87 0
      socket_definitions.py

+ 1 - 0
__init__.py

@@ -110,6 +110,7 @@ link_relationship_category = [
         NodeItem("linkInherit"),
         NodeItem("LinkInheritConstraint"),
         NodeItem("LinkArmature"),
+        NodeItem("LinkGeometryAttribute"),
     ]
 deformer_category=[NodeItem(cls.bl_idname) for cls in deformer_nodes_ui.TellClasses()]
 xForm_category = [

+ 22 - 0
link_nodes.py

@@ -32,6 +32,7 @@ def TellClasses():
              # stuff that snaps or limits a bone
              LinkFloor,
              LinkShrinkWrap,
+             LinkGeometryAttribute,
              # Drivers
              LinkDrivenParameter,
             ]
@@ -910,3 +911,24 @@ class LinkShrinkWrap(MantisLinkNode):
             # self.set_custom_space() # this needs to be overridden for me TODO
             evaluate_sockets(self, c, props_sockets)
         self.executed = True
+
+
+class LinkGeometryAttribute(MantisLinkNode):
+    '''A node representing a geometry attribute relationship.'''
+    def __init__(self, signature, base_tree,):
+        super().__init__(signature, base_tree, LinkGeometryAttributeSockets)
+        self.init_parameters(additional_parameters={"Name":None })
+        self.set_traverse([("Input Relationship", "Output Relationship")])
+
+    def bRelationshipPass(self, bContext = None,):
+        prepare_parameters(self)
+        for xf in self.GetxForm():
+            print
+            c = xf.bGetObject().constraints.new('GEOMETRY_ATTRIBUTE')
+            self.get_target_and_subtarget(c)
+            if constraint_name := self.evaluate_input("Name"):
+                c.name = constraint_name
+            props_sockets = self.gen_property_socket_map()
+            self.bObject.append(c)
+            evaluate_sockets(self, c, props_sockets)
+        self.executed = True

+ 29 - 0
link_nodes_ui.py

@@ -30,6 +30,7 @@ def TellClasses():
              LinkSplineIKNode,
              LinkFloorNode,
              LinkShrinkWrapNode,
+             LinkGeometryAttribute,
              LinkTransformationNode,
            ]
 
@@ -434,6 +435,34 @@ class LinkShrinkWrapNode(Node, LinkNode):
         # TODO: this stuff should be handled by input tags
         # once I get that working.
 
+class LinkGeometryAttribute(Node, LinkNode):
+    """A node representing Blender's Geometry Attribute Constraint"""
+    bl_idname = "LinkGeometryAttribute"
+    bl_label = "Geometry Attribute"
+    bl_icon = "CON_GEOMETRYATTRIBUTE"
+    initialized : bpy.props.BoolProperty(default = False)
+    mantis_node_class_name=bl_idname
+
+    def init(self, context):
+        self.init_sockets(LinkGeometryAttributeSockets)
+        self.use_custom_color = True
+        self.color = trackingColor
+        self.initialized = True
+
+    def display_update(self, parsed_tree, context):
+        pass
+        # vast majority of the time user doesn't link this.
+        data_type = self.inputs['Data Type'].default_value
+        if self.inputs['Data Type'].is_linked:# 1% or less of cases
+            node_tree = context.space_data.path[0].node_tree
+            nc = parsed_tree.get(get_signature_from_edited_tree(self, context))
+            if nc:
+                data_type = nc.evaluate_input("Data Type")
+        not_matrix_mode = data_type != 'FLOAT4X4'
+        self.inputs['Enabled Location'].hide=not_matrix_mode
+        self.inputs['Enabled Rotation'].hide=not_matrix_mode
+        self.inputs['Enabled Scale'].hide=not_matrix_mode
+
 # DRIVERS!!
 class LinkDrivenParameterNode(Node, LinkNode):
     """Represents a driven parameter in the downstream xForm node."""

+ 31 - 0
link_socket_templates.py

@@ -463,6 +463,37 @@ LinkShrinkWrapSockets = [
     OutputRelationshipTemplate,
 ]
 
+LinkGeometryAttributeSockets = [
+    InputRelationshipTemplate,
+    TargetTemplate, # IMPORTANT TO DO: targets should be an array
+    # and the constraints are made  ONLY if the target is valid...
+    # for BONE targets, maybe auto-magically build a mesh for the user.
+    # this is a little bit too hard to do for now. Users can just make a schema.
+    OffsetTargetTransformTemplate:= SockTemplate(name="Offset target transform", is_input=True,
+            bl_idname="BooleanSocket", blender_property='apply_target_transform'),
+    AttributeTemplate:= SockTemplate(name="Attribute", bl_idname="ParameterStringSocket", is_input=True,
+                 default_value="position", blender_property='attribute_name'),
+    DataTypeTemplate := SockTemplate(name="Data Type",
+            bl_idname="EnumGeometryAttributeDataTypeSocket", is_input=True,
+            blender_property='data_type'),
+    DomainTemplate := SockTemplate(name="Domain",
+            bl_idname="EnumGeometryAttributeDomainSocket", is_input=True,
+            blender_property='domain'),
+    SampleIndex := SockTemplate(name="Sample Index", bl_idname='UnsignedIntSocket',
+        is_input=True, default_value=0,blender_property='sample_index'),
+    EnabledLocationTemplate:= SockTemplate(name="Enabled Location", is_input=True,
+            bl_idname="BooleanSocket", blender_property='mix_loc'),
+    EnabledRotationTemplate:= SockTemplate(name="Enabled Rotation", is_input=True,
+            bl_idname="BooleanSocket", blender_property='mix_rot'),
+    EnabledScaleTemplate:= SockTemplate(name="Enabled Scale", is_input=True,
+            bl_idname="BooleanSocket", blender_property='mix_scl'),
+    SockTemplate(name='Mix Mode',  bl_idname='EnumMixModeGeometryAttribute', is_input=True,
+                         default_value='REPLACE', blender_property='mix_mode'),
+    InfluenceTemplate,
+    EnableTemplate,
+    OutputRelationshipTemplate,
+]
+
 # Remove this socket because of Blender changes.
 if (app.version >= (4, 5, 0)):
     LinkSplineIKSockets.pop(9)

+ 20 - 19
ops_generate_tree.py

@@ -59,25 +59,26 @@ def get_pretty_name(name):
 
 
 constraint_link_map={
-    'COPY_LOCATION'   : "LinkCopyLocation",
-    'COPY_ROTATION'   : "LinkCopyRotation",
-    'COPY_SCALE'      : "LinkCopyScale",
-    'COPY_TRANSFORMS' : "LinkCopyTransforms",
-    'LIMIT_DISTANCE'  : "LinkLimitDistance",
-    'LIMIT_LOCATION'  : "LinkLimitLocation",
-    'LIMIT_ROTATION'  : "LinkLimitRotation",
-    'LIMIT_SCALE'     : "LinkLimitScale",
-    'DAMPED_TRACK'    : "LinkDampedTrack",
-    'LOCKED_TRACK'    : "LinkLockedTrack",
-    'STRETCH_TO'      : "LinkStretchTo",
-    'TRACK_TO'        : "LinkTrackTo",
-    'CHILD_OF'        : "LinkInheritConstraint",
-    'IK'              : "LinkInverseKinematics",
-    'ARMATURE'        : "LinkArmature",
-    'SPLINE_IK'       : "LinkSplineIK",
-    'TRANSFORM'       : "LinkTransformation",
-    'FLOOR'           : "LinkFloor",
-    'SHRINKWRAP'      : "LinkShrinkWrap"
+    'COPY_LOCATION'     : "LinkCopyLocation",
+    'COPY_ROTATION'     : "LinkCopyRotation",
+    'COPY_SCALE'        : "LinkCopyScale",
+    'COPY_TRANSFORMS'   : "LinkCopyTransforms",
+    'LIMIT_DISTANCE'    : "LinkLimitDistance",
+    'LIMIT_LOCATION'    : "LinkLimitLocation",
+    'LIMIT_ROTATION'    : "LinkLimitRotation",
+    'LIMIT_SCALE'       : "LinkLimitScale",
+    'DAMPED_TRACK'      : "LinkDampedTrack",
+    'LOCKED_TRACK'      : "LinkLockedTrack",
+    'STRETCH_TO'        : "LinkStretchTo",
+    'TRACK_TO'          : "LinkTrackTo",
+    'CHILD_OF'          : "LinkInheritConstraint",
+    'IK'                : "LinkInverseKinematics",
+    'ARMATURE'          : "LinkArmature",
+    'SPLINE_IK'         : "LinkSplineIK",
+    'TRANSFORM'         : "LinkTransformation",
+    'FLOOR'             : "LinkFloor",
+    'SHRINKWRAP'        : "LinkShrinkWrap",
+    'GEOMETRY_ATTRIBUTE': "LinkGeometryAttribute"
     }
 
 def create_relationship_node_for_constraint(node_tree, c):

+ 87 - 0
socket_definitions.py

@@ -246,6 +246,10 @@ def TellClasses() -> List[MantisSocket]:
              EnumShrinkwrapFaceCullSocket,
              EnumShrinkwrapProjectAxisSocket,
              EnumShrinkwrapModeSocket,
+             # Geometry Attribute
+             EnumGeometryAttributeDataTypeSocket,
+             EnumGeometryAttributeDomainSocket,
+             EnumMixModeGeometryAttribute,
              # Deformers
              EnumSkinning,
              MorphTargetSocket,
@@ -2448,6 +2452,89 @@ class EnumShrinkwrapModeSocket(MantisSocket):
         return self.color_simple
 
 
+eDataTypeMode = (
+       ('VECTOR', "Vector", "Vector", 0), 
+       ('QUATERNION', "Quaternion", "", 1), 
+       ('FLOAT4X4', "4x4 Matrix", "", 2), )
+
+class EnumGeometryAttributeDataTypeSocket(MantisSocket):
+    '''Shrinkwrap Mode Socket'''
+    bl_idname = 'EnumGeometryAttributeDataTypeSocket'
+    bl_label = "Datatype"
+    default_value: bpy.props.EnumProperty(
+        items=eDataTypeMode,
+        description="Select the data type of the attribute",
+        default = 'VECTOR',
+        update = update_socket,)
+    color_simple = cString
+    color : bpy.props.FloatVectorProperty(default=cString, size=4)
+    input : bpy.props.BoolProperty(default =False,)
+    def draw(self, context, layout, node, text):
+        ChooseDraw(self, context, layout, node, text, use_enum=False)
+    def draw_color(self, context, node):
+        return self.color
+    @classmethod
+    def draw_color_simple(self):
+        return self.color_simple
+
+eDomaineMode = (
+    ('POINT', "Point", "Point", 0), 
+    ('EDGE', "Edge", "Edge", 1), 
+    ('FACE', "Face", "Face", 2), 
+    ('FACE_CORNER', "Face Corner", "Face Corner", 3), 
+    ('SPLINE', "Spline", "Spline", 4), 
+    ('INSTANCE', "Instance", "Instance", 5), )
+
+class EnumGeometryAttributeDomainSocket(MantisSocket):
+    '''Shrinkwrap Mode Socket'''
+    bl_idname = 'EnumGeometryAttributeDomainSocket'
+    bl_label = "Domain"
+    default_value: bpy.props.EnumProperty(
+        items=eDomaineMode,
+        description="Select the data type of the attribute",
+        default = 'POINT',
+        update = update_socket,)
+    color_simple = cString
+    color : bpy.props.FloatVectorProperty(default=cString, size=4)
+    input : bpy.props.BoolProperty(default =False,)
+    def draw(self, context, layout, node, text):
+        ChooseDraw(self, context, layout, node, text, use_enum=False)
+    def draw_color(self, context, node):
+        return self.color
+    @classmethod
+    def draw_color_simple(self):
+        return self.color_simple
+
+eMix_geometryattribute =(
+        ('REPLACE', "Replace (Aligned)", "Fully inherit scale"),
+        ('BEFORE_SPLIT', "Before (Split Channels)", "Fully inherit scale"),
+        ('AFTER_SPLIT', "After (Split Channels)", "Fully inherit scale"),
+        ('BEFORE_FULL', "Before (Full)", "Fully inherit scale"),
+        ('AFTER_FULL', "After (Full)", "Fully inherit scale"),)
+
+class EnumMixModeGeometryAttribute(MantisSocket):
+    '''Custom node socket type'''
+    bl_idname = 'EnumMixModeGeometryAttribute'
+    bl_label = "Rotation Mix"
+
+    default_value: bpy.props.EnumProperty(
+        items=eMix_geometryattribute,
+        name="Mix Mode",
+        description="Mix mode",
+        default = 'REPLACE', #{'REPLACE'},
+        #options = {'ENUM_FLAG'}, # this sux
+        update = update_socket,)
+    color_simple = cString
+    color : bpy.props.FloatVectorProperty(default=cString, size=4)
+    input : bpy.props.BoolProperty(default =False,)
+    def draw(self, context, layout, node, text):
+        ChooseDraw(self, context, layout, node, text)
+    def draw_color(self, context, node):
+        return self.color
+    @classmethod
+    def draw_color_simple(self):
+        return self.color_simple
+
 eSkinningMethod = (('EXISTING_GROUPS', "Use Existing Groups", "Use the existing vertex groups, or create empty groups if not found.",),
                    ('AUTOMATIC_HEAT', "Automatic (Heat)", "Use Blender's heatmap automatic skinning",),
                    ('COPY_FROM_OBJECT', "Copy from object", "Copy skin weights from the selected object"),)