VEX language reference

Details of VEX syntax, data types, and so on.

Contexts

VEX programs are written for a specific context. For example, a shader that controls the surface color of an object is written for the surface context. A shader that determines the illuminance from a light is written for the light context. A VEX program that creates or filters channel data is written for the chop context.

The context affects which functions, statements, and global variables are available.

See VEX contexts for an overview of the ways in which you can use VEX.

If you are writing for a shading context (surface, displacement, light, etc.), you should also read the shading context specific information.

Statements

VEX supports the usual statements familiar from C. It also supports shading-specific statements such as the illuminance and gather loops that are only available in certain contexts.

Built-in functions

VEX contains a large library of built-in functions. Some functions are only available in certain contexts.

See VEX functions.

User-defined functions

Functions are defined similarly to C: specify the return type, the function name, and parenthesized list of arguments, followed by the code block.

  • Each argument can be given a default value using =.

  • Arguments of the same type can be declared in a comma separated list without re-declaring the type. Other arguments must be separated by a semi-colon.

  • int test(int a, b; string c) {
        if (a > b) {
            printf(c);
        }
    }
    

Notes

  • User functions must be declared before they are referenced.

  • The functions are in-lined automatically by the compiler, so recursion will not work.

  • As in RenderMan Shading Language, parameters to user functions are always passed by reference, so modifications in a user function affect the variable the function was called with.

  • There is no limit on the number of user functions.

  • You can have more than one return statement in a function.

  • You can access global variables directly (unlike RenderMan Shading Language, you do not need to declare them with extern). However, we recommend you avoid accessing global variables, since this limits your function to only work in one context (where those globals exist). Instead, pass the global(s) to the function as parameters.

Main (context) function

A VEX program must contain one function whose return type is the name of the context. This is the main function of the program that is called by mantra. The compiler expects one context function per file.

This function should do the work (by calling out to built-in and/or user-defined functions) of calculating any required information and modifying global variables. You do not use the return statement to return a value from the context function. See the specific context pages for the global variables available in each context.

The arguments to the context function, if any, become the user interface for the program, for example the parameters of a shading node that references the VEX program.

If a geometry attribute exists with the same name as a parameter of the context function, the attribute overrides the parameter’s value. This lets you paint attributes onto geometry to control VEX code.

surface
noise_surf(vector clr = {1,1,1}; float frequency = 1;
           export vector nml = {0,0,0})
{
    Cf = clr * (float(noise(frequency * P)) + 0.5) * diffuse(normalize(N));
    nml = normalize(N)*0.5 + 0.5;
}
Note

Parameters to context functions are dealt with in a special way with VEX. It is possible to override a parameter’s value using a geometry attribute with the same name as the variable. Aside from this special case, parameters should be considered “const” within the scope of the shader. This means that it is illegal to modify a parameter value. The compiler will generate errors if this occurs.

User interface pragmas

The user interface generated from this program by Houdini will be minimal, basically just the variable name and a generic text field based on the datatype. For example, you might want to specify that frequency should be a slider with a certain range, and that clr should be treated as a color (giving it a color picker UI). You can do this with user interface compiler pragmas.

#pragma opname        noise_surf
#pragma oplabel        "Noisy Surface"

#pragma label    clr            "Color"
#pragma label    frequency    "Frequency"

#pragma hint    clr            color
#pragma range    frequency    0.1 10

surface noise_surf(vector clr = {1,1,1}; float frequency = 1;
           export vector nml = {0,0,0})
{
    Cf = clr * (float(noise(frequency * P)) + 0.5) * diffuse(normalize(N));
    nml = normalize(N)*0.5 + 0.5;
}

Operators

VEX has the standard C operators with C precedence, with the following differences.

Tip

Multiplication is defined between two vectors or points. The multiplication performs an element by element multiplication (rather than a dot or cross product; see cross and dot).

Note

Many operators are defined for non-scalar data types (i.e. a vector multiplied by a matrix will transform the vector by the matrix). See type resolutions .

Dot operator

You can use the dot operator (.) to reference individual components of a vector or vector4:

  • .x or .r to reference the first element.

  • .y or .g to reference the second element.

  • .z or .b to reference the third element.

  • .w or .a to reference the fourth element of a vector 4.

The dot operator is only defined for vector and vector4. The choice of the letters x,y,z/r,g,b is arbitrary; the same letters apply even if the vector doesn’t hold a point or color.

Note

There is currently no mechanism for extracting components from matrix types. However, it is possible to get some of the information by multiplying a vector by the matrix and extracting information from the vector. See the matrix functions.

Comparisons

The comparison operators (==, !=, <, <=, >, >=) are defined when the left hand of the operator is the same type as the right hand side, for string, float and integer types only. The operations result in integer types.

The logical (&&, ||, and !) and bitwise (& |, ^, and ~) operators are only defined for integers.

Precedence table

Operators higher in the table have higher precedence.

OrderOperatorAssociativityDescription
15()L to RFunction call, expression grouping, structure member.
13! Logical negation
~One’s complement
+Unary plus
-Unary minus
++Increment
--Decrement
(typename)Type cast
12*L to RMultiplication
/Division
%Modulus
11+L to RAddition
-Subtraction
10<L to RLess than
>Greater than
<=Less than or equal
>=Greater than or equal
9==L to REqual
!=Not equal
8&L to RBitwise AND
7^L to RBitwise exclusive OR
6|L to RBitwise OR
5&&L to RLogical AND
4||L to RLogical OR
3? :L to RTernary conditional
2=R to LAssign to variable
+=Add and assign
-=Subract and assign
*=Multiply and assign
/=Divide and assign
%=Take modulus and assign
&=Take bitwise AND and assign
|=Take bitwise OR and assign
^=Take bitwise exclusive OR and assign
1,L to RArgument separator

Data types

VEX supports a fixed set of data types and does not allow user data types to be defined. VEX does not have an array datatype.

Type Definition Example

int

Integer values 21, -3, 0×31

float

Floating point scalar values 21.3, -3.2, 1.0

vector

Three floating point values. These values can be used to

represent positions, directions, normals or colors (RGB or HSV)

{0,0,0}, {0.3,0.5,-0.5}

vector4

Four floating point values. These values can be used to

represent positions in homogeneous coordinates, or color with alpha (RGBA)

{0,0,0,1}, {0.3,0.5,-0.5,0.2}

array

A list of values. See arrays for more information.

{ 1, 2, 3, 4, 5, 6, 7, 8 }

matrix

Sixteen floating point values representing a 3D

transformation matrix.

{ {1,0,0,0}, {0,1,0,0}, {0,0,1,0}, {0,0,0,1} }

matrix3

Nine floating point values representing a 3D rotation

matrix or a 2D transformation matrix.

{ {1,0,0}, {0,1,0}, {0,0,1} }

string

A string of characters.

“hello world”

“Mandril.pic”

bsdf

A bidirectional scattering distribution function. See writing PBR shaders for information on BSDFs.

Type casting

Variable casting

This is similar to type casting in C++ or Java: you transform a value of one type into another (for example, an int into a float).

This is sometimes necessary, as when you have the following:

int a, b;
float c;
c = a / b;

In this example, the compiler will do integer division (see type resolution ). If you wanted to do floating point division instead, you need to explicitly cast a and b as floats:

int a, b;
float c;
c = (float)a / (float)b;

This generates additional instructions to perform the casts. This may be an issue in performance-sensitive sections of your code.

Function casting

VEX dispatches functions based not only on the types of the arguments (like C++ or Java), but also on the return type. To disambiguate calls to functions with the same argument types but different return types, you can cast the function.

For example, the noise function can take different parameter types, but can also return different types: noise can return either a float or vector.

In the code:

float n;
n = noise(noise(P));

…VEX could dispatch to either float noise(vector) or vector noise(vector).

To cast a function call, surround it with typename( ... ), as in:

n = noise( vector( noise(P) ) );

(While this looks like a function call, it does nothing but disambiguate the function call inside.)

Note

If you don’t explicitly cast the function call, VEX will print out a warning and then guess which function you wanted.

A good rule of thumb is to use function casting in preference to variable casting whenever possible to avoid performance hits.

Type resolutions

This table lists how Vex decides the type resulting from operator combinations.

Left side Operator Right side Result
matrix + matrix matrix
matrix3 + matrix3 matrix3
vector4 + vector4 vector4
vector + vector4 vector4
float + vector4 vector4
int + vector4 vector4
vector4 + vector vector
vector + vector vector
float + vector vector
int + vector vector
float + float float
int + float float
float + int int
int + int int
matrix * matrix matrix
matrix3 * matrix3 matrix3
matrix * vector4 vector4
vector4 * vector4 vector4
vector * vector4 vector4
float * vector4 vector4
int * vector4 vector4
matrix * vector vector
matrix3 * vector vector
vector4 * vector vector
vector * vector vector
float * vector vector
int * vector vector
float * float float
int * float float
float * int int
int * int int
float / vector4 vector4
int / vector4 vector4
float / vector vector
int / vector vector
float / float float
int / float float
float / int int
int / int int
float % vector4 vector4
float % vector vector
float % float float
int % int int
^ vector4 vector4
^ vector4 vector4
^ float float
^ int int

Comments

VEX uses C++ style comments:

  • One-line comments are preceded by //

  • Freeform comments begin with /* and end with */

Reserved Keywords

break, bsdf, char, color, continue, do, float, for, gather, hpoint, if, int, integer, matrix, normal, point, return, string, struct, typedef, union, vector, vector2, vector4, while