Note : Additional information can now be found on my blog athttps://baldingwizard.wixsite.com/blog/node-expressions. The site also includes a number of tutorials which demonstrate the use of this add-on.

The Node Expressions add-on provides a means to enter a mathematical expression which is automatically parsed to generate a node group built up of standard maths nodes (and so is GPU-friendly) to implement that expression. It is available within the Node Editor 'Add' menu as 'Maths Expression'.

On selecting the menu option you'll be presented with a popup window prompting you to enter your expression.

For example, entering the expression 'a + b' will result in a node with two inputs ('a' and 'b'), outputting a single value that is the mathematical sum of 'a' and 'b'. The expression will be contained within a new node group with the inputs and outputs named appropriately (in this case 'a' and 'b').

The name of the output of the group can be indicated by including the name in the expression as in 'SumOfValues = a + b'.

The following standard mathematical operations are implemented :

**Operation**

**Example**Additiona + bSubtractiona - bMultiplicationa * bDivisiona / bPowera ** bSinesin(x)Cosinecos(x)Tangenttan(x)Arcsineasin(x)Arccosineacos(x)Arctangentatan(x)Arctangent(2)atan2(x,y)Absoluteabs(x)Roundround(x)Maximummax(x,y)Minimummin(x,y)Modulomod(x,y)Mathematical Modulommod(x,y)Loglog(x,y)Greater Thanx > yLess Thanx < yGreater or Equalx >= yLess Than or Equalsx <= yEqualsx == yNotnot(a)Andand(a,b)Oror(a,b)Exclusive-Orxor(a,b)Clampclamp(a)Clipclip(a)Fractionfract(a)Floorfloor(a)Ceilingceil(a)

Additionally, you can work with Vectors and Textures using the following functions : Combine components Add Subtract Multiply Divide Dot Product Cross Product Normalize (split vector)

Combine componentscombine(x,y,z)Addvadd(v,w)Subtractvsub(v,w)Multiplyvmult(v,w)Dividevdiv(v,w)Dot Productvdot(v,w)Cross Productvcross(v,w)Normalizevnorm(v)(split vector)v[n]Texturesnoise(vector, scale)noise(vector, scale, detail)

noise(vector, scale, detail, distortion)

musgrave(vector, scale, ....)

musgrave.fbm(vector, scale, ....)

musgrave.mf(vector, scale, ....)

musgrave.rmf(vector, scale, ....)

musgrave.hmf(vector, scale, ....)

musgrave.ht(vector, scale, ....)

voronoi(vector, scale)

voronoi.cell(vector, scale)

Any of the above functions, operators and comparators can be combined into a single expression and standard operator precedence rules should be followed - ie, power takes precedence over multiplication and division, which take precedence over addition and subtraction. Comparators (ie, >, <, >=, <=, ==) take least precedence. The expression can also include brackets to indicate overriding the operator precedence.

The expression can be edited using the Edit button of the custom node created with the node group. The node group is compatible with GPU rendering (since it only uses 'standard' Maths nodes) and can be exported to use in a Blend file independently of the add-on.

The expression can be arbitrarily complicated and the group inputs and outputs will be automatically updated with the relevant inputs and outputs to the expression.

Note also that multiple expressions can be entered, separated by commas, so as to provide a group with multiple outputs - for example, `sum=a+b+c,distance=(a*a+b*b+c*c)**0.5,minimum=min(min(a,b),c),maximum=max(max(a,b),c)`

to create a group with inputs of a,b,c and outputs of sum,distance,minimum,maximum.

### Default Values

Default values can be set for any input variable by adding a suffix within '{}' braces following any one usage of that variable. For example, creating a node as `Sum=a{0.25}+b{0.5}+c{0.1}`

will create a group to add three input values (a, b, c), with default values (used when the input nodes of the group are not connected) of a=0.25, b=0.5, c=0.1.

### Vectors

Input Vectors can be split into their component parts by including the suffix - for example, `vector[x]`

wil extract the first element of the vector. Output variables can be defined as vector type by suffixing with `[]`

, and individual components can be combined into a vector using the `combine(...)`

function.

### 'Special' Variables

A number of 'special' variables can be used in expressions to represent common input values. These are as follows :

Texture Coordinates :

- Generated
`Input.Generated`

- Normal
`Input.Normal`

- UV
`Input.UV`

- Object
`Input.Object`

- Camera
`Input.Camera`

- Window
`Input.Window`

- Reflection
`Input.Reflection`

Geometry :

- Position
`Geom.Position`

- Normal
`Geom.Normal`

- True Normal
`Geom.TrueNormal`

- Tangent
`Geom.Tangent`

- Incoming
`Geom.Incoming`

- Parametric
`Geom.Parametric`

- Backfacing
`Geom.Backfacing`

- Pointiness
`Geom.Pointiness`

Object Info :

- Index
`Object.Index`

- Material Index
`Object.Material`

- Random
`Object.Random`

- Location
`Object.Location`

Particle Info :

- Index
`Particle.Index`

- Age
`Particle.Age`

- Lifetime
`Particle.Lifetime`

- Location
`Particle.Location`

- Size
`Particle.Size`

- Velocity
`Particle.Velocity`

- Angular Velocity
`Particle.AngularVelocity`

- Random
`Particle.Random`

### Some Examples

Here are some examples to get you started :

Grid : `(mod(x,0.1)/0.1>0.1)*(mod(y,0.1)/0.1>0.1)`

Grid(with variable Scale and Thickness) :

`_scale=1/Scale, mod(x,_scale)/_scale>Thickness)*(mod(y,_scale)/_scale>Thickness)`

Wave : `abs(x-(sin(y*10)/2.5+0.5))>0.1`

Combined waves : `abs(x-sin(y*freq1)*amp1-sin(y*freq2)*amp2-sin(y*freq3)*amp3)<0.05`

Fan : `mod(atan2(x-0.5,y-0.5)+3.141,0.5)/0.5`

Spiral : `mod((_angle+_distance*Curviness)/4,_invertedScale)/_invertedScale, _angle=(atan2(x,y)+3.141)/3.141/2, _distance=((x)**2+(y)**2)**0.5+z/Scale, _invertedScale=1/Scale`

Star : `_dist=(x**2+y**2)**0.5, _angle=atan2(y,x), _edge=sin(_angle*Points)/2+0.5, Output=_dist>_edge*(Outer-Inner)+Inner`

### Fish Scales

A much more complicated example produced by comparing distances to the points in a grid to produce overlapping circles or scales :

The right-most "DynamicMaths..." node converts the output of the Noise (which clusters around 0.5) to cover the full 0.0 to 1.0 range by multiplying by a large value and taking the modulo using the following expression :

`Value = max(0,mod(Noise*963.34,1)-Mask)`

The other "DynamicMaths..." node creates the scales using the following expression :

`CentreX=_x1*_hit1+_x2*_hit2+_x1*_hit3+_x2*_hit4, CentreY=_y1*_hit1+_y1*_hit2+_y2*_hit3+_y2*_hit4, _x1=x-mod(x,Size), _x2=_x1+Size, _y1=y-mod(y,Size), _y2=_y1+Size, _d1 = ((x-_x1)**2+(y-_y1)**2)**0.5, _d2 = ((x-_x2)**2+(y-_y1)**2)**0.5, _d3 = ((x-_x1)**2+(y-_y2)**2)**0.5, _d4 = ((x-_x2)**2+(y-_y2)**2)**0.5, _hit1 = _d1 < Radius, _hit2 = (1-_hit1) * (_d2 < Radius), _hit3 = (1-max(_hit1,_hit2)) * (_d3 < Radius), _hit4 = (1-max(_hit1,max(_hit2,_hit3))) * (_d4 < Radius), _hitNone = (1-max(_hit1,max(_hit2,max(_hit3,_hit4)))), _distToHit = _d1 * _hit1 + _d2 * _hit2 + _d3 *_hit3 + _d4*_hit4 + 99999*_hitNone, Value=abs(_distToHit-Radius)<Thickness`

The '_' before a variable indicates it's a hidden variable (so it's not present on the output). The expression calculates the location of the 4 closest points ([x1,y1], [x1,y2], [x2,y1], [x2,y2]) and calculates the distances to each (dist1, dist2, dist3, dist4), determines which one of these is uppermost ('hit' - hit1, hit2, hit3, hit4), and finally determines if the 'hit' was close to the edge of that 'scale'. This generates the following nodes within the node group (which I certainly wouldn't want to have put together manually) :

### Text Blocks

By setting the expression to 'TEXT:<textblock>' (where <textblock> is the name of an existing text block in the Text Editor) the expression can be sourced from the Text Editor. This allows for much easier editing of complicated expressions, split over multiple lines, and can include comments and additional line spacing. For example, the following text can be used to generate a basic Hexagon Shader :

# Hexagons

#Set X and Y scaling based on Aspect ratio (0.866 for undistorted hexagons (`sin(60 degrees)`)

_xpitch=Aspect/Scale

_ypitch=0.866/Scale

#Logic to control where we need to place the reference points

_firsthalf=mod(x,_xpitch)>_xpitch/2

_tophalf=mod(y,_ypitch)>_ypitch/2

_oddline=mod(y,_ypitch*2)>_ypitch

#Define the reference points - x1 is "main" reference, others positioned in relation to that

_x1=x-mod(x,_xpitch)+_oddline*((0-_xpitch/2*0)), _y1=y-mod(y,_ypitch)+_oddline*_ypitch

_x2=_x1+_xpitch, _y2=_y1

_x3=(_x1+_x2)/2, _y3=_y1-_ypitch

_x4=_x3, _y4=_y1+_ypitch

_x5=_x3-_xpitch+_xpitch*2*_firsthalf, _y5=_y3*not(_tophalf)+_y4*_tophalf

#Distance to each reference point

_d1 = ((x-_x1)**2+(y-_y1)**2)**0.5

_d2 = ((x-_x2)**2+(y-_y2)**2)**0.5

_d3 = ((x-_x3)**2+(y-_y3)**2)**0.5

_d4 = ((x-_x4)**2+(y-_y4)**2)**0.5

_d5 = ((x-_x5)**2+(y-_y5)**2)**0.5

#Distance to the closest point

_dist = min(_d1,_d2,_d3,_d4,_d5)

#Determine which of the reference point is the closest

_closest1 = (_dist == _d1)

_closest2 = not(_closest1)*(_dist == _d2)

_closest3 = not(or(_closest1,_closest2))*(_dist == _d3)

_closest4 = not(or(_closest1,_closest2,_closest3))*(_dist == _d4)

_closest5 = not(or(_closest1,_closest2,_closest3,_closest4))

#Determine the distance to the *next* closest

_nextdist = max(_closest1*min(_d2, _d3, _d4, _d5)

_closest2*min(_d1, _d3, _d4, _d5)

_closest3*min(_d1, _d2, _d4, _d5)

_closest4*min(_d1, _d2, _d3, _d5)

_closest5*min(_d1, _d2, _d3, _d4, _d5))

#Determine which of the points is the next closest

_nextclosest1 = (_d1 == _nextdist)*not(_closest1)

_nextclosest2 = (_d2 == _nextdist)*not(_closest2)*not(_nextclosest1)

_nextclosest3 = (_d3 == _nextdist)*not(_closest3)*not(or(_nextclosest1,_nextclosest2))

_nextclosest4 = (_d4 == _nextdist)*not(_closest4)*not(or(_nextclosest1,_nextclosest2,_nextclosest3))

_nextclosest5 = not(_closest5)*not(or(_nextclosest1,_nextclosest2,_nextclosest3,_nextclosest4))

#Calculate how close we are to the edge (the edge is halfway between the two distances)

Hexagon = 1-(_dist /((_nextdist + _dist)/2))

#DistanceFromCentre = _dist

#DistanceFromNextCentre = _nextdist

### Presets

When creating new expresions the add-on provides a number of 'Preset' expressions that can be selected from a list. The presets can be used as they are or can be used as the start point for your own expressions. Some presets include optional modes or extra functionality which can be adjusted before the preset is applied. In addition, presets can be used to automatically generate a text block so as to allow them to be easily viewed and edited as required.

The following presets are currently available :

**Preset**

**Description**BlendSmoothly blend between two input valuesFanGenerate a fan, radiating from the centreNormal DistribtionVary the output based on a 'normal' distributionGrid RepeatTranslate input coordinates to generate a repeating gridHexagonsGenerate hexagonal/honeycomb patternsMappingA 'Mapping' node with the transform adjustable via input nodesPolar CoordinatesConvert a vector into Angle and DirectionScalesGenerate overlapping scalesSpiral 2DA simple spiral in 2-dimensionsSpiral 3DA 3-dimensional spiral (can be used to generate a volumetric galaxy)StarA 2-dirmensional parameterised star/flowerWaveAn adjustable 1-dimensional sine wave with additional harmonics

New presets are generally added at each new version of the add-on - so this list is expected to grow over time. The presets are intended to provide examples of what is possible with the add-on as well as providing useful node groups that can be immediately included in your own projects.