Tools for Cycles PyNodes

Hi all,

I’ve been writing some tools for creating PyNodes for Cycles, and although there is still much to do, the basic stuff is now functional, so if you wish to take a look…

This is still the beggining of a bigger journey, and for now, there isn’t much, aside basic support for new nodes.
The Addon has also an operator for converting node_groups to a basic node. Select the node_group, press SPACE and look for ‘Convert Selected NodeGroup to PyNode’.
It will ask for bl_name and bl_label, and automatically create the *.py file in the ‘Nodes’ folder. After this, the node will be present in the new ‘Custom Nodes’ in the Add menu.
This node will be similar to the node_group, but any user can edit the script add/change functionalities.

Any sugestions or help is welcome.

7 Likes

this is great, i’d need to try it and give a feedback thanks. :slight_smile:

i had this error while installing it from user preferences.


Thanks for pointing that out.
Forgot to change some tabs into spaces… Fixed now
And fixed the unregister_nodes, so starting will no nodes will work.

Awesome, it works perfectly well, now I’d need to organize my node trees and make them custom nodes. Thanks once again for this :slight_smile:

I’m still changing the Node Interface, for more complex nodes.

The next version will have all of these working:

self.value_set(obj, attr, val)
self.addNode(NodeType, NodeAttributes)
self.delNode(Node)
self.addInputSocket(SocketType, SocketAttributes)
self.delInputSocket(Socket)
self.addOutputSocket(SocketType, SocketAttributes)
self.delOutputSocket(Socket)
self.addLink(Socket, Socket)
self.delLink(Link)

and i’m still making experiments to include self.MenuCategory() so on register, the node will be placed in the Category returned from that function. (this will also help creating an AddMenu editor later)

Awesome, work thanks for all of this :slight_smile: . I’d like to ask, apart from it saving our ubershaders/node trees as a custom node in our blend file is there a way of saving it as a proper material preset to re-use instead of appending it from another file. Maybe if there’s a way of creating an add and store function to keep the nodes when we open another new file? Am not into python fully yet still a noob on it.

If the custom node is being used in some .blend file, it will still work when that file is opened on a blender version without this addon.
The only problem is that the node will loose all its UI funcionality; it will work just as the original nodegroup, thought this api is for making nodes a bit more complex than nodegroups.

This is good enough for sending the file to render farms… But for editing, it’s better to install the addon; thought it’s possible to include a small version of the script in the blend file, the user will have to enable the option for running automatic scripts in the file.

If later, this api is accepted as a standard blender module, it could easilly be merged into the current nodeitems_utils and nodeitems_builtins, and everything would work flawlessly in every blender machine.
My main problem ATM, is more related to other Custom Nodes, that may not follow the current modules standards (on which I’m basing this work). So there’s much work to do in order to make this an api for every custom node.

Wow, this is really great and a huge task too, I see the possibility of this being accepted as a standard blender module. I’m loving this more already :slight_smile:

This is great idea. Thanks for sharing

Thanks a lot Secrop!
At soon…:o
Spirou4D

Got finally some more time to work on this…
New version 0.1.5 is on Github.

Change Notes:
-Previous nodes done by the converter will no longer work with this version. If that’s a problem for you, please send me the node code, so I can convert it. (I didn’t wrote any upgrade converter, since this is still in Alpha phase)

-The node interface is now like this:self.value_set(obj, attr, val)
self.value_get(obj, attr)
self.addNode(NodeType, **NodeAttributes)
self.delNode(Node)
self.addInput(SocketType, **SocketAttributes)
self.delInput(Socket)
self.addOutput(SocketType, **SocketAttributes)
self.delOutput(Socket)
self.addLink(Socket, Socket)
self.delLink(Link)

*nodes, *links, *inputs and *outputs are placed in the self., for convenience.

-It’s now possible to place the node in a different menu. You only need to have the following function:def menu_draw():

[INDENT=2]return Category.Identifier, Category.Name
[/INDENT]

If the function is not there then a default category will be created. And the same if there isn’t any Category with those properties.
(this is still incomplete and for now, the default order on the add menu may change if adding nodes to existing Categories)

If you want to block the internal nodetrees from appearing in the Add menu, you need to uncomment the configBlender() and revertBlender() in the register and unregister functions of the init.py
(I just left it like that because sometimes is usefull for looking inside the nodetrees, for debugging purposes)

For those who’ll look to the source code… there’s a call in the ShaderNodeBase to a ShaderNodeScript.compile method.
Consider it the Easter Egg!
That’s right! I’m writing a compiler. Most part of the ast generator is ready, as well as the lexer and the basic structures for the grammar. :cool:
This is because making a mathematical function by adding operators, then linking everything is a pain!!

But I stumbled in a small dilema, from wich I would like to ear from you.
Should I base the script language in Python or in OSL?
Note that lots of things from OSL and Python will not be present.

I was thinking in something like this for python:


def defaultNodeScript(*inputs, *outputs):
    setattr(inputs, 'Metadata Attributes')

    def functionA(*inputs, *outputs):
         outputs=some function with the inputs

    def functionB(*inputs, *outputs):
         outputs=some function with the inputs
 
    outputs=do something with the inputs and the functions

For OSL it would be more or less the same, but with only 4 types: float, float3, float4, Closure

Anyway I’m opened for discussions about this, as I clearly haven’t made my mind. :slight_smile:

@Chukx_007, I told you something wrong a few posts ago… although the private nodetree is stored in the blend file, Blender itself doesn’t change the node by the nodetree. I’m still figuring the best way to do it, so for now one must change the nodes in all materials manually (maybe an option on saving?!) :frowning:

Another small update (0.1.6)

Some bugs fixed:
-the addon will now work correctly in Windows and Linux. Haven’t tried it in Mac but it’s supposed to work there also.
-fixed error on deactivating and unregistering nodes
-some minor fixes

Thanks to nudelZ, who spotted most of those errors.

I’ve included two nodes in the package, ‘Normal Bake’ and ‘Displacement Bake’. The first is based on my old ‘World to Tangent’ nodegroup, and the second on nudelZ’s ‘Displacement Bake’.
And new nodes will be there in the next days! :wink:

A editor for the add menu is on the way, only the interface is missing, but there are progresses.

1 Like

This sounds quite exciting, Secrop.

I’d like to run a scenario past you and see if this would (eventually) work with your node builder…

Let’s say I have four Image Texture nodes (albedo/diffuse, gloss/roughness, displacement, and reflection) in a group. After converting the group using your addon, will I then have the four Open Image widgets exposed in the new node? I don’t know if I’m explaining this well. If not, please let me know.

Not sure if I understand it…

Creating a new node, is basically the same as creating a nodegroup. The main difference is that you can add/change the node’s interface as you which. You can do stuff that nodes don’t do normally, like getting values from the scene or automatically change the node’s behaviour and look.

For example the nodes I’ve posted above, they have the same functionality as the nodegroups from which i based the code. But the coded nodes have an interface that you couldn’t do with nodegroups, like the XYZ flip and switch buttons. Also because it’s possible to edit the node’s functionality, it’s possible to make nodes a bit more ‘intelligent’. The node from nudelz is now super simplified because of this, instead of having all possible configurations for the FlipAndSwitch values from ZBrush as nodes, there’s only 1 setup that is changed on user interaction, and instead of the ~550 nodes nudelZ used, the scripted node has only 11 nodes!!!

Okay. I’ll just stop being lazy/frightened-of-new-things and mess around with it. :slight_smile:

if you need any assistance or on any doubt don’t hesitate to ask…

Oh my days!!! You just made this more awesome for me to integrate permanently into my workflow. wow am so loving the progress of this. A million thanks

I’ve updated some things to the addon, and created a smaller class to support new nodes (ShaderNodeBase.ShaderNodeCompact). I also corrected the addLink() and addLinks() functions, to accept objects as well as strings.

Because of that, the DisplacementBake and the NormalBake nodes are now much smaller, with all common functions placed in the ShaderNodeBase.py.

In addition, I created three new nodes:
Compare, Switch Float and Interpolate.


The ‘Compare’ node returns 0 for False, 1 for True, and has the following operations (the screenshot is not updated, the output is now of type Int):

  • Greater Than
  • Greater Than or Equal To
  • Equal To
  • Less Than
  • Less Than or Equal To
  • Not Equal To
  • Similar, by some threshold ammount

The ‘Switch’ node is just a simple switch. If the ‘switch’ value is 0, it returns the ‘value 1’, and if 1 it returns ‘value 2’.

The ‘Interpolate’ node interpolates between ‘value 1’ and ‘value 2’, and has the following types of interpolation functions:

  • Lerp or Linear
  • SmoothStep
  • SmootherStep
  • High Power - with an option for choosing the exponential power
  • Inverted High Power - with an option for choosing the exponential power
  • Sine
  • Inverted Sine
  • Cos
  • Catmull-Rom - with two control points for the spline curve (since the node is normalized, P0 and P4 are by default 0 and 1, respectively). Note that this function allows returned values outside the[‘value1’, ‘value2’] interval, and there are no clampings. So use it with precaution.

The three nodes can be found at ‘Add>Converter’.

PS: I haven’t tested these nodes extensively, so maybe there may be one bug or two.

Thanks, Secrop, but I think I misunderstood what this does. I thought it was a way to take a node group I’ve built and turn it into a node that would be available from the Add menu.