PExpr#
PearExpression is a single line, math like, functional language.
It is, by design, easy to transpile to other languages like artic, like in the case of the Ignis rendering framework.
It has no support for control flow, like if or while, and statements in general.
For more complex shading networks multiple expressions can be chained with textures and function calls.
Some examples for the PExpr language:
sin(uv.x) * uv.xyxy + color(0.2, 0.4, 0.1, 0)
/* or */
fract(P.x) * perlin(N.yx)
A very similar language is SeExpr by Walt Disney Animation Studios. SeExpr is more complex and industry proven, however, more difficult to transpile to other languages. Nevertheless, both languages are easy to learn and to tinkle around.
An expression can be defined in many places where a number, vector or color can be given as a parameter to a light, texture, bsdf, medium, etc…
An example for a PExpr used inside a BSDF definition:
{
// ...
"bsdfs": [
// ...
{ "name":"NAME", "type":"diffuse", "reflectance":"some_tex.r * perlin(uv.yx * abs(sin(uv.x * 10 * Pi))) * some_other_tex(uv.yx)" }
// ...
]
// ...
}
A direct connection to a texture is just a simple use-case of a PExpr expression. Keep in mind that throughout the use of textures and expressions cycles are prohibited at all times.
Types#
PExpr is strongly typed. Only a single implicit cast from int to num is available.
All available types are:
boolBoolean with true and false states.intSigned integer.numFloating point number.vec2Two-dimensional vector.vec3Three-dimensional vector.vec4Four-dimensional vector. Is used also as a color.strString.
Vectorized types like vec2, vec3 and vec4 can be cast or extended to each other by the access/swizzle operation like:
vec3(1,2,3).zyxx /* Return type is vec4 (same as color) with values (3,2,1,1) */
Variables#
Some special variables given are available as vec2:
uvThe current texture coordinates.prim_coordsPrimitive specific coordinates if surface, else zero vector.
some as vec3:
uvwThe current texture coordinates given as triplet.VWorld ray direction facing from a surface or any other source outwards.RdSame asV.RoWorld ray origin.PWorld position if bsdf or medium, else zero vector.NpNormalized position if bsdf or medium, else zero vector.NWorld shading normal if bsdf, else zero vector.NgWorld geometry normal if bsdf, else zero vector.NxWorld shading tangent if bsdf, else zero vector.NyWorld shading bitangent if bsdf, else zero vector.
few as int:
entity_idContains the id of the current entity or-1if not on a surface.IxContains the current pixel x index or0if not available.IyContains the current pixel y index or0if not available.
and a few as bool:
frontsidetrue if normal and ray orientation is front facing. This will be alwaystrueif the point is not lying on a surface.
Predefined constants of type num are:
PiThe famous pi constant.EThe famous euler constant.EpsThe float epsilon defined by the system.NumMaxThe maximum number a float can represent by the system.NumMinThe minimum number a float can represent by the system.InfInfinity float constant.
All textures defined in the scene representation are also available as variables of type vec4.
These texture variables use the variable uv as their texture coordinate implicitly.
The above defined special variable and constant names have precedence over texture names and parameters as explained below.
Scene Parameters#
Defining scene-wide parameters inside the "parameters" section in the scene description allows the convenient usage of user input in the viewer and the cli. All defined parameters are available as variables inside a PExpr expression.
Parameters can be defined as follow:
{
// ...
"parameters": [
// ...
{ "name":"NAME1", "type":"number", "value":42 },
{ "name":"NAME2", "type":"vector", "value":[1,0,0] },
{ "name":"NAME3", "type":"color", "value":[1,0,1] }
// ...
]
// ...
}
Currently only the types number for num, vector for vec3 and color for vec4 are available. The given value can not be a PExpr!
Note
Defining color with alpha is currently not supported. Use an array of three numbers to define color.
The above defined parameters have precedence over texture names, but not the already defined special variables and constants in the previous section.
Property names starting with an _ are considered read-only and can not be changed within the viewer. You may have to press F4 to open up the property view in igview.
The command line options --Pi, --Pn, --Pv and --Pc allow setting the parameters to a different value at the start of the rendering. Using the command line parameters allow changing internal and read-only flagged parameters as well.
Functions#
abs(num) -> numabs(vec2) -> vec2abs(vec3) -> vec3abs(vec4) -> vec4abs(int) -> intacos(num) -> numacos(vec2) -> vec2acos(vec3) -> vec3acos(vec4) -> vec4angle(vec2, vec2) -> numangle(vec3, vec3) -> numangle(vec4, vec4) -> numasin(num) -> numasin(vec2) -> vec2asin(vec3) -> vec3asin(vec4) -> vec4atan(num) -> numatan(vec2) -> vec2atan(vec3) -> vec3atan(vec4) -> vec4atan2(num, num) -> numatan2(vec2, vec2) -> vec2atan2(vec3, vec3) -> vec3atan2(vec4, vec4) -> vec4avg(vec2) -> numavg(vec3) -> numavg(vec4) -> numblackbody(num) -> vec4bump(vec3, vec3, vec3, num, num, num) -> vec3cbrt(num) -> numcbrt(vec2) -> vec2cbrt(vec3) -> vec3cbrt(vec4) -> vec4ccellnoise(num) -> vec4ccellnoise(num, num) -> vec4ccellnoise(vec2) -> vec4ccellnoise(vec2, num) -> vec4ccellnoise(vec3) -> vec4ccellnoise(vec3, num) -> vec4ceil(num) -> numceil(vec2) -> vec2ceil(vec3) -> vec3ceil(vec4) -> vec4cellnoise(num) -> numcellnoise(num, num) -> numcellnoise(vec2) -> numcellnoise(vec2, num) -> numcellnoise(vec3) -> numcellnoise(vec3, num) -> numcfbm(vec2) -> vec4cfbm(vec2, num) -> vec4cfbm(vec2, num, int, num, num) -> vec4cfbm(vec3) -> vec4cfbm(vec3, num) -> vec4cfbm(vec3, num, int, num, num) -> vec4check_ray_flag(str) -> boolcheckerboard(vec2) -> intcheckerboard(vec3) -> intclamp(num, num, num) -> numclamp(vec2, vec2, vec2) -> vec2clamp(vec3, vec3, vec3) -> vec3clamp(vec4, vec4, vec4) -> vec4clamp(int, int, int) -> intcnoise(num) -> vec4cnoise(num, num) -> vec4cnoise(vec2) -> vec4cnoise(vec2, num) -> vec4cnoise(vec3) -> vec4cnoise(vec3, num) -> vec4color(num, num, num, num) -> vec4color(num, num, num) -> vec4color(num) -> vec4cos(num) -> numcos(vec2) -> vec2cos(vec3) -> vec3cos(vec4) -> vec4cperlin(vec2) -> vec4cperlin(vec2, num) -> vec4cpnoise(num) -> vec4cpnoise(num, num) -> vec4cpnoise(vec2) -> vec4cpnoise(vec2, num) -> vec4cpnoise(vec3) -> vec4cpnoise(vec3, num) -> vec4cross(vec3, vec3) -> vec3cvoronoi(num) -> vec4cvoronoi(num, num) -> vec4cvoronoi(num, num, num, str) -> vec4cvoronoi(vec2) -> vec4cvoronoi(vec2, num) -> vec4cvoronoi(vec2, num, num, str, str) -> vec4cvoronoi(vec2, num, num, str, str, num) -> vec4cvoronoi(vec3) -> vec4cvoronoi(vec3, num) -> vec4cvoronoi(vec3, num, num, str, str) -> vec4cvoronoi(vec3, num, num, str, str, num) -> vec4deg(num) -> numdeg(vec2) -> vec2deg(vec3) -> vec3deg(vec4) -> vec4dist(vec2, vec2) -> numdist(vec3, vec3) -> numdist(vec4, vec4) -> numdot(vec2, vec2) -> numdot(vec3, vec3) -> numdot(vec4, vec4) -> numensure_valid_reflection(vec3, vec3, vec3) -> vec3exp(num) -> numexp(vec2) -> vec2exp(vec3) -> vec3exp(vec4) -> vec4exp2(num) -> numexp2(vec2) -> vec2exp2(vec3) -> vec3exp2(vec4) -> vec4fbm(vec2) -> numfbm(vec2, num) -> numfbm(vec2, num, int, num, num) -> numfbm(vec3) -> numfbm(vec3, num) -> numfbm(vec3, num, int, num, num) -> numfloor(num) -> numfloor(vec2) -> vec2floor(vec3) -> vec3floor(vec4) -> vec4fmod(num, num) -> numfmod(vec2, vec2) -> vec2fmod(vec3, vec3) -> vec3fmod(vec4, vec4) -> vec4fract(num) -> numfract(vec2) -> vec2fract(vec3) -> vec3fract(vec4) -> vec4fresnel_conductor(num, num, num) -> numfresnel_dielectric(num, num) -> numgabor(vec2) -> numgabor(vec2, num) -> numgabor(vec2, num, int, num, num, num) -> numhash(num) -> numhsltorgb(vec4) -> vec4hsvtorgb(vec4) -> vec4int(num) -> intlength(vec2) -> numlength(vec3) -> numlength(vec4) -> numlog(num) -> numlog(vec2) -> vec2log(vec3) -> vec3log(vec4) -> vec4log10(num) -> numlog10(vec2) -> vec2log10(vec3) -> vec3log10(vec4) -> vec4log2(num) -> numlog2(vec2) -> vec2log2(vec3) -> vec3log2(vec4) -> vec4lookup(str, bool, num, vec2, ...) -> numluminance(vec4) -> nummax(num, num) -> nummax(vec2, vec2) -> vec2max(vec3, vec3) -> vec3max(vec4, vec4) -> vec4max(int, int) -> intmin(num, num) -> nummin(vec2, vec2) -> vec2min(vec3, vec3) -> vec3min(vec4, vec4) -> vec4min(int, int) -> intmix(num, num, num) -> nummix(vec2, vec2, num) -> vec2mix(vec3, vec3, num) -> vec3mix(vec4, vec4, num) -> vec4mix_burn(vec4, vec4, num) -> vec4mix_color(vec4, vec4, num) -> vec4mix_dodge(vec4, vec4, num) -> vec4mix_hue(vec4, vec4, num) -> vec4mix_linear(vec4, vec4, num) -> vec4mix_overlay(vec4, vec4, num) -> vec4mix_saturation(vec4, vec4, num) -> vec4mix_screen(vec4, vec4, num) -> vec4mix_soft(vec4, vec4, num) -> vec4mix_value(vec4, vec4, num) -> vec4noise(num) -> numnoise(num, num) -> numnoise(vec2) -> numnoise(vec2, num) -> numnoise(vec3) -> numnoise(vec3, num) -> numnorm(vec2) -> vec2norm(vec3) -> vec3norm(vec4) -> vec4num(int) -> numperlin(vec2) -> numperlin(vec2, num) -> numpingpong(num, num) -> numpingpong(vec2, vec2) -> vec2pingpong(vec3, vec3) -> vec3pingpong(vec4, vec4) -> vec4pnoise(num) -> numpnoise(num, num) -> numpnoise(vec2) -> numpnoise(vec2, num) -> numpnoise(vec3) -> numpnoise(vec3, num) -> numpow(num, num) -> numpow(vec2, vec2) -> vec2pow(vec3, vec3) -> vec3pow(vec4, vec4) -> vec4rad(num) -> numrad(vec2) -> vec2rad(vec3) -> vec3rad(vec4) -> vec4reflect(vec3, vec3) -> vec3rgbtohsl(vec4) -> vec4rgbtohsv(vec4) -> vec4rgbtoxyz(vec4) -> vec4rotate_axis(vec3, num, vec3) -> vec3rotate_euler(vec3, vec3) -> vec3rotate_euler_inverse(vec3, vec3) -> vec3round(num) -> numround(vec2) -> vec2round(vec3) -> vec3round(vec4) -> vec4select(bool, bool, bool) -> boolselect(bool, int, int) -> intselect(bool, num, num) -> numselect(bool, vec2, vec2) -> vec2select(bool, vec3, vec3) -> vec3select(bool, vec4, vec4) -> vec4select(bool, str, str) -> strsign(num) -> numsign(vec2) -> vec2sign(vec3) -> vec3sign(vec4) -> vec4sign(int) -> intsignbit(int) -> boolsignbit(num) -> boolsin(num) -> numsin(vec2) -> vec2sin(vec3) -> vec3sin(vec4) -> vec4smax(num, num, num) -> numsmax(vec2, vec2, vec2) -> vec2smax(vec3, vec3, vec3) -> vec3smax(vec4, vec4, vec4) -> vec4smin(num, num, num) -> numsmin(vec2, vec2, vec2) -> vec2smin(vec3, vec3, vec3) -> vec3smin(vec4, vec4, vec4) -> vec4smootherstep(num) -> numsmoothstep(num) -> numsnap(num, num) -> numsnap(vec2, vec2) -> vec2snap(vec3, vec3) -> vec3snap(vec4, vec4) -> vec4snoise(num) -> numsnoise(num, num) -> numsnoise(vec2) -> numsnoise(vec2, num) -> numsnoise(vec3) -> numsnoise(vec3, num) -> numsperlin(vec2) -> numsperlin(vec2, num) -> numsqrt(num) -> numsqrt(vec2) -> vec2sqrt(vec3) -> vec3sqrt(vec4) -> vec4sum(vec2) -> numsum(vec3) -> numsum(vec4) -> numtan(num) -> numtan(vec2) -> vec2tan(vec3) -> vec3tan(vec4) -> vec4transform_direction(vec3, str, str) -> vec3transform_normal(vec3, str, str) -> vec3transform_point(vec3, str, str) -> vec3trunc(num) -> numtrunc(vec2) -> vec2trunc(vec3) -> vec3trunc(vec4) -> vec4vec2(num, num) -> vec2vec2(num) -> vec2vec3(num, num, num) -> vec3vec3(num) -> vec3vec4(num, num, num, num) -> vec4vec4(num) -> vec4voronoi(num) -> numvoronoi(num, num) -> numvoronoi(num, num, num, str) -> numvoronoi(vec2) -> numvoronoi(vec2, num) -> numvoronoi(vec2, num, num, str, str) -> numvoronoi(vec2, num, num, str, str, num) -> numvoronoi(vec3) -> numvoronoi(vec3, num) -> numvoronoi(vec3, num, num, str, str) -> numvoronoi(vec3, num, num, str, str, num) -> numwrap(num, num, num) -> numwrap(vec2, vec2, vec2) -> vec2wrap(vec3, vec3, vec3) -> vec3wrap(vec4, vec4, vec4) -> vec4xyztorgb(vec4) -> vec4
All textures defined in the scene representation are also available as functions with signature TEXTURE(vec2) -> vec4, with TEXTURE being the texture name.
The above defined function names have precedence over texture names, if the signature matches.