Guest User

Untitled

a guest
Jul 17th, 2018
69
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
text 7.60 KB | None | 0 0
  1. # the little less documented way of adding a custom node tree
  2. # and populate it with nodes of varying types of I/O
  3. # sockets that work together, discombobulated
  4.  
  5. # first we import the blender API
  6. import bpy
  7.  
  8.  
  9. # then we create the UI space, the node tree as it is called
  10. # but in actualy fact this is similar to a UI panel/menu
  11. # and mostly handled in the background in terms of creation
  12. # so let's define out custom node tree, inheriting from its base type
  13. class CustomNodeTree(bpy.types.NodeTree):
  14. # the docstring here is used to generate documentation but
  15. # also used to display a description to the user
  16. '''A custom node tree type'''
  17. # then we can give it a custom id to access it, if not given
  18. # it will use the classname by default
  19. bl_idname='CustomNodeTree'
  20. # the label is the name that will be displayed to the user
  21. bl_label='Custom Node Tree'
  22. # the icon that will be displayed in the UI
  23. # NOTE: check the blender dev plugins to see icons in text editor
  24. bl_icon='BLENDER'
  25.  
  26.  
  27. # that is all we needed to make a nodetree
  28. # first for convenience we make a class from which all our nodes
  29. # will inherit from, saving us some typing
  30. class CustomNode(bpy.types.Node):
  31. # this line makes the node visible only to the 'CustomNodeTree'
  32. # node tree, essentially checking context
  33. @classmethod
  34. def poll(cls, ntree):
  35. return ntree.bl_idname == 'CustomNodeTree'
  36.  
  37.  
  38. # now we start making a simple input node that uses builtin
  39. # blender properties, this is the simplest node
  40. # we define the node class that inherits from its mixin class
  41. class CustomSimpleInputNode(CustomNode):
  42. # we can add a docstring that will be interpreted as description
  43. '''A simple input node'''
  44. # optionally we define an id that we can reference the node by
  45. bl_idname = 'CustomSimpleInputNode'
  46. # we add a label that the node will show the user as its name
  47. bl_label = 'Simple Input Node'
  48. # we can also add an icon to it
  49. bl_icon = 'PLUS'
  50.  
  51. # we can add properties here that the node uses locally
  52. # NOTE: does not get drawn automatically
  53. intProp = bpy.props.IntProperty()
  54.  
  55. # init function that is automagickally is called when the
  56. # node is instantiated into the treem setup sockets here
  57. # for both inputs and outputs
  58. def init(self, context):
  59. # makes a new output socket of type 'NodeSocketInt' with the
  60. # label 'output' on it
  61. # NOTE: no elements will be drawn for output sockets
  62. self.outputs.new('NodeSocketInt', "output")
  63.  
  64. # copy function is ran to initialize a copied node from
  65. # an existing one
  66. def copy(self, node):
  67. print("copied node", node)
  68.  
  69. # free function is called when an existing node is deleted
  70. def free(self):
  71. print("Node removed", self)
  72.  
  73. # draw method for drawing node UI just like any other
  74. # NOTE: input sockets are drawn by their respective methods
  75. # but output ones DO NOT for some reason, do it manually
  76. # and connect the drawn value to the output socket
  77. def draw_buttons(self, context, layout):
  78. # create a slider for int values
  79. layout.prop(self, 'intProp')
  80.  
  81. # this method lets you design how the node properties
  82. # are drawn on the side panel (to the right)
  83. # if it is not defined, draw_buttons will be used instead
  84. #def draw_buttons_ext(self, context, layout):
  85.  
  86. #OPTIONAL
  87. #we can use this function to dynamically define the label of
  88. # the node, however defining the bl_label explicitly overrides it
  89. #def draw_label(self):
  90. # return "this label is shown"
  91.  
  92.  
  93. # now to be able to see the nodes in the add node menu AND see it on the
  94. # tool shelf (left panel) we need to define node categories and then
  95. # register them, the rest is handled automagickally by blender
  96. # so first we import the utilities used for handling node categories
  97. import nodeitems_utils
  98.  
  99. # now we can make our own category using the NodeCategory baseclass
  100. # as before we first make a mixin class to save space
  101. class CustomNodeCategory(nodeitems_utils.NodeCategory):
  102. # define the classmethod that tells blender which node tree
  103. # the categories made with this class belong to (is visible to)
  104. @classmethod
  105. def poll(cls, context):
  106. return context.space_data.tree_type == 'CustomNodeTree'
  107.  
  108.  
  109. # make a list of node categories for registration
  110. node_categories = [
  111. # NOTE: did not find documentation other then template script for it
  112. # esentially:
  113. # we instantiate a new 'nodeitems_utils.NodeCategory' class, that
  114. # has been extended with a poll method that makes sure that the
  115. # category and node only shows up in the desired node tree
  116. # The first argument is a string with its id we will use to access it by
  117. # the second argument is the name displayed to the user
  118. # the third argument is a list of (items) nodes that are under
  119. # that category, the list contains instances 'nodeitems_utils.NodeItem'
  120. CustomNodeCategory("CUSTOMINPUTNODES", "Custom Input Nodes", items=[
  121. # the nodes (items) in this category are instantiated in this list
  122. # with the 'nodeitems_utils.NodeItem' class, which can have
  123. # additional settings
  124. # the first argument is the node class idname we want to add
  125. # then there can be keyword arguments like label
  126. # another argument can be a 'settings' keyword argument
  127. # that takes a dictionary that can override default values of all
  128. # properties
  129. # NOTE: use 'repr()' to convert the value to string IMPORTANT
  130. nodeitems_utils.NodeItem("CustomSimpleInputNode",
  131. label="Simple Input", settings={"intProp":repr(1.0)}),
  132. # minimalistic node addition is like this
  133. nodeitems_utils.NodeItem("CustomSimpleInputNode"),
  134. ]),
  135. ]
  136.  
  137.  
  138.  
  139. #finally we register our classes so we can install as plugin
  140. #to that end we create a list of classes to be loaded and unloaded
  141. classes=(
  142. CustomNodeTree,
  143. CustomSimpleInputNode,
  144. )
  145.  
  146. # for loading we define the registering of all defined classes
  147. def register():
  148. # we register all our classes into blender
  149. for cls in classes:
  150. bpy.utils.register_class(cls)
  151. # we register the node categories with the node tree
  152. # the first argument is a string that is the idname for this collection
  153. # of categories
  154. # the second is the actual list of node categories to be registered under
  155. # this name
  156. nodeitems_utils.register_node_categories("CUSTOM_NODES", node_categories)
  157.  
  158.  
  159. # for unloading we define the unregistering of all defined classes
  160. def unregister():
  161. # we unregister our node categories first
  162. nodeitems_utils.unregister_node_categories("CUSTOM_NODES")
  163. # then we unregister all classes from the blender
  164. for cls in classes:
  165. bpy.utils.unregister_class(cls)
  166.  
  167.  
  168. # finally we make it runnable in the text editor for quick testing
  169. if __name__=='__main__':
  170. # during test running there is a bug where registering or adding
  171. # references to certain groups and categories cannot override
  172. # existing ones, here is a workaround
  173. # we enter a try..finally block
  174. try:
  175. # first try unregistering the existing category
  176. # WARNING: ALWAYS triple check that you unload the correct
  177. # things in this block, as it will not raise errors
  178. nodeitems_utils.unregister_node_categories("CUSTOM_NODES")
  179. finally:
  180. # finally, wether it suceeded or not, we can now register it again
  181. # this essentially reloads existing/register changes made
  182. # and thanks to the nature of the finally block, is always run
  183. register()
Add Comment
Please, Sign In to add comment