Welcome to this introduction into node development in Animation Nodes 2.0 or higher. In this guide you will learn how to get started with writing your own nodes (and I suggest you learn this before you try to modify existing nodes!). It will consist of multiple parts. Each part will go a bit more into detail so that you will be able to write more complex nodes in the end. The following tutorials expect you to have a basic knowledge in Python.
Now you are ready to create the actual file. Since Animation Nodes 2.0 there are two different types of source code files:
Python files: .py
These are just normal python files. Most nodes should be
of this type, there are only a very few nodes which aren’t. I suggest to
choose this type always at this stage. It will be easy to change it later if
necessary.
Cython files: .pyx
Cython is another programming
language that builds on top of Python. The main benefit is that it can be
compiled into machine code which can make it much faster than normal python
code. For most nodes this is absolute overkill, the performance benefit will
only be visible be computational expensive operations. Also you can only work
with Cython files when you setup the complete working environment.
The first simple node we want to create will be able to copy the location of one object to another object with an offset.
First create a file for this node following the rules above. Then copy this little template code into the file:
import bpy
from animation_nodes.base_types import AnimationNode
class TemplateNode(bpy.types.Node, AnimationNode):
bl_idname = "an_TemplateNode"
bl_label = "Template"
def create(self):
pass
def execute(self):
pass
This template is what I personally use for all new nodes, it is very easy to build up on it.
Now we have to choose a name for our new node. The most important thing here is
the bl_idname
because this is the identifier for your node, when you change
it later on, all files that used this node will be broken. Also it should have
a prefix like an_
so that it there will be no problems with other add-ons. So
make sure that you give it a good name that tells as exact as possible what the
node does. The class name and the bl_label
property can be changed later
without problems if necessary. Here is the updated “header” for our specific
example:
class CopyLocationWithOffsetNode(bpy.types.Node, AnimationNode):
bl_idname = "an_CopyLocationWithOffsetNode"
bl_label = "Copy Location with Offset"
The next step is to create the sockets we need. Therefor there is the
create(self)
function. In our example node we need three inputs. One
source object, one target object and the offset vector. So let’s create
those:
def create(self):
# Type Name Identifier
self.newInput("Object", "Source", "source")
self.newInput("Object", "Target", "target")
self.newInput("Vector", "Offset", "offset")
When creating a socket, we have to specify at least three parameters:
Type: This will determine which socket will be created, every socket has a
different color. There are a lot of socket types. Here are a few common one:
Object
, Vector
, Float
, Integer
, Object List
, …
Name: This name will be displayed in the Node Editor in Blender.
Identifier: The identifier is not very important for us yet. However you it
shouldn’t change if not absolutely necessary, but changing it is not as bad
as changing the bl_idname
. It is common to use this identifier as variable
name in the code later.
Last but not least we have to put some code into the execute
function. As
soon as the node has input sockets this function has to have parameters. In
this case we need three parameters, the names should correspond to the socket
identifiers. Also the order has to be the same. In the function body we can do
whatever we want with these objects. One thing we have to take care of is an
object can be None
. This has to be checked before anything else happens
because if there is an error in the node, the whole node tree suddenly stops
working.
def execute(self, source, target, offset):
if source is None or target is None:
return
target.location = source.location + offset
This node is already fully functional now. Below is all the code for this node again.
import bpy
from animation_nodes.base_types import AnimationNode
class CopyLocationWithOffsetNode(bpy.types.Node, AnimationNode):
bl_idname = "an_CopyLocationWithOffsetNode"
bl_label = "Copy Location with Offset"
def create(self):
self.newInput("Object", "Source", "source")
self.newInput("Object", "Target", "target")
self.newInput("Vector", "Offset", "offset")
def execute(self, source, target, offset):
if source is None or target is None:
return
target.location = source.location + offset
We will continue to work on this node in the next part.