Home Reference VEX 

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.

Order Operator Associativity Description
15 () L to R Function call, expression grouping, structure member.
13 ! Logical negation
~ One’s complement
+ Unary plus
- Unary minus
++ Increment
Decrement
(type_name) Type cast
12 * L to R Multiplication
/ Division
% Modulus
11 + L to R Addition
- Subtraction
10 &lt; L to R Less than
&gt; Greater than
<= Less than or equal
>= Greater than or equal
9 == L to R Equal
!= Not equal
8 & L to R Bitwise AND
7 ^ L to R Bitwise exclusive OR
6 | L to R Bitwise OR
5 && L to R Logical AND
4 || L to R Logical OR
3 ? : L to R Ternary conditional
2 = R to L Assign 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 R Argument 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}

matrix

Sixteen floating point values representing a 3D

transformation matrix.

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

matrix3

Nine floating point values representing a 3D rotation

matrix or a 2D transformation matrix.

{ {1,0,0,0}, {0,1,0,0}, {0,0,1,0}, {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