rombotools::freebie::mathparser

rombotools::freebie::mathparser

maxtarpini
Collaborator Collaborator
3,084 Views
15 Replies
Message 1 of 16

rombotools::freebie::mathparser

maxtarpini
Collaborator
Collaborator

this is a math expression parser.. ie. you can simply input a basic math expression and use a variable 'x' to source the connected input. This unleashes some tremendous power if you know what to do with math. So instead to have to use many math nodes you can use one to rule most of them.

Current operators : + - / * ^ %
Current functions : sin, cos, tan, floor, fract
Parentheses : ()

 

For example : floor(x*12)%2 , where x is the floating input node (U/V coord) and % is the modulo operator

 

https://www.rombo.tools/downloads/romboMathParser.zip

 

rombomathparser_app.png

3,085 Views
15 Replies
Replies (15)
Message 2 of 16

maxtarpini
Collaborator
Collaborator

Updated to three inputs and so three variables : x,y and z.

Added following ops : (bitwise) & | << >> 

Added following fncs : asin acos atan sinh cosh tanh exp floor ceil fract sqrt log log2 logn inv(ert) comp(lement) abs

Added : verbosity for incorrect expressions, MTD file for DCCs

 

Remarkably, this doesn't work : 3+(-2) .. meaning, I don't plan to fix it 🙂

From v1.5, you can write it like this however : 3+neg(2).

 

We can now re-do the previous example with just one romboMathParser.

Screenshot 2024-07-10 171810.png



Btw, you can have any number of nested parentheses ..
like with the following expression that will draw a diamond pattern. 

rombomathparser_tris.png

 

This simple expression instead will return the luminance of a color.
In Maya, romboMathParser is under Utility/Math.
No need for parentheses here because the order of operations is exploited.
Screenshot 2024-07-10 230840.png

Message 3 of 16

maxtarpini
Collaborator
Collaborator

Added following fncs : rnd(seed) .. generates random numbers in 0-1

Added support for two-arguments fncs : max, min, atanz (atan2), mod, pow, step

 

Now with two-args fncs we can do more interesting stuff easily.

rombomathparse_twoargsfnc.png


The 'sin' thing with magic numbers generates random numbers, the 'fract' ensures they are in 0-1.
Or try this exp 'fract(fract(p * 0.1031) * (p * 33.33))' which avoids 'sin'.
We could have used also just the 'rnd' fnc.

 

Below with both X and Y. ScreenSpaceX/Y is in Arnold math node : state_float->imagespaceU/V.
Thickness node is used to tweak how thick are the lines without touching the expression.

rombomathparse_twoargsfncs.png


This last example would involve at least 12 nodes and all the pain to keep track of that. Btw, romboMathParser doesn't need to compile anything and does not embed full-fledged scripting language like Python, Lua or OSL because does everything inline based on a simple and effective math parser algorithm.

 

Message 4 of 16

maxtarpini
Collaborator
Collaborator

Addded fncs :
- radtodeg -> converts radians to degrees
- degtorad -> converts degrees to radians
- union -> perlin boolean op -> ((a+b) - (a*b))
- diff -> perlin boolean op -> ((a) - (a*b))

Added 3-args fncs :
- clamp -> constrains x to lie between a and b ..(x,a,b)
- lerp -> interpolates linearly x between a and b .. (a,b,x)
- exerp -> exponential interpolation
- logerp -> logarithmic interpolation
- sstep -> smoothstep function .. (a,b,x)
- pulse -> step(edge0, x) - step(edge1, x);
- pulset -> pulse (edge, period, mod(x,period));

Added constants :
- PI -> π -> 3.1459...
- E -> euler -> 2.7182...
- GR -> goldenratio -> 1.6180...

Added globals :
all shading float/int globals are available.
Name convention is : SG(shading globals) + uppercase variable name, ie:
SGU -> float u .. U surface parameter
SGDUDX -> float dudx .. U derivative wrt screen X-axis
SGSC -> uint8_t sc .. type of shading context

 

Added : README file


Now, to test for example constants and new fncs .. we know that Pi is the ratio of a circle's circumference to its diameter .. so if you input radtodeg(PI) .. and assign the shader to a cube .. go to the Pixel tab of your Arnold IPR view .. and put the mouse cursor over the rendered cube .. you should see 180 under Lum (remember that what you see in the IPR is not what you source from the pixel which is linear raw.. so values are not altered).


With globals instead we can re-write the previous exps without having to leave mathParser .. for example following :
(floor(SGU*12-SGV*12) + floor(SGU*12+SGV*12)) %2
does the same as above .. where SGU and SGV are the previous state_float->U and state_float->V connected to x and y slots.


Eventually a bit more involved example where we design some antialised circles.

rombomathparser_circles.png

Message 5 of 16

maxtarpini
Collaborator
Collaborator

Re-engineered the parser to better cope with Arnold initialize and evaluate phases.

We now parse and tokenize the expression in the init/update phase. Still there we convert the math expression from infix to postfix notation (also known as Reverse Polish Notation or RPN). Eventually we use the RPN like 'compiled code' in the evaluate phase because together with the token to parse the expression we have associated a lambda function that will be called from the RPN with the dynamic content from Arnold (xyz user-defined variables and globals) because the funny part was to be able to support the dynamic stuff while tokenizing/converting the expression as static.

This makes romboMathParser x20 faster and at least on pair (generally faster) with any shader network (or OSL code) you'd want to use to accomplish the same thing while remaining easier faster and funnier to setup.

Please re-download the lib (v1.4) from the initial post.

Below I'm using an rnd fnc to displace the circles we modelled previously.

rombomathparser_displacedcircles.png

Message 6 of 16

maxtarpini
Collaborator
Collaborator

Here some kind of origami pattern to test all the stuff works together. 

rombomathparser_origami.png

You may want to write the same with atan in this way : mod((((atan((SGV-.5)/(SGU-.5)) / (PI*2)) +0.5) *16), 1).

🖖

0 Likes
Message 7 of 16

maxtarpini
Collaborator
Collaborator

.....

rombo_mathp.png

🖖

 

0 Likes
Message 8 of 16

maxtarpini
Collaborator
Collaborator

To collect use cases for the romboMathParser ..

I post here too the solution to : 

https://forums.autodesk.com/t5/arnold-general-rendering-forum/facing-ratio-linear-attribute/td-p/132...

See that post for more info.

 

How to linearize a cosine gradient with trig fncs :

fcklinearcosine.png

🖖

0 Likes
Message 9 of 16

maxtarpini
Collaborator
Collaborator

In the while we're refining rtoa v2.0 which features almost 50 new shaders (!) ..

we release for everyone a new spicy update to our mathparser. 


This is Math Parser v2.0. It features a completely re-written core.

We enhanced the two stages "compiler/interpreter" architecture :
it strictly separates the CPU-intensive parsing setup from the performance-critical rendering loop.

A new custom parser tokenizes the math expression and compiles it into a linear array of integer-based bytecode.
We also do constant folding now and other optimizations.
The shader kernel reads this pre-compiled bytecode.
A tiny Virtual Machine executes the instructions for lighting speed renderings.

 

It now supports vector (3D) operations natively (component-wise math),
meaning sin(x) works whether x is a single float or a 3D vector.


Standard math functions can produce NaNs (Not a Number) or 'infinite' values if fed the wrong data.
MathParser uses "safe" versions of potential problematic functions that gracefully handle edge cases
by returning 0.0 or by clamping input values :
>> division by zero: returns 0.0 instead of crashing.
>> invalid roots: sqrt(-x) returns 0.0.
>> logarithms: log(0), log(-x) are handled safely.
>> trigonometry: asin/acos inputs > 1 are clamped.
>> power: pow(-x, float) returns 0.0.
>> modulo: fmod(x, 0) returns 0.0.


// Added new fncs :
dot(a, b) : Dot product. Returns scalar.
cross(a, b) : Cross product. Returns vector perpendicular to a and b.
length(v) : Returns the magnitude of vector v.
distance(a, b) : Distance between points a and b.
normalize(v) : Returns direction vector (length 1.0).
reflect(I, N) : Reflects vector I against normal N.
refract(I, N, ior) : Calculates refraction vector based on Index of Refraction.
smin(a, b, k), smax(...) : Smooth Minimum/Maximum. Blends a and b with factor k.
rotate(vec, axis, angle) : Rotates vector vec around axis by angle (radians).
translate(vec, vec) : Translate a vector vec by another vec.
scale(vec, vec) : Scale a vector vec by another vec.
vec(a, b, c) : Create a vector with a, b, c components.

rnd(x) : High quality random number generator


// Vector accessors
.x, .y, .z


// Added 3D shading globals :
SGP : shading point in world-space
SGPO : shading point in object-space
SGRO : ray origin
SGRD : ray direction
SGN, SGNF, SGNG, SGNGF : shading normals
SGDPDU, SGDPDV : surface derivatives
SGDDDX, SGDDDY : ray direction derivatives
SGDNDX, SGDNDY : surface normal derivatives


// Added new Constants :
TWOPI : 6.283.. (pi*2)
PITWO : 1.570.. (pi/2)
INVPI : 0.318.. (1/pi)


// Expression'recipes' :

Sine Wave Distortion
>> x + sin(y * 10.0 + z) * 0.1
Inputs: X=UV, Y=UV, Z=Time.
Adds a sine wave ripple traveling along the Y axis to the coordinate X.

Organic Soft Union (SDF)
>> smin(length(x) - 1.0, length(y) - 0.5, 0.2)
Inputs: X=Pos A, Y=Pos B.
Smoothly blends two spheres (radii 1.0 and 0.5) with a softness factor of 0.2.

Fresnel Term
>> pow(1.0 - max(0.0, dot(x, y)), 5.0)
Inputs: X=Normal, Y=View Vector.
Calculates a standard Fresnel edge glow effect manually.

Rounded Square
>> step(length(max(abs(rotate(UV - 0.5, N, X.x)) - Y, 0)), Z.x)
Inputs: X.x=Rotation, Y.x,Y.y=X,Y dimensions, Z.x=Rounded angle.
Draws a rounded square.

Concentric Shape
>> mod(length(PO + sin(PO * 5) * 0.2) * x, 1)
Inputs: X=Repetitions.
Draws concentric shapes.

Squares/Circles Pattern
>> mod(sin(U * Y.z) + sin(V * (X.z+1)), 1.0)
Inputs: X=Repetitions.
Draws a nice alternated pattern.

Diamond Checkboard
>> (floor((PO.x+2.5)*x-PO.y*y) + floor(PO.x*x+PO.y*y)) %2
Inputs: X=Repetitions.
Draws a diamond checkboard.

Origami Pattern
>> mod((((atanz(UV.y-.5, UV.x-.5) / (PI*2)) +0.5) *x), 1)
Inputs: X=Repetitions.
Draws a kind of origami pattern.

Bar Code
>> step(x.x, fract(sin(floor(WIN.x)*12.9898)*43758.453))
Inputs: y=Thickness.
Draws a kind of origami pattern.

Smooth Circular Grid
>> 1.0 - sstep(0.0, 0.5, ( length(( ((PO+z)*y-floor((PO+z)*y)) * 2.0) - 1) - 0.9) / 0.5)
Inputs:y=Repetitions; z=Position,
Draws a kind of origami pattern.


rombo_mathparser_arnold,jpg.jpg

 

https://www.rombo.tools/downloads/romboMathParser.zip

0 Likes
Message 10 of 16

rachid_1
Advocate
Advocate

Thanks for the update, now Arnol-7.4.5.0 has Line shader !
by the way any news for rtoa v1.6?

0 Likes
Message 11 of 16

MartinBeh
Advisor
Advisor

Is there a way to make this work in 3ds Max/MaxToA?

Martin B   EESignature
→ please 'Like' posts that are helpful; if a post answers your question please click the "Accept Solution" button.
0 Likes
Message 12 of 16

maxtarpini
Collaborator
Collaborator

Drop the .dll in a path seen by arnold.
Or add an environment variable ARNOLD_PLUGIN_PATH and add there the folder path that contains the .dll.

🖖

Message 13 of 16

MartinBeh
Advisor
Advisor

Apologies, I am new to adding plugins to Arnold...

 

  • "Drop the .dll in a path..." - the .mtd is not needed?
  • "seen by Arnold" -- is the .dll made for a specific version of Arnold, or will it work for multiple versions?

 

Martin B   EESignature
→ please 'Like' posts that are helpful; if a post answers your question please click the "Accept Solution" button.
0 Likes
Message 14 of 16

maxtarpini
Collaborator
Collaborator

Yeah drop also the mtd file, it will put the shader into RTOA/Utilities.

Can't remember right now if latest 7.4.5.0 is compatible with other 7.4.x.x .. just try it 😉

Message 15 of 16

maxtarpini
Collaborator
Collaborator

An example on how to compose a vector by creating one from scalar inputs (U and V).

Uses also upcoming (rtoa v2.0) noise colorizer and noise alligator
(most 3D new noises are also 2D, ie. can be used with UVs).

 

rombonoisercolorizer_mathparser.jpg

🖖

 

0 Likes
Message 16 of 16

maxtarpini
Collaborator
Collaborator

Here we compute a 'Fresnel' factor on-the-fly with the mathparser to compose diffuse + reflect contributions.

It's the part multiplied over y (where reflectgeneralized is piped into) : pow(1 - dot(SGN, neg(SGRD)), 4).

 

As an exercise I leave here the Schlick (Fresnel) approximation that can also be easily implemented with mathparser :

float F = 0.04f + (1.0f - 0.04f) * powf(1.0f - AiClamp(AiV3Dot(sg->Nf, -sg->Rd), 0.0f, 1.0f), 5.0f);

 

rombo_parallax_mathparser.jpg

This shows also an application for the upcoming (rtoa v2.0) Parallax shader (part of rtoa demo scenes).

🖖

0 Likes