Attribute Data Types

The attribute data type is the most important part of the attribute. It describes the type of data the attribute references, and the type of generated interface the node writer will use to access that data.

Attribute data at its core consists of a short list of data types, called Base Data Types. These types encapsulate a single value, such as a float or integer.

Warning

Not all attribute types may be supported by the code generator. For a list of currently supported types use the command generate_node.py --help.

Note

The information here is for the default type definitions. You can override the type definitions using a configuration file whose format is show in Type Definition Overrides.

Important

When extracting bundle members in C++ you’ll be passing in a template type to get the value. That is not the type shown here, these are the types you’ll get as a return value. (e.g. pass in _OgnToken_ to get a return value of _NameToken_, or _float[]_ to get a return value of _ogn::array<float>_.)

Base Data Types

This table shows the conversion of the Type Name, which is how the attribute type appears in the .ogn file type value of the attribute, to the various data types of the other locations the attribute might be referenced.

Type Name

USD

C++

CUDA

Python

JSON | Description

bool

bool

bool

bool*

bool

bool

True/False

double

double

double

double*

float

float

Double precision floating point value

float

float

float

float*

float

float

32 bit floating point value

half

half

pxr::GfHalf

__half*

float

float

16 bit floating point value

int

int

int32_t

int*

int

integer

32 bit signed integer

int64

int64

int64_t

longlong*

int

integer

64 bit signed integer

path

string

ogn::string

ogn::string

str

string

Path to another node or attribute

string

string

ogn::string

ogn::string

str

string

Standard string

token

token

NameToken

NameToken*

str

string

Interned string with fast comparison and hashing

uchar

uchar

uchar_t

uchar_t*

int

integer

8 bit unsigned integer

uint

uint

uint32_t

uint32_t*

int

integer

32 bit unsigned integer

uint64

uint64

uint64_t

uint64_t*

int

integer

64 bit unsigned integer

Note

For C++ types on input attributes a const is prepended to the simple types.

In addition to the standard numbers for floating point values the special values inf, -inf, nan, and snan are accepted, meaning +Infinity, -Infinity, QuietNaN, and SignalingNan, respectively. They translate into the nearest representation of the value according to the type used. For example std::numeric_limits<double>::infinity() for a C++ double-valued infinity, and float(‘Inf’) for the same thing in Python.

Here are samples of base data type values in the various languages:

custom int inputs:myInt = 1
custom float inputs:myFloat = 1
// The value type a C++ node implementation uses to access the attribute's data
static bool compute(OgnMyNodeDatabase& db)
{
    int const& iValue = db.inputs.myInt();
    float const& fValue = db.inputs.myFloat();
}
// The value type a C++ node implementation uses to pass the attribute's data to CUDA code. Note the use of attribute
// type definitions to make the function declarations more consistent.
extern "C" void runCUDAcompute(inputs::myInt_t*, inputs::myFloat_t*);
static bool compute(OgnMyNodeDatabase& db)
{
    int const* iValue = db.inputs.myInt();
    float const* fValue = db.inputs.myFloat();
    runCUDAcompute( iValue, fValue );
}
extern "C" void runCUDAcompute(inputs::myInt_t* intValue, inputs::myFloat_t* fValue)
{
}
# The value used by the Python typing system to provide a hint about the expected data type
@property
def myInt(self) -> int:
    return attributeValues.myInt

@property
def myFloat(self) -> float:
    return attributeValues.myFloat
{
    "myNode" : {
        "description" : ["This is my node with one integer and one float input"],
        "version" : 1,
        "inputs" : {
            "myInt" : {
                "description" : ["This is an integer attribute"],
                "type" : "int",
                "default" : 0
            },
            "myFloat" : {
                "description" : ["This is a float attribute"],
                "type" : "float",
                "default" : 0.0
            }
        }
    }
}

Array Data Types

An array type is a list of another data type with indeterminate length, analogous to a std::vector in C++ or a list type in Python.

Any of the base data types can be made into array types by appending square brackets ([]) to the type name. For example an array of integers would have type int[] and an array of floats would have type float[].

The JSON schema type is “array” with the type of the array’s “items” being the base type, although in the file it will just look like [VALUE, VALUE, VALUE].

Python uses the _numpy_ library to return both tuple and array data types.

Type Name

USD

C++

CUDA

Python

JSON

Description

bool[]

bool[]

ogn::array<bool>

bool*,size_t

numpy.ndarray[numpy.bool]

bool[]

Array of True/False

double[]

double[]

ogn::array<double>

double*,size_t

numpy.ndarray[numpy.float64]

float[]

Array of double precision floating point values

float[]

float[]

ogn::array<float>

float*,size_t

numpy.ndarray[numpy.float64]

float[]

Array of 32 bit floating point values

half[]

half[]

ogn::array<pxr::GfHalf>

__half*,size_t

numpy.ndarray[numpy.float64]

float[]

Array of 16 bit floating point values

int[]

int[]

ogn::array<int32_t>

int*,size_t

numpy.ndarray[numpy.int32]

integer[]

Array of 32 bit signed integers

int64[]

int64[]

ogn::array<int64_t>

longlong*,size_t

numpy.ndarray[numpy.int32]

integer[]

Array of 64 bit signed integers

token[]

token[]

ogn::array<NameToken>

NameToken*,size_t

numpy.ndarray[numpy.str]

string[]

Array of interned strings

uchar[]

uchar[]

ogn::array<uchar_t>

uchar_t*,size_t

numpy.ndarray[numpy.int32]

integer[]

Array of 8 bit unsigned integers

uint[]

uint[]

ogn::array<uint32_t>

uint32_t*,size_t

numpy.ndarray[numpy.int32]

integer[]

Array of 16 bit unsigned integers

uint64[]

uint64[]

ogn::array<uint64_t>

uint64_t*,size_t

numpy.ndarray[numpy.int32]

integer[]

Array of 32 bit unsigned integers

Note

For C++ types on input attributes the array type is ogn::const_array.

Here are samples of array data type values in the various languages:

custom int[] inputs:myIntArray = [1, 2, 3]
custom float[] inputs:myFloatArray = [1.0, 2.0, 3.0]
static bool compute(OgnMyNodeDatabase& db)
{
    ogn::const_array const& iValue = db.inputs.myIntArray();
    auto const& fValue = db.inputs.myFloatArray();
}
extern "C" runCUDAcompute(inputs::myIntArray_t*, size_t, inputs::myFloatArray_t*, size_t);
static bool compute(OgnMyNodeDatabase& db)
{
    int const* iValue = db.inputs.myIntArray();
    auto iSize = db.inputs.myIntArray.size();

    auto const fValue = db.inputs.myFloatArray();
    auto fSize = db.inputs.myFloatArray.size();

    runCUDAcompute( iValue, iSize, fValue, fSize );
}
extern "C" void runCUDAcompute(inputs::myIntArray_t* iArray, size_t iSize, inputs::myFloat_t* fArray, size_t fSize)
{
    // In here it is true that the number of elements in iArray = iSize
}
import numpy as np
@property
def myIntArray(self) -> np.ndarray[np.int32]:
    return attributeValues.myIntArray

@property
def myFloatArray(self) -> np.ndarray[np.float16]:
    return attributeValues.myFloatArray
{
    "myNode" : {
        "description" : ["This is my node with one integer array and one float array input"],
        "version" : 1,
        "inputs" : {
            "myIntArray" : {
                "description" : ["This is an integer array attribute"],
                "type" : "int[]",
                "default" : [1, 2, 3]
            },
            "myFloatArray" : {
                "description" : ["This is a float array attribute"],
                "type" : "float[]",
                "default" : [1.0, 2.0, 3.0]
            }
        }
    }
}

Tuple Data Types

An tuple type is a list of another data type with fixed length, analogous to a std::array in C++ or a tuple type in Python. Not every type can be a tuple, and the tuple count is restricted to a small subset of those supported by USD. They are denoted with by appending square brackets containing the tuple count to the type name. For example a tuple of two integers would have type int[2] and a tuple of three floats would have type float[3].

Since tuple types are implemented in C++ as raw data there is no differentiation between the types returned by input versus output attributes, just a const clause.

Type Name

USD

C++

CUDA

Python

JSON

Description

double[2]

double2

pxr::GfVec2d

double2*

numpy.ndarray[numpy.float64](2,)

[float,float]

2-tuple of double precision floating point values

double[3]

double3

pxr::GfVec3d

double3*

numpy.ndarray[numpy.float64](3,)

[float,float,float]

3-tuple of double precision floating point values

double[4]

double4

pxr::GfVec4d

double4*

numpy.ndarray[numpy.float64](4,)

[float,float,float,float]

4-tuple of double precision floating point values

float[2]

float2

pxr::GfVec2f

float2*

numpy.ndarray[numpy.float](2,)

[float,float]

2-tuple of 32 bit floating point values

float[3]

float3

pxr::GfVec3f

float3*

numpy.ndarray[numpy.float](3,)

[float,float,float]

3-tuple of 32 bit floating point values

float[4]

float4

pxr::GfVec4f

float4*

numpy.ndarray[numpy.float](4,)

[float,float,float,float]

4-tuple of 32 bit floating point values

half[2]

half2

pxr::GfVec2h

__half2*

numpy.ndarray[numpy.float16](2,)

[float,float]

2-tuple of 16 bit floating point values

half[3]

half3

pxr::GfVec3h

__half3*

numpy.ndarray[numpy.float16](3,)

[float,float,float]

3-tuple of 16 bit floating point values

half[4]

half4

pxr::GfVec4h

__half4*

numpy.ndarray[numpy.float16](4,)

[float,float,float,float]

4-tuple of 16 bit floating point values

int[2]

int2

pxr::GfVec2i

int2*

numpy.ndarray[numpy.int32](2,)

[float,float]

2-tuple of 32 bit signed integer values

int[3]

int3

pxr::GfVec3i

int3*

numpy.ndarray[numpy.int32](3,)

[float,float,float]

4-tuple of 32 bit signed integer values

int[4]

int4

pxr::GfVec4i

int4*

numpy.ndarray[numpy.int32](4,)

[float,float,float,float]

4-tuple of 32 bit signed integer values

Note

Owing to this implementation of a wrapper around raw data all of these types can also be safely cast to other types that have an equivalent memory layout. For example:

MyFloat3& f3 = reinterpret_cast<MyFloat3&>(db.inputs.myFloat3Attribute());

Here’s an example of how the class, typedef, USD, and CUDA types relate:

GfVec3f const& fRaw = db.inputs.myFloat3();
ogn::float3 const& fOgn = reinterpret_cast<ogn::float3 const&>(fRaw);
carb::Float3 const& fCarb = reinterpret_cast<carb::Float3 const>(fOgn);
vectorOperation( fCarb.x, fCarb.y, fCarb.z );
callCUDAcode( fRaw );
extern "C" void callCUDAcode(float3 myFloat3) {...}

Here are samples of tuple data type values in the various languages:

custom int2 inputs:myIntTuple = (1, 2)
custom float3 inputs:myFloatTuple = (1.0, 2.0, 3.0)
static bool compute(OgnMyNodeDatabase& db)
{
    GfVec2i const& iValue = db.inputs.myIntTuple();
    GfVec3f const& fValue = db.inputs.myFloatTuple();
}
// Note how the signatures are not identical between the declaration here and the
// definition in the CUDA file. This is possible because the data types have identical
// memory layouts, in this case equivalent to int[2] and float[3].
extern "C" runCUDAcompute(pxr::GfVec2i* iTuple, pxr::GfVec3f* fTuple);
static bool compute(OgnMyNodeDatabase& db)
{
    runCUDAcompute( db.inputs.myIntTuple(), db.inputs.myFloatTuple() );
}
extern "C" void runCUDAcompute(float3* iTuple, float3* fTuple)
{
    // In here it is true that the number of elements in iArray = iSize
}
import numpy as np
@property
def myIntTuple(self) -> np.ndarray[nd.int]:
    return attributeValues.myIntTuple
@property
def myFloatTuple(self) -> np.ndarray[nd.float]:
    return attributeValues.myFloatTuple
{
    "myNode" : {
        "description" : ["This is my node with one integer tuple and one float tuple input"],
        "version" : 1,
        "inputs" : {
            "myIntTuple" : {
                "description" : ["This is an integer tuple attribute"],
                "type" : "int[2]",
                "default" : [1, 2]
            },
            "myFloatTuple" : {
                "description" : ["This is a float tuple attribute"],
                "type" : "float[3]",
                "default" : [1.0, 2.0, 3.0]
            }
        }
    }
}

Arrays of Tuple Data Types

Like base data types, there can also be arrays of tuples by appending ‘[]’ to the data type. For now the only ones supported are the above special types, supported natively in USD.

The type names will have the tuple specification followed by the array specification, e.g. float[3][] for an array of three-floats.

JSON makes no distinction between arrays and tuples so it will be a multi-dimensional list.

Both the Python and C++ tuple and array types nest for arrays of tuple types.

Type Name

USD

C++

CUDA

Python

JSON

Description

double[2][]

double2[]

ogn::array<pxr::GfVec2d>

double2**,size_t

numpy.ndarray[numpy.float64](N,2)

[float,float][]

Array of 2-tuples of double precision floating point values

double[3][]

double3[]

ogn::array<pxr::GfVec3d>

double3**,size_t

numpy.ndarray[numpy.float64](N,3)

[float,float,float][]

Array of 3-tuples of double precision floating point values

double[4][]

double4[]

ogn::array<pxr::GfVec4d>

double4**,size_t

numpy.ndarray[numpy.float64](N,4)

[float,float,float,float][]

Array of 4-tuples of double precision floating point values

float[2][]

float2[]

ogn::array<pxr::GfVec2f>

float2**,size_t

numpy.ndarray[numpy.float](N,2)

[float,float][]

Array of 2-tuples of 32 bit floating point values

float[3][]

float3[]

ogn::array<pxr::GfVec3f>

float3**,size_t

numpy.ndarray[numpy.float](N,3)

[float,float,float][]

Array of 3-tuples of 32 bit floating point values

float[4][]

float4[]

ogn::array<pxr::GfVec4f>

float4**,size_t

numpy.ndarray[numpy.float](N,4)

[float,float,float,float][]

Array of 4-tuples of 32 bit floating point values

half[2][]

half2[]

ogn::array<pxr::GfVec2h>

__half2**,size_t

numpy.ndarray[numpy.float16](N,2)

[float,float][]

Array of 2-tuples of 16 bit floating point values

half[3][]

half3[]

ogn::array<pxr::GfVec3h>

__half3**,size_t

numpy.ndarray[numpy.float16](N,3)

[float,float,float][]

Array of 3-tuples of 16 bit floating point values

half[4][]

half4[]

ogn::array<pxr::GfVec4h>

__half4**,size_t

numpy.ndarray[numpy.float16](N,4)

[float,float,float,float][]

Array of 4-tuples of 16 bit floating point values

int[2][]

int2[]

ogn::array<pxr::GfVec2i>

int2**,size_t

numpy.ndarray[numpy.int32](N,2)

[float,float][]

Array of 2-tuples of 32 bit signed integer values

int[3][]

int3[]

ogn::array<pxr::GfVec3i>

int3**,size_t

numpy.ndarray[numpy.int32](N,3)

[float,float,float][]

Array of 4-tuples of 32 bit signed integer values

int[4][]

int4[]

ogn::array<pxr::GfVec4i>

int4**,size_t

numpy.ndarray[numpy.int32](N,4)

[float,float,float,float][]

Array of 4-tuples of 32 bit signed integer values

Here are samples of arrays of tuple data type values in the various languages:

custom int2[] inputs:myIntTuple = [(1, 2), (3, 4), (5, 6)]
custom float3[] inputs:myFloatTuple = [(1.0, 2.0, 3.0)]
static bool compute(OgnMyNodeDatabase& db)
{
    ogn::const_array<GfVec2i> const& iValue = db.inputs.myIntTupleArray();
    ogn::const_array<GfVec3f> const& fValue = db.inputs.myFloatTupleArray();
    // or auto const& fValue = db.inputs.myFloatTupleArray();
}
extern "C" runCUDAcompute(inputs::myIntTupleArray_t* iTuple, size_t iSize,
                        inputs::myFloatTupleArray_t* fTuple, size_t fSize);
static bool compute(OgnMyNodeDatabase& db)
{
    runCUDAcompute( db.inputs.myIntTupleArray(), db.inputs.myIntTupleArray.size(),
                    db.inputs.myFloatTupleArray(), db.inputs.myFloatTupleArray.size() );
}
extern "C" void runCUDAcompute(float3** iTuple, size_t iSize, float3** fTuple, size_t fSize)
{
}
import numpy as np
@property
def myIntTupleArray(self) -> np.ndarray:
    return attributeValues.myIntTupleArray
@property
def myFloatTupleArray(self) -> np.ndarray:
    return attributeValues.myFloatTupleArray
{
    "myNode" : {
        "description" : ["This is my node with one integer tuple array and one float tuple array input"],
        "version" : 1,
        "inputs" : {
            "myIntTuple" : {
                "description" : ["This is an integer tuple array attribute"],
                "type" : "int[2][]",
                "default" : [1, 2], [3, 4], [5, 6]]
            },
            "myFloatTuple" : {
                "description" : ["This is a float tuple array attribute"],
                "type" : "float[3][]",
                "default" : []
            }
        }
    }
}

Attribute Types With Roles

Some attributes have specific interpretations that are useful for determining how to use them at runtime. These roles are encoded into the names for simplicity.

Note

The fundamental data in the attributes when an AttributeRole is set are unchanged. Adding the role just allows the interpretation of that data as a first class object of a non-trivial type. The “C++ Type” column in the table below shows how the underlying data is represented.

For simplicity of specification, the type of base data is encoded in the type name, e.g. colord for colors using double values and colorf for colors using float values.

Type Name

USD

C++

CUDA

Python

JSON

Description

colord[3]

color3d

GfVec3d

double3

numpy.ndarray[numpy.float64](3,)

[float,float,float]

Color value with 3 members of type double precision float

colorf[3]

color3f

GfVec3f

float3

numpy.ndarray[numpy.float32](3,)

[float,float,float]

Color value with 3 members of type 32 bit float

colorh[3]

color3h

GfVec3h

__half3

numpy.ndarray[numpy.float16](3,)

[float,float,float]

Color value with 3 members of type 16 bit float

colord[4]

color4d

GfVec4d

double4

numpy.ndarray[numpy.float64](4,)

[float,float,float,float]

Color value with 4 members of type double precision float

colorf[4]

color4f

GfVec4f

float4

numpy.ndarray[numpy.float32](4,)

[float,float,float,float]

Color value with 4 members of type 32 bit float

colorh[4]

color4h

GfVec4h

__half4

numpy.ndarray[numpy.float16](4,)

[float,float,float,float]

Color value with 4 members of type 16 bit float

execute

int64

int64_t

int64

int

integer

Execution state stored as a 64 bit integer

frame[4]

frame4d

GfMatrix4d

Matrix4d

numpy.ndarray[numpy.float64](4,4)

[[float,float,float,float],
[float,float,float,float],
[float,float,float,float],
[float,float,float,float]]

Coordinate frame with 16 members of type double precision float

matrixd[2]

matrix2d

GfMatrix2d

Matrix2d

numpy.ndarray[numpy.float64](2,2)

[[float,float],[float,float]]

Transform matrix with 4 members of type double precision float

matrixd[3]

matrix3d

GfMatrix3d

Matrix3d

numpy.ndarray[numpy.float64](3,3)

[[float,float,float],
[float,float,float],
[float,float,float]]

Transform matrix with 9 members of type double precision float

matrixd[4]

matrix4d

GfMatrix4d

Matrix4d

numpy.ndarray[numpy.float64](4,4)

[[float,float,float,float],
[float,float,float,float],
[float,float,float,float],
[float,float,float,float]]

Transform matrix with 16 members of type double precision float

normald[3]

normal3d

GfVec3d

double3

numpy.ndarray[numpy.float64](3,)

[float,float,float]

Normal vector with 3 members of type double precision float

normalf[3]

normal3f

GfVec3f

float3

numpy.ndarray[numpy.float32](3,)

[float,float,float]

Normal vector with 3 members of type 32 bit float

normalh[3]

normal3h

GfVec3h

__half3

numpy.ndarray[numpy.float16](3,)

[float,float,float]

Normal vector with 3 members of type 16 bit float

objectId

uint64

uint64_t

uint64

int

integer

Object identifier stored as a 64 bit unsigned integer

pointd[3]

pointd

GfVec3d

double3

numpy.ndarray[numpy.float64](3,)

[float,float,float]

Cartesian point value with 3 members of type double precision float

pointf[3]

pointf

GfVec3f

float3

numpy.ndarray[numpy.float32](3,)

[float,float,float]

Cartesian point value with 3 members of type 32 bit float

pointh[3]

pointh

GfVec3h

__half3

numpy.ndarray[numpy.float16](3,)

[float,float,float]

Cartesian point value with 3 members of type 16 bit float

quatd[4]

quatd

GfQuatd

double3

numpy.ndarray[numpy.float64](4,)

[float,float,float]

Quaternion with 4 members of type double precision float as IJKR

quatf[4]

quatf

GfQuatf

float3

numpy.ndarray[numpy.float32](4,)

[float,float,float]

Quaternion with 4 members of type 32 bit float as IJKR

quath[4]

quath

GfQuath

__half3

numpy.ndarray[numpy.float16](4,)

[float,float,float]

Quaternion with 4 members of type 16 bit float as IJKR

texcoordd[2]

texCoord2d

GfVec2d

double2

numpy.ndarray[numpy.float64](2,)

[float,float]

Texture coordinate with 2 members of type double precision float

texcoordf[2]

texCoord2f

GfVec2f

float2

numpy.ndarray[numpy.float32](2,)

[float,float]

Texture coordinate with 2 members of type 32 bit float

texcoordh[2]

texCoord2h

GfVec2h

__half2

numpy.ndarray[numpy.float16](2,)

[float,float]

Texture coordinate with 2 members of type 16 bit float

texcoordd[3]

texCoord3d

GfVec3d

double3

numpy.ndarray[numpy.float64](3,)

[float,float,float]

Texture coordinate with 3 members of type double precision float

texcoordf[3]

texCoord3f

GfVec3f

float3

numpy.ndarray[numpy.float32](3,)

[float,float,float]

Texture coordinate with 3 members of type 32 bit float

texcoordh[3]

texCoord3h

GfVec3h

__half3

numpy.ndarray[numpy.float16](3,)

[float,float,float]

Texture coordinate with 3 members of type 16 bit float

timecode

timecode

double

double

float

float

Double value representing a timecode

vectord[3]

vector3d

GfVec3d

double3

numpy.ndarray[numpy.float64](3,)

[float,float,float]

Vector with 3 members of type double precision float

vectorf[3]

vector3f

GfVec3f

float3

numpy.ndarray[numpy.float32](3,)

[float,float,float]

Vector with 3 members of type 32 bit float

vectorh[3]

vector3h

GfVec3h

__half3

numpy.ndarray[numpy.float16](3,)

[float,float,float]

Vector with 3 members of type 16 bit float

Python and JSON do not have special types for role-based attributes, although that may change for Python once its interface is fully defined.

The roles are all tuple types so the Python equivalents will all be of the form Tuple[TYPE, TYPE…], and JSON data will be of the form [TYPE, TYPE, TYPE]. The types corresponding to the Equivalent column base types are seen above in Base Data Types.

The color role will serve for our example types here:

custom color3d inputs:myColorRole = (1.0, 0.5, 1.0)
static bool compute(OgnMyNodeDatabase& db)
{
    GfVec3d const& colorValue = db.inputs.myColorRole();
    // or auto const& colorValue = db.inputs.myColorRole();
}
extern "C" runCUDAcompute(pxr::GfVec3d* color);
static bool compute(OgnMyNodeDatabase& db)
{
    runCUDAcompute( db.inputs.myColorRole() );
}
extern "C" void runCUDAcompute(double3* color)
{
}
import numpy as np
@property
def myColorRole(self) -> np.ndarray:
    return attributeValues.myColorRole
{
    "myNode" : {
        "description" : ["This is my node with one color role input"],
        "version" : 1,
        "inputs" : {
            "myColorRole" : {
                "description" : ["This is a color role attribute"],
                "type" : "colord[3]",
                "default" : [0.0, 0.5, 1.0]
            }
        }
    }
}

Arrays of Role-Based Data

Like base data types, there can also be arrays of role-based data by appending ‘[]’ to the data type.

The type names will have the tuple specification followed by the array specification, e.g. colord[3][] for an array of 3d colors.

JSON makes no distinction between arrays and tuples so it will be a multi-dimensional list.

Both the Python and C++ tuple and array types nest for arrays of tuple types.

Type Name

USD

C++

CUDA

Python

JSON

Description

colord[3][]

color3d[]

ogn::array<GfVec3d>

double3*,size_t

numpy.ndarray[numpy.float64](N,3,)

[float,float,float][]

Array of color values with 3 members of type double precision float

colorf[3][]

color3f[]

ogn::array<GfVec3f>

float3*,size_t

numpy.ndarray[numpy.float32](N,3,)

[float,float,float][]

Array of color values with 3 members of type 32 bit float

colorh[3][]

color3h[]

ogn::array<GfVec3h>

__half3*,size_t

numpy.ndarray[numpy.float16](N,3,)

[float,float,float][]

Array of color values with 3 members of type 16 bit float

colord[4][]

color4d[]

ogn::array<GfVec4d>

double4*,size_t

numpy.ndarray[numpy.float64](N,4,)

[float,float,float,float][]

Array of color values with 4 members of type double precision float

colorf[4][]

color4f[]

ogn::array<GfVec4f>

float4*,size_t

numpy.ndarray[numpy.float32](N,4,)

[float,float,float,float][]

Array of color values with 4 members of type 32 bit float

colorh[4][]

color4h[]

ogn::array<GfVec4h>

__half4*,size_t

numpy.ndarray[numpy.float16](N,4,)

[float,float,float,float][]

Array of color values with 4 members of type 16 bit float

frame[4][]

frame4d[]

ogn::array<GfMatrix4d>

Matrix4d*,size_t

numpy.ndarray[numpy.float64](N,4,4)

[[float,float,float,float],
[float,float,float,float],
[float,float,float,float],
[float,float,float,float]][]

Array of coordinate frames with 16 members of type double precision float

matrixd[2][]

matrix2d[]

ogn::array<GfMatrix2d>

Matrix2d*,size_t

numpy.ndarray[numpy.float64](N,2,2)

[[float,float],[float,float]]

Array of transform matrices with 4 members of type double precision float

matrixd[3][]

matrix3d[]

ogn::array<GfMatrix3d>

Matrix3d*,size_t

numpy.ndarray[numpy.float64](N,3,3)

[[float,float,float],
[float,float,float],
[float,float,float]][]

Array of transform matrices with 9 members of type double precision float

matrixd[4][]

matrix4d[]

ogn::array<GfMatrix4d>

Matrix4d*,size_t

numpy.ndarray[numpy.float64](N,4,4)

[[float,float,float,float],
[float,float,float,float],
[float,float,float,float],
[float,float,float,float]][]

Array of transform matrices with 16 members of type double precision float

normald[3][]

normal3d[]

ogn::array<GfVec3d>

double3*,size_t

numpy.ndarray[numpy.float64](N,3,)

[float,float,float][]

Array of normal vectors with 3 members of type double precision float

normalf[3][]

normal3f[]

ogn::array<GfVec3f>

float3*,size_t

numpy.ndarray[numpy.float32](N,3,)

[float,float,float][]

Array of normal vectors with 3 members of type 32 bit float

normalh[3][]

normal3h[]

ogn::array<GfVec3h>

__half3*,size_t

numpy.ndarray[numpy.float16](N,3,)

[float,float,float][]

Array of normal vectors with 3 members of type 16 bit float

objectId[]

uint64[]

ogn::array<uint64_t>

uint64*,size_t

numpy.ndarray[numpy.uint32](N,)

integer[]

Array of object identifiers stored as a 64 bit unsigned integer

pointd[3][]

pointd[]

ogn::array<GfVec3d>

double3*,size_t

numpy.ndarray[numpy.float64](N,3,)

[float,float,float][]

Array of cartesian point values with 3 members of type double precision float

pointf[3][]

pointf[]

ogn::array<GfVec3f>

float3*,size_t

numpy.ndarray[numpy.float32](N,3,)

[float,float,float][]

Array of cartesian point values with 3 members of type 32 bit float

pointh[3][]

pointh[]

ogn::array<GfVec3h>

__half3*,size_t

numpy.ndarray[numpy.float16](N,3,)

[float,float,float][]

Array of cartesian point values with 3 members of type 16 bit float

quatd[4][]

quatd[]

ogn::array<GfQuatd>

double3*,size_t

numpy.ndarray[numpy.float64](N,4,)

[float,float,float][]

Array of quaternions with 4 members of type double precision float as IJKR

quatf[4][]

quatf[]

ogn::array<GfQuatf>

float3*,size_t

numpy.ndarray[numpy.float32](N,4,)

[float,float,float][]

Array of quaternions with 4 members of type 32 bit float as IJKR

quath[4][]

quath[]

ogn::array<GfQuath>

__half3*,size_t

numpy.ndarray[numpy.float16](N,4,)

[float,float,float][]

Array of quaternions with 4 members of type 16 bit float as IJKR

texcoordd[2][]

texCoord2d[]

ogn::array<GfVec2d>

double2*,size_t

numpy.ndarray[numpy.float64](N,2,)

[float,float][]

Array of texture coordinates with 2 members of type double precision float

texcoordf[2][]

texCoord2f[]

ogn::array<GfVec2f>

float2*,size_t

numpy.ndarray[numpy.float32](N,2,)

[float,float][]

Array of texture coordinates with 2 members of type 32 bit float

texcoordh[2][]

texCoord2h[]

ogn::array<GfVec2h>

__half2*,size_t

numpy.ndarray[numpy.float16](N,2,)

[float,float][]

Array of texture coordinates with 2 members of type 16 bit float

texcoordd[3][]

texCoord3d[]

ogn::array<GfVec3d>

double3*,size_t

numpy.ndarray[numpy.float64](N,3,)

[float,float,float][]

Array of texture coordinates with 3 members of type double precision float

texcoordf[3][]

texCoord3f[]

ogn::array<GfVec3f>

float3*,size_t

numpy.ndarray[numpy.float32](N,3,)

[float,float,float][]

Array of texture coordinates with 3 members of type 32 bit float

texcoordh[3][]

texCoord3h[]

ogn::array<GfVec3h>

__half3*,size_t

numpy.ndarray[numpy.float16](N,3,)

[float,float,float][]

Array of texture coordinates with 3 members of type 16 bit float

timecode[]

timecode[]

ogn::array<double>

double*,size_t

numpy.ndarray[numpy.float64](N,3,)

float[]

Array of double values representing a timecode

vectord[3][]

vector3d[]

ogn::array<GfVec3d>

double3*,size_t

numpy.ndarray[numpy.float64](N,3,)

[float,float,float][]

Array of vectors with 3 members of type double precision float

vectorf[3][]

vector3f[]

ogn::array<GfVec3f>

float3*,size_t

numpy.ndarray[numpy.float32](N,3,)

[float,float,float][]

Array of vectors with 3 members of type 32 bit float

vectorh[3][]

vector3h[]

ogn::array<GfVec3h>

__half3*,size_t

numpy.ndarray[numpy.float16](N,3,)

[float,float,float][]

Array of vectors with 3 members of type 16 bit float

As above the color role will serve for our example types here:

custom color3d[] inputs:myColorRoles = [(1.0, 0.5, 1.0), (0.5, 1.0, 0.5)]
static bool compute(OgnMyNodeDatabase& db)
{
    ogn::array<GfVec3d> const& colorValues = db.inputs.myColorRoles();
    // or auto const& colorValues = db.inputs.myColorRoles();
}
extern "C" runCUDAcompute(pxr::GfVec3d** color, size_t arraySize);
static bool compute(OgnMyNodeDatabase& db)
{
    runCUDAcompute( db.inputs.myColorRoles(), db.inputs.myColorRoles.size() );
}
extern "C" void runCUDAcompute(double3** color, size_t arraySize)
{
}
import numpy as np
@property
def myColorRoles(self) -> np.ndarray:
    return attributeValues.myColorRoles
{
    "myNode" : {
        "description" : ["This is my node with one color role array input"],
        "version" : 1,
        "inputs" : {
            "myColorRoles" : {
                "description" : ["This is a color role array attribute"],
                "type" : "colord[3][]",
                "default" : [[0.0, 0.5, 1.0], [0.5, 1.0, 0.5]]
            }
        }
    }
}

Bundle Type Attributes

There is a special type of attribute whose type is bundle. This attribute represents a set of attributes whose contents can only be known at runtime. It can still be in a tuple, array, or both. In itself it has no data in Fabric. Its purpose is to be a container to a description of other attributes of any of the above types, or even other bundles.

custom rel inputs:inBundle (
    doc="""The input bundle is a relationship, which comes from another bundle attribute""")

custom rel "outputs_outBundle" (
    doc="""The output bundle is a relationship, which is consumed by another bundle attribute""")

custom rel "state_stateBundle" (
    doc="""The state bundle is a relationship. It is an internal state of the node and can not be connected.""")
static bool compute(OgnMyNodeDatabase& db)
{
    // The simplest method of breaking open a bundle is to get an attribute by name
    auto const& inBundle = db.inputs.inBundle();
    auto myFloat3Attribute = inBundle.attributeByName(db.stringToToken("myFloat3"));
    if (auto asFloat3Array = myFloat3Attribute.get<float[][3]>())
    {
        handleFloat3Array(asFloat3Array); // The data is of type float[][3]
    }

    // The bundle has iteration capabilities
    for (auto& bundledAttribute : inBundle)
    {
        // Use the type information to find the actual data type and then cast it
        if ((bundledAttribute.type().baseType == BaseDataType::eInt)
        &&  (bundledAttribute.type().componentCount == 1)
        &&  (bundledAttribute.type().arrayDepth == 0))
        {
            CARB_ASSERT( nullptr != bundledAttribute.get<int>() );
        }
    }
}
extern "C" runCUDAcompute(float3* value, size_t iSize);
static bool compute(OgnMyNodeDatabase& db)
{
    auto const& myBundle = db.inputs.myBundle();
    auto myFloat3Attribute = myBundle.attributeByName(db.stringToToken("myFloat3"));
    if (auto asFloat3Array = myFloat3Attribute.get<float[][3]>())
    {
        runCUDAcompute(asFloat3Array.data(), asFloat3Array.size());
    }
    return true;
}
extern "C" void runCUDAcompute(float3** value, size_t iSize)
{
}
from omni.graph.core.types import AttributeTypes, Bundle, BundledAttribute

@staticmethod
def compute(db) -> bool:
    attribute_count = db.myBundle.attribute_count()
    for bundled_attribute in db.myBundle.attributes():
        if bundled_attribute.type.base_type == AttributeTypes.INT:
            deal_with_integers(bundled_attribute.value)
    return True
{
    "myNode" : {
        "description" : ["This is my node with one bundled input"],
        "version" : 1,
        "inputs" : {
            "myBundle" : {
                "description" : ["This is input bundle attribute"],
                "type" : "bundle"
            }
        }
    }
}

See the tutorials on Tutorial 15 - Bundle Manipulation and Tutorial 16 - Bundle Data for more details on manipulating the bundle and its attributes.

It’s worth noting here that as a bundle does not represent actual data these attributes are not allowed to have a default value.

If a bundle attribute is defined to live on the GPU, either at all times or as a decision at runtime, this is equivalent to stating that any attributes that exist inside the bundle will be living on the GPU using the same criteria.

Relationship Type Attributes

A relationship type contains a pointer to a list of paths. This paths point to prims or properties on the stage.

In USD these types will always be represented by the rel type.

They currently do not support default values in json. Nor can they be included in Extended Attribute Types

Type Name

USD

C++

CUDA

Python

JSON

Description

target

rel

TargetPath*

TargetPath*,size_t

usdrt.Sdf.Path[]

N/A

Reference to another prim on the USD stage

custom rel inputs:rel (
    doc="""Targets relationship, which could come from a prim or another target attribute""")

custom rel output:rel (
    doc="""Relationship that returns a path or paths""")
static bool compute(OgnMyNodeDatabase& db)
{
    const TargetPath* paths = db.inputs.rel();
}
extern "C" runCUDAcompute(TargetPath*, size_t);
static bool compute(OgnMyNodeDatabase& db)
{
    const TargetPath* iPaths = db.inputs.rel();
    auto iSize = db.inputs.paths.size();

    runCUDAcompute( iPaths, iSize );
}
extern "C" void runCUDAcompute(TargetPath* iPaths, size_t iSize)
{
    // In here it is true that the number of elements in iArray = iSize
}
import usdrt
@property
def myRelationship(self):
    return attributeValues.rel
{
    "myNode" : {
        "description" : ["This is my node with one target input"],
        "version" : 1,
        "inputs" : {
            "myTarget" : {
                "description" : ["This is input target attribute"],
                "type" : "target"
            }
        }
    }
}

Extended Attribute Types

Some attribute types are only determined at runtime by the data they receive. These types include the “any” type, which is a single attribute that can be any of the above types, and the “union” type, which specifies a subset of the above types it can take on. (The astute will notice that “union” is a subset of “any”.)

Extended attribute types allow a single node to handle several different attribute-type configurations. For example a generic ‘Cos’ node may be able to compute the cosine of any decimal type.

custom token inputs:floatOrInt
custom token inputs:floatArrayOrIntArray
custom token inputs:anyType
static bool compute(OgnMyNodeDatabase& db)
{
    // Casting can be used to find the actual data type the attribute contains
    // Different types are cast in the same way as bundle attributes
    auto const& floatOrInt = db.inputs.floatOrInt();
    bool isFloat = (nullptr != floatOrInt.get<float>());
    bool isInt = (nullptr != floatOrInt.get<int>());

    auto const& floatOrIntArray = db.inputs.floatOrIntArray();
    bool isFloatArray = (nullptr != floatOrIntArray.get<float[]>());
    bool isIntArray = (nullptr != floatOrIntArray.get<int[]>());

    auto const& anyType = db.inputs.anyType();
    std::cout << "Any type is " << anyType.type() << std::endl;
    // Like bundle attributes, use the type information to find the actual data type and then cast it
    if ((anyType.type().baseType == BaseDataType::eInt)
    &&  (anyType.type().componentCount == 1)
    &&  (anyType.type().arrayDepth == 0))
    {
        CARB_ASSERT( nullptr != anyType.get<int>() );
    }
}
extern "C" runCUDAcomputeFloat(float* value, size_t iSize, float multiplier, float power);
extern "C" runCUDAcomputeInt(int* value, size_t iSize, int multiplier, int power);
static bool compute(OgnMyNodeDatabase& db)
{
    auto const& floatOrIntArray = db.inputs.floatOrIntArray();
    if (auto asFloatArray = floatOrIntArray.get<float[]>())
    {
        auto floatMultiplier db.inputs.floatOrInt().get<float>();
        auto floatPower db.inputs.anyType().get<float>();
        runCUDAcomputeFloat(asFloatArray.data(), asFloatArray.size(), floatMultiplier, floatPower);
    }
    else if (auto asIntArray = floatOrIntArray.get<int[]>())
    {
        auto floatMultiplier db.inputs.floatOrInt().get<float>();
        auto intPower db.inputs.anyType().get<int>();
        runCUDAcomputeInt(asIntArray.data(), asIntArray.size(), intMultiplier, intPower);
    }
}
extern "C" void runCUDAcomputeFloat(float** value, size_t iSize, float* multiplier, float* power)
{
    // ...CUDA implementation
}
extern "C" void runCUDAcomputeInt(int** value, size_t iSize, int* multiplier, int* power)
{
    // ...CUDA implementation
}
@property
def floatOrInt(self) -> int | float:
    return attributeValues.floatOrInt

@property
def floatOrIntArray(self) -> numpy.ndarray:
    return attributeValues.floatOrIntArray

@property
def anyType(self) -> any:
    return attributeValues.anyType
{
    "myNode" : {
        "description" : "This is my node with some extended inputs",
        "version" : 1,
        "inputs" : {
            "anyType" : {
                "description" : "This attribute accepts any type of data, determined at runtime",
                "type" : "any"
            },
            "floatOrInt": {
                "description": "This attribute accepts either float or int values",
                "type": ["float", "int"]
            },
            "floatOrIntArray": {
                "description": ["This attributes accepts an array of float or int values.",
                                "All values in the array must be of the same type, like a regular array attribute."],
                "type": ["float[]", "int[]"],
            },
        }
    }
}

Types permitted in Extended Attributes

There are a few specialized types that are not included by extended types, either as part of a union group, or by an any extended type. Bundle, target and execution types are explicitly excluded, and attributes defined by an extended type cannot be resolved, or connected to one of these types.

Extended Attribute Union Groups

As described above, union extended types are specified by providing a list of types in the OGN definition. These lists can become quite long if a node can handle a large subset of the possible types. For convenience there are special type names that can be used inside the JSON list to denote groups of types. For example:

{
    "myNode" : {
        "description" : "This is my node using union group types",
        "version" : 1,
        "inputs" : {
            "decimal" : {
                "description" : "This attribute accepts double, float and half",
                "type" : ["decimal_scalers"]
            }
        }
    }
}

List of Attribute Union Groups

Group Type Name

Type Members

integral_scalers

uchar, int, uint, uint64, int64, timecode

integral_tuples

int[2], int[3], int[4]

integral_array_elements

integral_scalers, integral_tuples

integral_arrays

arrays of integral_array_elements

integrals

integral_array_elements, integral_arrays

matrices

matrixd[3], matrixd[4], transform[4], frame[4]

decimal_scalers

double, float, half

decimal_tuples

double[2], double[3], double[4], float[2], float[3], float[4], half[2], half[3], half[4]

colord[3], colord[4], colorf[3], colorf[4], colorh[3], colorh[4]

normald[3], normalf[3], normalh[3]

pointd[3], pointf[3], pointh[3]

texcoordd[2], texcoordd[3], texcoordf[2], texcoordf[3], texcoordh[2], texcoordh[3]

quatd[4], quatf[4], quath[4]

vectord[3], vectorf[3], vectorh[3]

decimal_array_elements

decimal_scalers, decimal_tuples

decimal_arrays

arrays of decimal_array_elements

decimals

decimal_array_elements, decimal_arrays

numeric_scalers

integral_scalers, decimal_scalers

numeric_tuples

integral_tuples, decimal_tuples

numeric_array_elements

numeric_scalers, numeric_tuples, matrices

numeric_arrays

arrays of numeric_array_elements

numerics

numeric_array_elements, numeric_arrays

array_elements

numeric_array_elements, token

arrays

numeric_arrays, token[]

strings

path, string, token, token[]

Extended Attribute Resolution

Extended attributes are useful to improve the usability of nodes with different types. However the node author has an extra responsibility to resolve the extended type attributes when possible in order to resolve possible ambiguity in the graph. If graph connections are unresolved at execution, the node’s computation will be skipped.

There are various helpful Python APIs for type resolution, including omni.graph.core.resolve_base_coupled() and omni.graph.core.resolve_fully_coupled() which allow you to match unresolved inputs to resolved inputs.

@staticmethod
def on_connection_type_resolve(node) -> None:
    a_attr = node.get_attribute("inputs:a")
    result_attr = node.get_attribute("outputs:result")
    og.resolve_fully_coupled([a_attr, result_attr])

You can also define your own semantics for custom type resolution. The following node takes two decimals, a and b, and returns their product. If one input is at a lower “significance” than the other, the less significant will be “promoted” to prevent loss of precision. For example, if inputs are float and double, the output will be a double.

See omni.graph.core.Type for more information about creating custom types.

@staticmethod
def on_connection_type_resolve(node) -> None:
    a_type = node.get_attribute("inputs:a").get_resolved_type()
    b_type = node.get_attribute("inputs:b").get_resolved_type()
    product_attr = node.get_attribute("outputs:product")
    product_type = product_attr.get_resolved_type()
    # we can only infer the output given both inputs are resolved and they are the same.
    if (a_type.base_type != og.BaseDataType.UNKNOWN and b_type.base_type != og.BaseDataType.UNKNOWN
            and product_type.base_type == og.BaseDataType.UNKNOWN):
        if a_type.base_type == b_type.base_type:
            base_type = a_type.base_type
        else:
            decimals = [og.BaseDataType.HALF, og.BaseDataType.FLOAT, og.BaseDataType.DOUBLE]
            try:
                a_ix = decimals.index(a_type.base_type)
            except ValueError:
                a_ix = -1
            try:
                b_ix = decimals.index(b_type.base_type)
            except ValueError:
                b_ix = -1

            if a_ix >= 0 or b_ix >= 0:
                base_type = a_type.base_type if a_ix > b_ix else b_type.base_type
            else:
                base_type = og.BaseDataType.DOUBLE

        product_attr.set_resolved_type(og.Type(base_type, max(a_type.tuple_count, b_type.tuple_count),
            max(a_type.array_depth, b_type.array_depth)))

See Tutorial 19 - Extended Attribute Types for more examples on how to perform attribute resolution in C++ and Python.

Type Definition Overrides

The generated types provide a default implementation you can use out of the box. Sometimes you might have your own favorite library for type manipulation so you can provide a type definition configuration file that modifies the return types used by the generated code.

There are four ways you can implement type overrides.

  1. Use the typeDefinitions flag on the generate_node.py script to point to the file containing the configuration.

  2. Use the “typeDefinitions”: “ConfigurationFile.json” keyword in the .ogn file to point a single node to a configuration.

  3. Use the “typeDefintitions”: {TypeConfigurationDictionary} keyword in the .ogn file to implement simple targeted overrides in a single node.

  4. Add the name of the type definitions file to your premake5.lua file in get_ogn_project_information(“omni/test”, “ConfigurationFile.json”) to modify the types for every node in your extension.

The format used for the type definition information is the same for all methods. Here is a sample, with an embedded explanation on how it is formatted.

{
    "typeDefinitions": {
        "$description": [
            "This file contains the casting information that will tell the OGN code generator what kind of data",
            "types it should generate for all of the attribute types. Any that do not explicitly appear in this file",
            "will use the default USD types (e.g. float[3] or int[][2]). As with regular .ogn files the keywords",
            "starting with a '$' are ignored by the parser and can be used for adding explanatory comments, such as",
            "this one.",
            "",
            "This file provides the type cast configuration for using POD data types. Note that as this is no",
            "POD equivalent for special types, including the 'half' float, they are left as their defaults. So long",
            "as none of your nodes use them they will not bring in USD. Other types such as 'any', 'bundle', 'string',",
            "and 'token' have explicit OGN types."
        ],
        "c++": {
            "$description": [
                "This section contains cast information for C++ data types. These are the types returned by the",
                "database generated for nodes written in C++. Each entry consists of a key value corresponding to",
                "the attribute type as it appears in .ogn files, and a value pair consisting of the raw data type",
                "to which the attribute value should be cast and the include file required to define it. Though there",
                "may be considerable duplication of include file definitions only one will be emitted by the generated code.",
                "Every supported type must be present in this file, using an empty list as the implementation if there",
                "is no explicit definition for them in this library. In those cases the hardcoded defaults will be",
                "used. If supported types are missing a warning will be logged as it may indicate an oversight. One",
                "caveat is allowed - if an array type is not specified but the non-array base type is then it is",
                "assumed that the array type information is the same as the non-array type information. e.g. the",
                "information for bool[] is the same as for bool[]."
            ],
            "any": [],
            "bool": ["bool"],
            "bundle": [],
            "colord[3]": ["double[3]"],
            "colord[4]": ["double[4]"],
            "colorf[3]": ["float[3]"],
            "colorf[4]": ["float[4]"],
            "colorh[3]": [],
            "colorh[4]": [],
            "double": ["double"],
            "double[2]": ["double[2]"],
            "double[3]": ["double[3]"],
            "double[4]": ["double[4]"],
            "execution": ["uint32_t"],
            "float": ["float"],
            "float[2]": ["float[2]"],
            "float[3]": ["float[3]"],
            "float[4]": ["float[4]"],
            "frame[4]": ["double[4][4]"],
            "half": [],
            "half[2]": [],
            "half[3]": [],
            "half[4]": [],
            "int": ["int"],
            "int[2]": ["int[2]"],
            "int[3]": ["int[3]"],
            "int[4]": ["int[4]"],
            "int64": ["int64_t"],
            "matrixd[2]": ["double[2][2]"],
            "matrixd[3]": ["double[3][3]"],
            "matrixd[4]": ["double[4][4]"],
            "normald[3]": ["double[3]"],
            "normalf[3]": ["float[3]"],
            "normalh[3]": [],
            "objectId": ["uint64_t"],
            "path": ["uint64_t"],
            "pointd[3]": ["double[3]"],
            "pointf[3]": ["float[3]"],
            "pointh[3]": [],
            "$Quaternion layout": "[i, j, k, r] must be used to match the memory layout used by GfQuat4d et. al.",
            "quatd[4]": ["double[4]"],
            "quatf[4]": ["float[4]"],
            "quath[4]": [],
            "string": [],
            "target": [],
            "texcoordd[2]": ["double[2]"],
            "texcoordd[3]": ["double[3]"],
            "texcoordf[2]": ["float[2]"],
            "texcoordf[3]": ["float[3]"],
            "texcoordh[2]": [],
            "texcoordh[3]": [],
            "timecode": ["double"],
            "token": [],
            "transform[4]": ["double[4][4]"],
            "uchar": ["uint8_t"],
            "uint": ["uint32_t"],
            "uint64": ["uint64_t"],
            "vectord[3]": ["double[3]"],
            "vectorf[3]": ["float[3]"],
            "vectorh[3]": []
        }
    }
}

Enum Attribute Type

While there isn’t an enum” type as such, you can use the *token type with some metadata supplied in the .ogn file to make an attribute behave like an enum, including having the UI provide a dropdown menu with the allowed choices.

When accessing the data you use the same approach as with a token attribute.

Type Name

USD

C++

CUDA

Python

JSON

Description

token

token

NameToken

NameToken*

str

string

Interned string with fast comparison and hashing

See the description in the OGN reference guide for details on the use of the allowedTokens keyword that lets the token operate as an enum.

custom token inputs:myEnum = "Red" (
    allowedTokens = ["Red", "Green", "Blue"]
)
static bool compute(OgnMyNodeDatabase& db)
{
    NameToken const& colorName = db.inputs.myEnum();
    // or auto const& colorName = db.inputs.myEnum();
}
extern "C" runCUDAcompute(NameToken* color);
static bool compute(OgnMyNodeDatabase& db)
{
    runCUDAcompute( db.inputs.myEnum() );
}
extern "C" void runCUDAcompute(NameToken* color)
{
}
@property
def myEnum(self) -> str:
    return attributeValues.myEnum
{
    "myNode" : {
        "description" : [
            "This is my node with one enum-style input",
            "Here is where the regular token is transformed into an enum."
        ],
        "version" : 1,
        "inputs" : {
            "myEnum" : {
                "description" : [
                    "This is an enum attribute. By adding the 'allowedTokens' keyword you tell OmniGraph",
                    "that the token is only meant to have a value appearing on that list."
                ],
                "type" : "token",
                "default" : "Red",
                "metadata": {
                    "allowedTokens": ["Red", "Green", "Blue"]
                }
            }
        }
    }
}