6
$\begingroup$

I have created a material with several math nodes, and I think it would be much easier if I could just write my own function in Python which would take some values and produce the output I want.

Is there a way to do that? I checked the script node, but it looks like it's more to define custom shaders only...

$\endgroup$
6
$\begingroup$

No

Unfortunately there's currently no Eval / Custom math node for Cycles as described in the question. Unless it's an OSL definition it has to be pre-compiled. Look through the OSL examples, you might find that it is capable of doing at least some of what you want.

See the specs: https://github.com/imageworks/OpenShadingLanguage/blob/master/src/doc/osl-languagespec.pdf

And suggested reading: Understanding the Cycles 'Script' node

But..

Node trees can be scripted and groups can too. I imagine it is possible, with sufficient willpower, to write a script or addon that translates a (Python like) expression with variables into a node-group with inputs and outputs. Perhaps something like:

# {materialname: material.001, groupname: NodeGroup}
sockets = {inputs: [var1, var2, var3], outputs: [var4]}
theta = var1 / 300
gamma = sin(theta * var2)
var4 = gamma * var3

enter image description here

and to the outside world that would look like a single node.

enter image description here

To make a useful implementation is not a trivial thing, but it could move away from pure python syntax to a more domain specific syntax to provide more convenience for specifying the types of inputs and outputs (Vector, Color, numeric..).

$\endgroup$
  • $\begingroup$ That's an interesting idea, but it would require quite a lot of work... moreover, that would still not allow me to do things that are very easiliy accomplished in code, like a simple if/else statement. Thanks for your answer anyway. $\endgroup$ – Paolo Tedesco Sep 24 '15 at 10:33
  • $\begingroup$ agreed @PaoloTedesco I wish it was different, but that's where we're at at the moment. The Math node modes less than / greater than will output 1 if A > B or A < B respectively .. some form of logic is possible $\endgroup$ – zeffii Sep 24 '15 at 10:43
  • $\begingroup$ @PaoloTedesco Mix nodes can work as if/else statements. I have also figured out how to make an is equal to node group. $\endgroup$ – PGmath Sep 24 '15 at 12:58
4
$\begingroup$

Yes - this is possible using dynamically generated node groups similar to Cycles Materials Math node with more than two inputs, coupled with a python script to parse the entered expression. Since the expression is built up using standard Maths nodes it is effectively just as efficient as if you had built the nodes manually - but with the ease of being able to simply enter the expression and let Blender do the hard work.

This can be achieved by installing the Maths Expression add-on available here, developed originally for Recreating Mandelbulbs with math nodes - simply download the .ZIP file, open User Preferences, and in the Add-ons tab select 'Install Add-on from file...' and point it at the .ZIP. Enable the add-on (by enabling the checkbox) and Save User Settings to make it automatically enabled when loading Blender.

You should now have a new 'Custom Nodes' menu in the Add menu of the Node Editor and within that a new 'Dynamic Maths Expression' option. Selecting this will add a node similar to the following :

empty Maths Expression node

Entering an expression into the Expression field will automatically build the internal nodes to implement that expression, automatically addin Input and Output sockets as required.

For example, entering a+b+c will result in the following node and internal structure :

a+b+c node and internal structure

Similarly you can enter much more complicated expressions such as calculating the distance of an x, y, z vector as (x*x+y*y+z*z)**0.5 :

xyz vector distance

Note that you can implement multiple expressions simultaneously by entering each expression, separated by commas. You can also assign a name to each expression using the '=' operator. For example, entering the expression Distance=(x*x+y*y+z*z)**0.5,Maximum=max(x,max(y,z)),Average=(x+y+z)/3 will produce the following node providing all three results :

multiple named expressions

In the comments to @zeffii's answer it mentions being able to implement conditional statements. This can be achieve by making use of the values of True and False being 1 and 0 respectively - by multiplying a statement by a conditional we can effectively mask it where the conditional is False and only include it where it is True, summing the result of multiple utually exclusive conditions. For example, to implement the ternary statement x*3 if x<0 else x*5 we could simply write :

(x*3)*(x<0) + (x*5)*(x>=0)

Note that the first term will be zero if x>=0 while the second term will be zero when x<0.

The add-on successfully interprets all the main operators (+, -, *, /), power (**), comparators (<, <=, >, >=, ==), and functions sin(), cos(), tan(), asin(), acos(), atan(), atan2(), max(), min(), log(), round(), mod(), abs(), as well as brackets to override the natural precedence and '=' as a means of assigning a label to an output (rather than the default of 'Value').

Note that the generated node tree is available via the Group node - as for any other node group - with a name starting 'DynamicMathsExpression'. The 'internal' nodes can be copied and pasted outside the group so that they can be used independent of the add-on.

$\endgroup$

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.