Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- # the little less documented way of adding a custom node tree
- # and populate it with nodes of varying types of I/O
- # sockets that work together, discombobulated
- # first we import the blender API
- import bpy
- # then we create the UI space, the node tree as it is called
- # but in actualy fact this is similar to a UI panel/menu
- # and mostly handled in the background in terms of creation
- # so let's define out custom node tree, inheriting from its base type
- class CustomNodeTree(bpy.types.NodeTree):
- # the docstring here is used to generate documentation but
- # also used to display a description to the user
- '''A custom node tree type'''
- # then we can give it a custom id to access it, if not given
- # it will use the classname by default
- bl_idname='CustomNodeTree'
- # the label is the name that will be displayed to the user
- bl_label='Custom Node Tree'
- # the icon that will be displayed in the UI
- # NOTE: check the blender dev plugins to see icons in text editor
- bl_icon='BLENDER'
- # that is all we needed to make a nodetree
- # first for convenience we make a class from which all our nodes
- # will inherit from, saving us some typing
- class CustomNode(bpy.types.Node):
- # this line makes the node visible only to the 'CustomNodeTree'
- # node tree, essentially checking context
- @classmethod
- def poll(cls, ntree):
- return ntree.bl_idname == 'CustomNodeTree'
- # now we start making a simple input node that uses builtin
- # blender properties, this is the simplest node
- # we define the node class that inherits from its mixin class
- class CustomSimpleInputNode(CustomNode):
- # we can add a docstring that will be interpreted as description
- '''A simple input node'''
- # optionally we define an id that we can reference the node by
- bl_idname = 'CustomSimpleInputNode'
- # we add a label that the node will show the user as its name
- bl_label = 'Simple Input Node'
- # we can also add an icon to it
- bl_icon = 'PLUS'
- # we can add properties here that the node uses locally
- # NOTE: does not get drawn automatically
- intProp = bpy.props.IntProperty()
- # init function that is automagickally is called when the
- # node is instantiated into the treem setup sockets here
- # for both inputs and outputs
- def init(self, context):
- # makes a new output socket of type 'NodeSocketInt' with the
- # label 'output' on it
- # NOTE: no elements will be drawn for output sockets
- self.outputs.new('NodeSocketInt', "output")
- # copy function is ran to initialize a copied node from
- # an existing one
- def copy(self, node):
- print("copied node", node)
- # free function is called when an existing node is deleted
- def free(self):
- print("Node removed", self)
- # draw method for drawing node UI just like any other
- # NOTE: input sockets are drawn by their respective methods
- # but output ones DO NOT for some reason, do it manually
- # and connect the drawn value to the output socket
- def draw_buttons(self, context, layout):
- # create a slider for int values
- layout.prop(self, 'intProp')
- # this method lets you design how the node properties
- # are drawn on the side panel (to the right)
- # if it is not defined, draw_buttons will be used instead
- #def draw_buttons_ext(self, context, layout):
- #OPTIONAL
- #we can use this function to dynamically define the label of
- # the node, however defining the bl_label explicitly overrides it
- #def draw_label(self):
- # return "this label is shown"
- # now to be able to see the nodes in the add node menu AND see it on the
- # tool shelf (left panel) we need to define node categories and then
- # register them, the rest is handled automagickally by blender
- # so first we import the utilities used for handling node categories
- import nodeitems_utils
- # now we can make our own category using the NodeCategory baseclass
- # as before we first make a mixin class to save space
- class CustomNodeCategory(nodeitems_utils.NodeCategory):
- # define the classmethod that tells blender which node tree
- # the categories made with this class belong to (is visible to)
- @classmethod
- def poll(cls, context):
- return context.space_data.tree_type == 'CustomNodeTree'
- # make a list of node categories for registration
- node_categories = [
- # NOTE: did not find documentation other then template script for it
- # esentially:
- # we instantiate a new 'nodeitems_utils.NodeCategory' class, that
- # has been extended with a poll method that makes sure that the
- # category and node only shows up in the desired node tree
- # The first argument is a string with its id we will use to access it by
- # the second argument is the name displayed to the user
- # the third argument is a list of (items) nodes that are under
- # that category, the list contains instances 'nodeitems_utils.NodeItem'
- CustomNodeCategory("CUSTOMINPUTNODES", "Custom Input Nodes", items=[
- # the nodes (items) in this category are instantiated in this list
- # with the 'nodeitems_utils.NodeItem' class, which can have
- # additional settings
- # the first argument is the node class idname we want to add
- # then there can be keyword arguments like label
- # another argument can be a 'settings' keyword argument
- # that takes a dictionary that can override default values of all
- # properties
- # NOTE: use 'repr()' to convert the value to string IMPORTANT
- nodeitems_utils.NodeItem("CustomSimpleInputNode",
- label="Simple Input", settings={"intProp":repr(1.0)}),
- # minimalistic node addition is like this
- nodeitems_utils.NodeItem("CustomSimpleInputNode"),
- ]),
- ]
- #finally we register our classes so we can install as plugin
- #to that end we create a list of classes to be loaded and unloaded
- classes=(
- CustomNodeTree,
- CustomSimpleInputNode,
- )
- # for loading we define the registering of all defined classes
- def register():
- # we register all our classes into blender
- for cls in classes:
- bpy.utils.register_class(cls)
- # we register the node categories with the node tree
- # the first argument is a string that is the idname for this collection
- # of categories
- # the second is the actual list of node categories to be registered under
- # this name
- nodeitems_utils.register_node_categories("CUSTOM_NODES", node_categories)
- # for unloading we define the unregistering of all defined classes
- def unregister():
- # we unregister our node categories first
- nodeitems_utils.unregister_node_categories("CUSTOM_NODES")
- # then we unregister all classes from the blender
- for cls in classes:
- bpy.utils.unregister_class(cls)
- # finally we make it runnable in the text editor for quick testing
- if __name__=='__main__':
- # during test running there is a bug where registering or adding
- # references to certain groups and categories cannot override
- # existing ones, here is a workaround
- # we enter a try..finally block
- try:
- # first try unregistering the existing category
- # WARNING: ALWAYS triple check that you unload the correct
- # things in this block, as it will not raise errors
- nodeitems_utils.unregister_node_categories("CUSTOM_NODES")
- finally:
- # finally, wether it suceeded or not, we can now register it again
- # this essentially reloads existing/register changes made
- # and thanks to the nature of the finally block, is always run
- register()
Add Comment
Please, Sign In to add comment