Expressions¶
Many filters take a formula instead of a number. Select Faces by Expression asks for a condition, Compute Vertex Color by Expression for a formula per color channel, Compute Vertex Coordinates by Expression for a formula per axis. The formula is evaluated once for every element (vertex, face or edge), and the properties of that element are available to it as variables:
to get |
write |
|---|---|
the faces that look up |
|
a red that grows with height |
|
a surface rippled along X |
|
Expressions are evaluated by muParser, version 2.3.5 when this page was written. It is not pinned, so a build with a different version could differ. This page lists what is available on top of it, and what is not: the filter dialogs only say “Expression for red output in range [0, 255]”.
The examples, the function and operator table, and everything under What to expect are run by the test suite, which fails if they stop being true. The variable tables were written from the source and are not checked mechanically.
Which filters take expressions¶
Filter |
Python name |
Runs over |
Writes |
Only selected |
|---|---|---|---|---|
Select Vertices by Expression |
|
vertex |
vertex selection |
no |
Select Faces by Expression |
|
face |
face selection |
no |
Select Edges by Expression |
|
edge |
edge selection |
no |
Compute Vertex Coordinates by Expression |
|
vertex |
position |
yes |
Compute Vertex Normals by Expression |
|
vertex |
normal |
yes |
Compute Face Normals by Expression |
|
face |
normal |
yes |
Compute Vertex Color by Expression |
|
vertex |
color |
yes |
Compute Face Color by Expression |
|
face |
color |
yes |
Compute Edge Color by Expression |
|
edge |
color |
yes |
Compute Vertex Scalar by Expression |
|
vertex |
scalar |
yes |
Compute Face Scalar by Expression |
|
face |
scalar |
yes |
Compute Edge Scalar by Expression |
|
edge |
scalar |
yes |
Parametrize per Vertex by Expression |
|
vertex |
texture coordinates |
yes |
Parametrize per Wedge by Expression |
|
face |
per-wedge texture coordinates |
yes |
Define Custom Vertex Scalar Attribute |
|
vertex |
a named scalar attribute |
no |
Define Custom Face Scalar Attribute |
|
face |
a named scalar attribute |
no |
Define Custom Vertex Point Attribute |
|
vertex |
a named 3D point attribute |
no |
Define Custom Face Point Attribute |
|
face |
a named 3D point attribute |
no |
Create Isosurface from Expression |
|
sample point |
a new mesh |
no |
Refine by User Expression |
|
edge |
new vertices and faces |
no |
Runs over is the kind of element the formulas are evaluated on, and so which variables they can read. Only selected says whether the filter has the Only selected … option (see Working on the selection).
Two of the fields are not what their labels suggest:
In Compute Vertex Color by Expression the red, green and blue formulas are labeled X, Y and Z Function (their Python names are
x,y,z); the fourth is the alpha. Compute Face Color and Compute Edge Color label them Red, Green and Blue.Compute Vertex Coordinates by Expression has an Alpha expression field that does nothing; it is ignored.
Writing an expression¶
Numbers are written 3, 0.5, .5 or 1e-3. Names are case-sensitive: Z is
not z.
Operators, from tightest to loosest: ^ (power), * /, + -, the comparisons
< > <= >= == !=, &&, ||, and the conditional condition ? a : b.
Parentheses group as usual. ^ binds tighter than a minus sign, so -2^2 is -4.
A comparison gives 1 or 0. In a selection filter any non-zero result selects the
element.
Functions¶
Angles are in radians.
trigonometry |
|
hyperbolic |
|
exponential |
|
sign and rounding |
|
several values |
|
random |
|
Two constants: _pi and _e.
These do not exist, though most expression languages have them. Each is refused with
Unexpected token "…":
not available |
use instead |
|---|---|
|
|
|
|
|
|
|
|
|
|
|
none |
|
|
rnd() and randInt() draw from a generator seeded by the filter’s Random seed
parameter. With the default 0 every run gives different values; any other number makes
the run exactly reproducible.
Variables¶
Each filter sees the variables of the element it runs over. All of them see the bounding box and the functions above.
Bounding box¶
The bounding box of the layer, taken before the filter runs and in the layer’s own coordinates (its transform is not applied):
xmin ymin zmin · xmax ymax zmax · xmid ymid zmid (the center) ·
xdim ydim zdim (the extents) · bbdiag (the diagonal length)
Vertex filters¶
variable |
meaning |
|---|---|
|
position, in the layer’s own coordinates |
|
normal |
|
color, each from 0 to 255 |
|
scalar |
|
index of the vertex |
|
texture coordinates; 0 if the layer has none |
|
texture index of those coordinates; 0 if none |
|
1 if the vertex is selected, else 0 |
Face filters¶
A face has its own properties and the properties of its three corners, which are numbered
0, 1 and 2. The corner variables read the corner vertices.
variable |
meaning |
|---|---|
|
corner positions |
|
corner normals |
|
corner colors |
|
corner scalars |
|
indices of the corner vertices |
|
1 if that corner is selected, else 0 |
|
the face’s own color; 255 if the layer has no face color |
|
the face’s own normal |
|
the face’s own scalar; 0 if the layer has none |
|
index of the face |
|
1 if the face is selected, else 0 |
|
texture coordinates of the three wedges; 0 if none |
|
texture index of the first wedge; 0 if none |
Edge filters¶
These run on the real edges of a polyline layer, not on the sides of triangles. An edge
has two endpoints, numbered 0 and 1, which are named as the first two corners of a
face. What it adds is its own properties and a few quantities derived from the endpoints.
variable |
meaning |
|---|---|
|
endpoint positions |
|
endpoint normals |
|
endpoint colors |
|
endpoint scalars |
|
indices of the endpoint vertices |
|
1 if that endpoint is selected, else 0 |
|
the edge’s own color |
|
the edge’s own scalar |
|
index of the edge |
|
1 if the edge is selected, else 0 |
|
length |
|
midpoint |
|
unit direction, from endpoint 0 to endpoint 1; zero for an empty edge |
The two filters that are different¶
Create Isosurface from Expression evaluates the formula at points of a grid. It sees only
x,y,z, and the surface is where the result is zero. It has no bounding box and no mesh to read.Refine by User Expression has two formulas that see different things. The edge predicate sees the endpoints’
x0 … z1,nx0 … nz1,r0 g0 b0andr1 g1 b1(no alpha), andq0 q1. The split-point formulas see onlyx0 y0 z0 x1 y1 z1. Neither sees the bounding box or custom attributes. The predicate is tried with the endpoints in both orders and the edge is refined if either is true, so a predicate likeq0 > q1matches every edge whose endpoints differ.
Custom attributes¶
Define Custom … Attribute stores the result of a formula on every element under a name, and later expression filters can then read it by that name.
A scalar attribute
heightis read asheight.A point attribute
diris read as three variables,dir_x,dir_y,dir_z.An integer attribute, such as an identifier or a label from a file, is also read by its name. No filter writes one.
A vertex attribute is seen by vertex filters and a face attribute by face filters, not across: a face filter that mentions a vertex attribute is refused with
Unexpected token. Edge filters see no custom attributes.
A name may use letters, digits and underscores and must not start with a digit. A name that
is already a variable (q, fi, zmid, …) is refused when you define the attribute.
An attribute that arrives some other way, from a file, with an unusable name is skipped
without a message.
Working on the selection¶
Filters marked yes under Only selected have a checkbox, Only selected vertices (or faces, or edges), with a live count. With it on, nothing outside the selection changes. It is on by default whenever something is selected, and a run with it on and nothing to work on is refused rather than silently doing nothing.
If you selected the other kind of element (vertices for a face filter, say), the filter works on the elements lying wholly inside that selection: the faces whose three corners are all selected. Your own selection is left exactly as it was.
For the scalar filters, Normalize and Map into Color then use the range of the selected elements alone.
Select … by Expression is the other direction: it sets the selection. It replaces the old one unless Preserve Existing Selection is on, which adds to it instead.
Independently of all that, the formulas can look at the selection themselves with vsel,
fsel, esel and the corner versions. With the checkbox off, fsel*255 as the green
channel marks the selected faces green and leaves the rest black.
Examples¶
In each, the filter is listed first and the formulas under its field labels.
Color the vertices by height, blue at the bottom to red at the top.
Compute Vertex Color by Expression: X 255*(z-zmin)/zdim, Y 0,
Z 255-255*(z-zmin)/zdim, Alpha 255.
Select the vertices above the middle. Select Vertices by Expression: z > zmid.
Select the faces that look up. Select Faces by Expression: fnz > 0.7.
Color the faces by their normal, the usual normal-map look. Compute Face Color by
Expression: Red 127.5*(fnx+1), Green 127.5*(fny+1), Blue 127.5*(fnz+1), Alpha 255.
Mark the selected faces green, with the checkbox off. Compute Face Color by
Expression: Red 0, Green fsel*255, Blue 0, Alpha 255.
Carry a measurement into a later step. Define Custom Vertex Scalar Attribute: name
height, formula z-zmin. Then Compute Vertex Color by Expression: X 255*height/zdim,
Y 0, Z 0, Alpha 255.
Ripple a surface. Compute Vertex Coordinates by Expression: X x, Y y,
Z z+0.1*sin(10*x).
Refine only the upper half. Refine by User Expression: edge predicate
z0 > 0 && z1 > 0, split point (x0+x1)/2, (y0+y1)/2, (z0+z1)/2.
Color a polyline by direction. Compute Edge Color by Expression: Red 255*abs(edx),
Green 255*abs(edy), Blue 255*abs(edz), Alpha 255.
What to expect¶
Colors are rounded to the nearest whole number and limited to 0–255:
300gives 255,-5gives 0,127.5gives 128. A result that is not a number, such assqrt(-1), gives 0 rather than stopping the filter.Normals are stored as the formulas give them, not scaled to unit length.
Scalars are stored exactly as computed; a not-a-number result is stored as it is.
A bad expression is refused before anything is changed, with a message like
Unexpected token "floor" found at position 0.The message does not say which field it came from, and a name you misspelled is reported the same way as a function that does not exist.