123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188 |
- import bpy
- from bpy.types import NodeTree, Node, NodeSocket
- # Implementation of custom nodes from Python
- # Derived from the NodeTree base type, similar to Menu, Operator, Panel, etc.
- class MyCustomTree(NodeTree):
- # Description string
- '''A custom node tree type that will show up in the editor type list'''
- # Optional identifier string. If not explicitly defined, the python class name is used.
- bl_idname = 'CustomTreeType'
- # Label for nice name display
- bl_label = "Custom Node Tree"
- # Icon identifier
- bl_icon = 'NODETREE'
- # Custom socket type
- class MyCustomSocket(NodeSocket):
- # Description string
- '''Custom node socket type'''
- # Optional identifier string. If not explicitly defined, the python class name is used.
- bl_idname = 'CustomSocketType'
- # Label for nice name display
- bl_label = "Custom Node Socket"
- # Enum items list
- my_items = (
- ('DOWN', "Down", "Where your feet are"),
- ('UP', "Up", "Where your head should be"),
- ('LEFT', "Left", "Not right"),
- ('RIGHT', "Right", "Not left"),
- )
- my_enum_prop: bpy.props.EnumProperty(
- name="Direction",
- description="Just an example",
- items=my_items,
- default='UP',
- )
- # Optional function for drawing the socket input value
- def draw(self, context, layout, node, text):
- if self.is_output or self.is_linked:
- layout.label(text=text)
- else:
- layout.prop(self, "my_enum_prop", text=text)
- # Socket color
- def draw_color(self, context, node):
- return (1.0, 0.4, 0.216, 0.5)
- # Mix-in class for all custom nodes in this tree type.
- # Defines a poll function to enable instantiation.
- class MyCustomTreeNode:
- @classmethod
- def poll(cls, ntree):
- return ntree.bl_idname == 'CustomTreeType'
- # Derived from the Node base type.
- class MyCustomNode(Node, MyCustomTreeNode):
- # === Basics ===
- # Description string
- '''A custom node'''
- # Optional identifier string. If not explicitly defined, the python class name is used.
- bl_idname = 'CustomNodeType'
- # Label for nice name display
- bl_label = "Custom Node"
- # Icon identifier
- bl_icon = 'SOUND'
- # === Custom Properties ===
- # These work just like custom properties in ID data blocks
- # Extensive information can be found under
- # http://wiki.blender.org/index.php/Doc:2.6/Manual/Extensions/Python/Properties
- my_string_prop: bpy.props.StringProperty()
- my_float_prop: bpy.props.FloatProperty(default=3.1415926)
- # === Optional Functions ===
- # Initialization function, called when a new node is created.
- # This is the most common place to create the sockets for a node, as shown below.
- # NOTE: this is not the same as the standard __init__ function in Python, which is
- # a purely internal Python method and unknown to the node system!
- def init(self, context):
- self.inputs.new('CustomSocketType', "Hello")
- self.inputs.new('NodeSocketFloat', "World")
- self.inputs.new('NodeSocketVector', "!")
- self.outputs.new('NodeSocketColor', "How")
- self.outputs.new('NodeSocketColor', "are")
- self.outputs.new('NodeSocketFloat', "you")
- # Copy function to initialize a copied node from an existing one.
- def copy(self, node):
- print("Copying from node ", node)
- # Free function to clean up on removal.
- def free(self):
- print("Removing node ", self, ", Goodbye!")
- # Additional buttons displayed on the node.
- def draw_buttons(self, context, layout):
- layout.label(text="Node settings")
- layout.prop(self, "my_float_prop")
- # Detail buttons in the sidebar.
- # If this function is not defined, the draw_buttons function is used instead
- def draw_buttons_ext(self, context, layout):
- layout.prop(self, "my_float_prop")
- # my_string_prop button will only be visible in the sidebar
- layout.prop(self, "my_string_prop")
- # Optional: custom label
- # Explicit user label overrides this, but here we can define a label dynamically
- def draw_label(self):
- return "I am a custom node"
- ### Node Categories ###
- # Node categories are a python system for automatically
- # extending the Add menu, toolbar panels and search operator.
- # For more examples see release/scripts/startup/nodeitems_builtins.py
- import nodeitems_utils
- from nodeitems_utils import NodeCategory, NodeItem
- # our own base class with an appropriate poll function,
- # so the categories only show up in our own tree type
- class MyNodeCategory(NodeCategory):
- @classmethod
- def poll(cls, context):
- return context.space_data.tree_type == 'CustomTreeType'
- # all categories in a list
- node_categories = [
- # identifier, label, items list
- MyNodeCategory('SOMENODES', "Some Nodes", items=[
- # our basic node
- NodeItem("CustomNodeType"),
- ]),
- MyNodeCategory('OTHERNODES', "Other Nodes", items=[
- # the node item can have additional settings,
- # which are applied to new nodes
- # NB: settings values are stored as string expressions,
- # for this reason they should be converted to strings using repr()
- NodeItem("CustomNodeType", label="Node A", settings={
- "my_string_prop": repr("Lorem ipsum dolor sit amet"),
- "my_float_prop": repr(1.0),
- }),
- NodeItem("CustomNodeType", label="Node B", settings={
- "my_string_prop": repr("consectetur adipisicing elit"),
- "my_float_prop": repr(2.0),
- }),
- ]),
- ]
- classes = (
- MyCustomTree,
- MyCustomSocket,
- MyCustomNode,
- )
- def register():
- from bpy.utils import register_class
- for cls in classes:
- register_class(cls)
- nodeitems_utils.register_node_categories('CUSTOM_NODES', node_categories)
- def unregister():
- nodeitems_utils.unregister_node_categories('CUSTOM_NODES')
- from bpy.utils import unregister_class
- for cls in reversed(classes):
- unregister_class(cls)
- if __name__ == "__main__":
- register()
|