Custom node plugins must be placed in the .panjea folder inside your home directory. Each plugin should start with the name pyjea_. Plugins run inside the Python2 subprocess, but they can contain exported functions that run in the main Blender process (Python3). A plugin must define a function called register that takes the argument api. To register your custom node class, call the function: api["register_node"] passing it your class. Note that all plugins share the same namespace, so make sure you provide unique class and function names.
Below is an example of a minimal custom node, and how to register it. Your class should have: an icon symbol, a title, inputs list, __init__ method, and eval method.
import math class mynode( object ): icon = u'√' title = 'Square Root' inputs = [ (1,'number') ] def __init__(self, node): node(self) def eval(self, number): return math.sqrt( number ) def register( api ): api['register_node']( mynode )
Blender functions are registered when your node is created, inside your __init__ constructor call the node object passing your function with the keyword argument bpy=myfunc. The call to node will return a signal function wrapper that you can use in your eval method to call the Blender function. Blender functions can use the Blender bpy API directly, and call exported functions from other plugins, but they can not reference global variables from your plugin script. In general, your Blender function should take as its first argument a name, which is the name of the Blender object you are creating or updating, then your function should check if that name is already in bpy.data.objects, if so then update it, otherwise create it. If your function creates many meshes, you should join them together into a single mesh as the last step, this way it remains compatible with the Instance Node.
class myobject( object ): icon = u'🌲' title = 'Tree' inputs = [(2,'name'), (1,'x'), (1,'y'), (1,'z')] def __init__(self, node): self.signal = node(self, bpy=make_tree) def eval(self, name, x,y,z): self.signal( name, x,y,z ) return name
Above is the class which creates the custom node, inside of __init__ the make_tree function is passed to the node using the bpy keyword. The make_tree function runs in the Blender process, and calls the Blender Python API (bpy). Below is the source of the make_tree function, these are all standard bpy calls, except for api.select this is used because it allows the code to be compatible with Blender2.79 and Blender2.8 and newer.
def make_tree(name, x,y,z): if name in bpy.data.objects: ob = bpy.data.objects[ name ] ob.location = [x,y,z] return bpy.ops.mesh.primitive_cone_add() top = bpy.context.active_object top.location = [x,y,z+2] mat = bpy.data.materials.new(name=name) top.data.materials.append(mat) mat.diffuse_color[0] = 0 mat.diffuse_color[1] = 1 mat.diffuse_color[2] = 0 bpy.ops.mesh.primitive_cylinder_add(vertices=16, radius=0.2) trunk = bpy.context.active_object trunk.name = name trunk.location = [x,y,z] mat = bpy.data.materials.new(name=name+'.trunk') trunk.data.materials.append(mat) mat.diffuse_color[0] = 0.25 mat.diffuse_color[1] = 0.25 mat.diffuse_color[2] = 0.1 api.select(top) bpy.ops.object.join()
The bpy API has three main parts that most plugins will use: bpy.ops, bpy.context, and bpy.data. The api object is a simpler abstraction layer on top of these interfaces, and stays backwards compatible with Blender2.79.
To make your custom plugin compatible with the Tile Node you need to follow these rules: