On this page |
APEX Script is a code interface for conveniently building APEX graphs. It uses a Python-like syntax to generate a graph that represents the code logic.
You can write APEX Script code in the APEX Script SOP, which generates a graph when it is run. The APEX Script SOP can also take in inputs, execute the code snippet, and output the results.
The APEX Autorig Component and APEX Rigscript Component SOPs also provide an interface for writing APEX Script snippets.
Simple APEX Script example ¶
In APEX Script, BindInput() is a special function that defines the inputs to a graph. It creates a parms
node with ports that represent the graph inputs. The BindOutput() function defines the graph outputs, and creates an output
node with ports that represent the values that are output from the graph.
The below APEX Script snippet takes a value as an input, and outputs the same value. The snippet can be put in the APEX Script SOP, Snippet parameter:
a = BindInput(3.5) BindOutput(a)
To see the APEX Script snippet represented as a graph:
-
Open up the APEX network view. At the top of the pane where you want to open the APEX network view, click the New Tab icon and select New Pane Tab Type ▸ Animation ▸ APEX Network View.
-
On the APEX Script SOP, in the Visualizer section, set Show to Component Script.
To view the graph input value:
-
In the geometry spreadsheet, beside the node name, select Apex Script Graph from the drop-down menu.
or
Connect the 2nd output (APEX Script Graph output) of the APEX Script SOP to a Null SOP, and select the Null SOP.
-
In the geometry spreadsheet, click Detail on the top toolbar. The input parameters are stored in the
parms
detail attribute on the graph.
If you click on the Reload Setup Parms button in the APEX Script SOP, the graph inputs appear in the parameter editor as parameters that you can adjust.
To view the graph output value:
-
On the APEX Script SOP, Invocation section, click beside Output Dictionary Bindings.
-
Apex Outputs Group is the name of the output node in the graph. In our case, it is
output
. -
The output is stored in a dictionary format. Set the dictionary name in Output Attrib.
-
-
In the geometry spreadsheet, beside the node name, select Invoked from the drop-down menu.
-
Click Detail on the top toolbar.
Syntax ¶
The APEX Script syntax borrows heavily from Python with a main difference being that variable types in APEX Script are statically typed, that is, once a variable is defined to be of a particular type, the variable type cannot be changed.
Indentation indicates a block of code. If you don’t indent the line after a for or if statement, or if you indent a line outside a for or if block, APEX Script will raise an error.
Commented lines begin with a #
. Any text that follows a #
is commented out. To comment a block of code in the APEX Script SOP, select the block of code in the Snippet parameter and press ⌃ Ctrl + /.
Variables ¶
Variables are containers for storing data values, and are created when you assign a value to it. Variable names can consist of uppercase and lowercase letters, digits, and underscores (_
), but cannot start with a digit. Variable names are case-sensitive.
# Create a Value<Float> node and initialize it to 1.5 f = 1.5
Data types ¶
Variables can store different types of data. The data types that are available in APEX Script are listed in the Null node doc, and can be initialized using <type>()
, for example, Float()
, String()
, and Dict()
.
# Create a float with a default value of 0 f1 = Float() # Create a float and initialize it to 1.5 f2 = Float(1.5) # Create a graph handle object g = ApexGraphHandle()
If the type of a variable is not explicitly specified, it is inferred by the value that is first assigned to it.
# x is a float x = 1.5
Once a variable is initialized with a particular type, its type cannot be changed.
x = 3 # Trying to change type raises an error x = 'string'
Certain data types can be converted to other types. See Convert for information on which types can be converted other types:
# Float a = 1.5 # Convert float to int b = Int(a) # Convert int to bool c = Bool(b)
Annotation ¶
Python-style annotation can be used to indicate that a variable or function argument is of a specific type. Annotation is important for defining dictionaries, function arguments, and specifying graph input types. Annotations have the following syntax:
<argument>: <annotation>
An annotated variable is uninitialized until it has been explicitly initialized, therefore an annotated variable cannot be used until it has been initialized:
# Uninitialized variable a: Float # Initialize another variable b = Float(1) # Error because 'a' is not initialized b = a + b
Annotating and initializing a variable:
# Annotate and initialize variable a: Float = 1.5 # Initialize another variable b = Float(1) # This works b = a + b
Operators ¶
Operators are used to perform operations on values and variables.
Arithmetic operators ¶
Arithmetic operators are used to perform mathematical operations.
Operation |
Operator |
Example |
---|---|---|
Addition |
|
|
Subtraction |
|
|
Multiplication |
|
|
Division |
|
|
Exponentiation |
|
|
Assignment operators ¶
Assignment operators are used to assign values to variables.
Operation |
Operator |
Example |
---|---|---|
Addition |
|
# x = x + 2 x += 2 |
Subtraction |
|
# x = x - 2 x -= 2 |
Multiplication |
|
# x = x * 2 x *= 2 |
Division |
|
# x = x / 2 x /= 2 |
Exponentiation |
|
# x = x ** 2 x **= 2 |
Comparison operators ¶
Comparison operators are used to compare two values. The result of a comparison operation is a boolean (True or False)
Operation |
Operator |
Example |
---|---|---|
Equal |
|
|
Equal using |
|
|
Not equal |
|
|
Not equal using |
|
|
Greater than |
|
|
Less than |
|
|
Greater than or equal to |
|
|
Less than or equal to |
|
|
Logical operators ¶
Logical operators are used to check if certain conditions are true.
Operation |
Operator |
Description |
Example |
---|---|---|---|
And |
|
Returns True if both conditions are true. |
|
Or |
|
Returns True if either condition is true. |
|
Not |
|
Returns True if the condition is not true. |
|
Membership operators ¶
Membership operators are used to check whether a value is in a string or array.
Operator |
Description |
Example |
---|---|---|
|
Returns True if the value is in the string or array. |
|
|
Returns True if the value is not in the string or array. |
|
Operator precedence ¶
The precedence of the different operators is listed below, starting with the highest precedence operator:
-
Parentheses
-
Exponentiation
-
Multiplication, division
-
Addition, subtraction
-
Comparison, membership
-
Logical NOT
-
Logical AND
-
Logical OR
Strings ¶
Strings can be specified with single or double quotes.
# Empty string s1 = '' # Create and initialize strings s2 = 'hello_world' s3 = String("hello_world")
Surround a string that spans multiple lines with triple quotes ('''
or """
).
multi_s = """This is the longest string in the world."""
Concatenate strings with a +
:
a = 'Hello' b = 'world' c = a + ' ' + b
The function len() returns the number of characters in a string:
s = 'hello world' # s_len = 11 s_len = len(s)
Python-style string formatting is supported in APEX Script. To perform string formatting, put an f
in front of the string, and use curly brackets {}
to specify the formatting to perform on the string. See string::Format for information on the formatting specification.
s = 'world' a = 1.2 b = 2.3 # s2 = "hello world +3.50" s2 = f"hello {s} {a+b:+.2f}"
See the string::* nodes for the string operations that are available in APEX Script.
Arrays ¶
Arrays are used to store multiple items of the same type in a single variable. Arrays are defined using square brackets []
. Elements in an array are indexed (the first element has index 0, the second element has index 1, etc.), and can be accessed by referencing its index number. Array elements can be any of the types listed as <type>Array
in the Null node doc.
See the array::* nodes for the array operations that are available in APEX Script.
Create and initialize arrays:
# Empty arrays a1 = IntArray() a2: IntArray = [] a3: IntArray = IntArray() # Initialize array with default values a4 = IntArray(1,2,3) f = 1.5 a5 = [f,f] # Array of strings s = 'hi' arr_of_str = [s,'bbb','ccc'] # Array of vectors v = (1,2,3) arr_of_vec = [v,v]
The function len() returns the number of items in an array:
a = [2,4,6] # a_len = 3 a_len = len(a)
Set and get array elements:
# Create array a = ['x','y','z'] # Set array elements a[0] = 'aaa' a[1] = apex.string.fromInteger(3) # Get array element elem = a[2]
A negative index gets the element starting from the end of the array:
# Create array a = ['x','y','z'] # neg = 'z' neg = a[-1]
Use expressions to specify array indices:
a = IntArray(1,2,3) x = 5 # a = [3,2,3] a[Int(0.5)] = a[Int(x-3)] # a = [0,2,3] a[Int(x-5)] = 0
Nested indices:
arr1 = [0,1,2] arr2 = [5,10,15] # arr_elem = 15 arr_elem = arr2[arr1[2]]
Working with dictionary arrays:
# Create array of dictionaries dict1 = {'test': 1.0, 'c': 5} dict2 = {'alpha': 'aaa', 'beta': 'bbb'} dictarray = [dict1, dict2] # Replace dictionary at first array element dictarray[0] = {'x': 'hello_world'}
Vectors ¶
Vectors store multiple items of the same type in a single variable, where the items in a vector are not indexed. In APEX Script, vectors can have a length of 2, 3, or 4. Vectors are defined using parentheses ()
, and the number of elements within the parentheses determine whether the vector is of type Vector2, Vector3, or Vector4.
Initialize vectors using Vector3 as an example:
# Create a zero vector v1 = Vector3() # Create a vector with all elements initialized to 5 v2 = Vector3(5) # Create and initialize vectors v3 = (1,2,3) v4 = Vector3(1,2,3) # Initialize a vector with variables a = Float(1) v5 = Vector3(a*1,a+1,3)
Matrices ¶
A matrix is essentially a 2-dimensional vector, where all the components in a matrix are of the same type. Matrices are defined using parentheses ()
, where the number of elements within the parentheses determine whether the matrix is of type Matrix3 (3×3 matrix with 9 elements) or Matrix4 (4×4 matrix with 16 elements).
Taking Matrix3 as an example, a matrix could also be seen as a collection of 3 Vector3's, or a “vector” with 9 components.
Initialize matrices using Matrix3 as an example:
# Create a zero matrix m1 = Matrix3() # Create a matrix with diagonal values set to 2 m2 = Matrix3(2) # Initialize matrices m3 = (1,2,3,4,5,6,7,8,9) m4 = Matrix3(1,2,3,4,5,6,7,8,9) m5 = Matrix3((1,2,3),(4,5,6),(7,8,9)) # Initialize matrices with variables v = (1,2,3) m6 = (v,(4,5,6),(7,8,9)) a = Float(1) m7 = (a,2,3,4,5,6,7,8,9) m8 = Matrix3(a+1,a+2,a+3,4,5,6,7,8,9)
Dictionaries ¶
Dictionaries are used to store data in key-value pairs. They are defined with curly brackets {}
that contain a list of <key>:<value>
entries. The key name must be a string type, and the value can be any type. Dictionaries cannot have different entries with the same key.
See the dict::* nodes for the dictionary operations that are available in APEX Script.
Create dictionaries (these dictionaries are used in subsequent examples):
# Empty dictionaries d1 = Dict() d2: Dict = {} d3: Dict = Dict() dict = { 'key1': 1.0, 'key2': 'hello_world' } # Nested dictionary dict_nested = { 'test1': 2, 'test2': [1,2,3], 'test3': { '3a': 1.5, 'say': 'hello_world' }, 'd_array': DictArray( {'a': 1} ) }
The function len() returns the number of entries in a dictionary:
d = { 'a': 1, 'b': 3.5, 'c': 'test' } # d_len = 3 d_len = len(d)
Dictionary entries are referenced by their key name within square brackets []
. To add items into a dictionary:
# Add constant to a dictionary dict['key3'] = 5.0 # Add to dictionary from a variable dict['key4'] = dict_nested # Add array element to a dictionary test_tags = ['tag1', 'tag2', 'tag3'] dict['tag'] = test_tags[0] # Add another dictionary to a dictionary dict['d_test'] = { 'x': 10, 'y': 20 } # Add entry into a nested dictionary dict_nested['test3']['x'] = 'testing' dict_nested['d_array'][0]['b'] = 2
Set a new value in an existing dictionary entry:
dict_nested['test3']['say']: String = 'hello_again'
Dictionary values can be any type, so type annotation must be used when initializing a variable from a dictionary entry:
s: String = dict['key2'] f: Float = dict_nested['test3']['3a']
Examples with annotation:
# Create a dictionary with 2 key-value pairs d1 = {'key1': Geometry(), 'key2': 1.2} # Create another dictionary d2 = {'a': 2.2} # Add entry to the 2nd dictionary d2['b']: Float = d1['key2']
Conditionals ¶
APEX Script supports conditionals with the use of the if
statement combined with the comparison, logical, or membership operators. The elif
(else if) and else
parts of the if statement are optional. The indented lines after the if statement is the block of code that is executed within the conditional.
The syntax for the if statement is:
if <if_condition>: <statement1> elif <else_if_condition>: <statement2> else: <statement3>
-
<statement1>
is executed if<if_condition>
is true. -
<statement2>
is executed if<if_condition>
is false and<else_if_condition>
is true. -
<statement3>
is executed if<if_condition>
and<else_if_condition>
are both false.
If statement with the comparison operators:
x = 0 if x < 0: test = 'aaa' elif x > 0: test = 'eee' else: test = 'ccc'
If statement with the membership operator:
test_tags = ['aaa', 'bbb', 'ccc'] test = 'ccc' # Check if array contains an item if test in test_tags: test_tags.append('repeated_tag')
If statement checks if a dictionary entry exists:
d = {'a': 3} if d['a']: x = 1
If statement with the length function, len():
s = 'hello' if len(s): x = 1
Nested if statement:
x = 10 if x >= 0: a = 'non-negative' if x > 0: b = 'positive'
Loops ¶
APEX Script supports the use of for
loops to iterate over the elements of an array or a range of ints. The indented lines after the for statement is the block of code that is executed.
The syntax for the for loop is:
for <element> in [<array>]:
h = 'hello' for x in ['world', 'again']: h = h + ' ' + x # Result after for loop: h = 'hello world again'
You can specify the for loop to iterate over the block of code a specific number of times using the range
keyword and the number of iterations inside parentheses ()
:
for <element> in range(<int>):
y = 0 for x in range(3): y = y + 1
To get access to the index while iterating over the elements of an array, use the enumerate
keyword:
for <index>, <element> in enumerate(<array>)
test_tags = ['aaa', 'bbb', 'ccc'] for t, test in enumerate(test_tags): test = (test + String(t)) # Result for the different iterations: aaa0, bbb1, ccc2
Nested for loop:
h = 'hello' i: Int = 0 for x in range(3): for x in ['world', 'again']: h = h + ' ' + x i = i + 1 i = i + 10
Loop over geometry points and primitives:
-
for <point_number> in geo.points()
-
for <primitive_number> in geo.prims()
geo = BindInput(Geometry()) transform = Matrix4() for pt in geo.points(): geo.transform(transform) for prim in geo.prims(): geo.setPrimAttribValue(prim, 'name', 'test', valuetype=String)
Note
geo::SetPrimAttribValue<T> is an example of a templated function. See templated functions for information on how to specify these special types of functions.
How-to ¶
To... | Do this |
---|---|
Make code changes take effect |
After making changes to the code snippet in the APEX Script SOP, press ⌃ Ctrl + Enter. |
View the graph nodes that are associated with the APEX Script line number |
|
Lay out the nodes in a graph |
Add |
Convert a graph to APEX Script code |
|
Comment or uncomment a block of code |
Select a block of code and press ⌃ Ctrl + /. |
Change the code snippet font size |
Click inside the Snippet parameter and press ⌃ Ctrl + + or ⌃ Ctrl + -. |