Values

See also

The C++ Value and Python rumba.Value documentation.

Values are stored or generated by the plugs. Values can be basic or advanced. Basic values have the following types:

Basic Values

Basic Types

Name

Internal C++ Type

Description

Bool

bool

A boolean value

Int

int

A signed 32 bits integer

Float

double

A double precision floating point number

String

std::string

A utf-8 encoded string

V2i

Imath::V2i

A signed 32 bits two dimensions vector (x, y)

V3i

Imath::V3i

A signed 32 bits three dimensions vector (x, y, z)

V4i

Imath::V4i

A signed 32 bits four dimensions vector (x, y, z, w)

V2f

Imath::V2d

A double precision two dimensions vector (x, y),

V3f

Imath::V3d

A double precision three dimensions vector (x, y, z)

V4f

Imath::V4d

A double precision four dimensions vector (x, y, z, w)

Color4f

Imath::Color4f

A single precision color (r, g, b, a)

M44f

Imath::M44d

A double precision 4x4 Matrix

Box3f

Imath::Box3d

A double precision 3d bounding box

Quatf

Imath::Quatd

A double precision quaternion

Here is an example of how to retrieve some value from the maquina::EvaluationContext and returns a simple value:

  • c++
  • python
static Value eval_result( EvalContext& ctx )
{
    // Directly get the basic value from the plug
    const Imath::V3d& direct_v3d = ctx.as_V3d(1);

    // Retrieve a generic value then cast it :
    const Value value = ctx.value(1);
    const Imath::V3d& v3d = value.as_V3d();

    ...

    return Imath::V3d(1.0, 2.0, 3.0); // Return basic values directly
}
def eval_result(ctx):
    # Directly get the basic value from the plug
    v3d = ctx.as_V3d(1)

    # Retrieve a generic value then cast it :
    value = ctx.value(1)
    v3d = value.as_V3d()

    ...

    return Imath.V3d(1.0, 2.0, 3.0) # Return basic values directly

Warning

In C++, all the values returned by the EvaluationContext must be considered unmutable. Always use the const type modifier.

Advanced Values

Advanced values are more complex objects like shapes or collections. Those objects must be casted in an API class to be accessed or modified.

Some example of the advanced values:

Advanced Types

Type Name

API Class

Parent Class

Description

BufferFloat

BufferFloat

Value

A mutable buffer of single precision float numbers

BufferFloat

BufferConstFloat

Value

An unmutable buffer of single precision float numbers

Scene

Scene

Value

A mutable scene tree of transforms and objects

Scene

SceneConst

Value

An unmutable scene tree of transforms and objects

Array

Array

Value

An array of heterogeneous values

Dict

Dict

Value

A string based dictionary of heterogeneous values

Shape

Shape

Value

The base type of shapes

Points

Points

Shape

The base type of shapes with vertices

Mesh

Mesh

Points

A polygonal mesh

Spline

NurbsCurve

Points

A nurbs curve

NurbsSurface

NurbsSurface

Points

A nurbs surface

Ownership

In both C++ and Python, advanced value objects are copied by reference. To really duplicate an object and get your own mutable instance, use Node::duplicate() or maquina::duplicate() for buffers and scenes:

  • c++
  • python
// Get a const value from the dependance #1, we must not modify that one
const Mesh a(ctx.value(1));

// Copy by reference
Mesh b = a; // a and b are the same object. Don't modify a, you will modify b!

// Duplication
Mesh c = a.duplicate(); // c is a new object, it can be modified safely.
# Cast the dependance #1 to a Mesh value. Beware we must not modify that one
a = Mesh(ctx.value(1))

# Copy by reference
b = a # a and b are the same object. Don't modify a, you will modify b!

# Duplication
c = a.duplicate() # c is a new object, it can be modified safely.

Array

See also

The C++ Array and Python rumba.Array documentation.

Array objects are a collection of heterogeneous values. They have a size and can be accessed using indices. MTORBA returns the Maya’s compounds and array plug values as Array objects.

  • c++
  • python
static Value eval_result( EvalContext& ctx )
{
    // Get a const Array from the dependance #1, we must not modify that one
    const Array array(ctx.value(1));

    const auto size = array.size();

    // Access an array element
    float f = array.as_float(0);
    const Value v = array.value(0);

    // Create an empty array
    Array result;

    // Push values in the array
    result.push_back(1.f);
    result.push_back(ctx.value(2)); // It's legal to return references of input values

    // Return the new array as the evaluation result
    return result;
}
def eval_result(ctx):
    # Cast the dependance #1 to an Array value. Beware we must not modify that one
    array = Array(ctx.value(1))

    size = array.size()

    # Access an array element
    f = array.as_float(0)
    v = array.value(0)

    # Create an empty array
    result = Array()

    # Push values in the array
    result.push_back(1.0)
    result.push_back(ctx.value(2)) # It's legal to return references of input values

    # Return the new array as the evaluation result
    return result

Buffers

See also

The C++ Buffer, BufferConst and Python rumba.BufferFloat, rumba.BufferConstFloat documentation.

Buffers are collections of basic types stored in a compact memory buffer. To avoid mistakes, buffers have different API classes for their mutable and unmutable versions, like BufferFloat vs BufferConstFloat.

Buffer Types

Type Name

Mutable API Class

Unmutable API Class

Description

BufferInt32

BufferInt32

BufferConstInt32

A buffer of signed 32 bits integers

BufferUInt8

BufferUInt8

BufferConstUInt8

A buffer of unsigned 8 bits integers

BufferUInt32

BufferUInt32

BufferConstUInt32

A buffer of unsigned 32 bits integers

BufferFloat

BufferFloat

BufferConstFloat

A buffer of single precision float numbers

BufferDouble

BufferDouble

BufferConstDouble

A buffer of double precision float numbers

BufferV2f

BufferV2f

BufferConstV2f

A buffer of single precision two dimensions vector (x, y)

BufferV3f

BufferV3f

BufferConstV3f

A buffer of single precision three dimensions vector (x, y, z)

BufferV4f

BufferV4f

BufferConstV4f

A buffer of single precision four dimensions vector (x, y, z, w)

BufferV2i

BufferV2i

BufferConstV2i

A buffer of signed 32 bits integer two dimensions vector (x, y)

BufferV3i

BufferV3i

BufferConstV3i

A buffer of signed 32 bits integer three dimensions vector (x, y, z)

BufferV4i

BufferV4i

BufferConstV4i

A buffer of signed 32 bits integer four dimensions vector (x, y, z, w)

BufferM33f

BufferM33f

BufferConstM33f

A buffer of Imath::M33f

BufferM44f

BufferM44f

BufferConstM44f

A buffer of Imath::M44f

BufferBox3f

BufferBox3f

BufferConstBox3f

A buffer of Imath::Box3f

For example, the vertices of a geometry can be retrieved as a buffer with Points::read_points() or Points::write_points().

For better read/write access performances, we recommand to use Buffer::read() or Buffer::write(), which deliver a gsl::span. Ìn a nutshell, a gsl::span` contains a pointer on a contiguous sequence of values.

Sparse Buffers

Sparse buffers are used to store sparse attributes on a geometry topology, like deformer’s weight maps for instance.

Some example of sparse buffers types :

Sparse Buffer Types

Type Name

Mutable API Class

Unmutable API Class

Description

SparseBufferFloat

SparseBufferFloat

SparseBufferConstFloat

A sparse buffer of single precision float numbers

SparseBufferV3f

SparseBufferV3f

SparseBufferConstV3f

A sparse buffer of single precision three dimensions vector (x, y, z)

Indexed Buffers

Indexed buffers are used to store indexed values on a geometry topology, like the mesh UV coordinates or the normals for instance.

Some example of indexed buffers types :

Indexed Buffer Types

Type Name

Mutable API Class

Unmutable API Class

Description

IndexedBufferFloat

IndexedBufferFloat

IndexedBufferConstFloat

An indexed buffer of single precision float numbers

IndexedBufferV3f

IndexedBufferV3f

IndexedBufferConstV3f

An indexed buffer of single precision three dimensions vector (x, y, z)

Geometry Values

Maquina supports different kind of shapes objects, Points (point clouds), Mesh, NurbsCurve, NurbsSurface, Lattice.

Geometry objects have vertices (points), topology (for meshes) and optional attributes. Vertices, attributes and topologies are buffer values shared across geometry values. They can be accessed using their name. Attributes can have arbitrary names, but some names are reserved by convention:

Basic Attributes

Attribute Name

Type

Description

P

BufferV3f

The mesh vertices. Accessed with Points::read_points() and Points::read_points::write_points().

UV

IndexedBufferV2f

The mesh UV coordinates, IndexedBufferV2f in a face_varying topology

N

IndexedBufferV3f

The mesh normals, indexed buffer in a face_varying topology

The API always returns attributes with a valid size, regarding the topology where they are defined. The plug-in developer does not have to worry about the buffer dimension, it must match the mesh structure. However, an exception may be thrown trying to access a non-existing attribute.

The different topologies of an attribute:

Attribute Topologies

Topology Name

Description

maquina::Shape::Topology::constant

The attribute is a single constant value

maquina::Shape::Topology::vertex

The attribute has a value per vertex

maquina::Shape::Topology::face

The attribute has a value per face

maquina::Shape::Topology::face_varying

The attribute has a value per face corner

Here is an example of an evaluation function accessing an input mesh value’s points and UVs, duplicating the mesh, modifying its vertices and returning the new mesh as result:

  • c++
  • python
static Value eval_result( EvalContext& ctx )
{
    // Get a float value
    const float envelope = ctx.as_float(0);
    if(envelope == 0.f)
        return ctx.value(1);    // It's legal to return input values

    // * Input

    // Get a const value from the dependance #1, we must not modify that one
    const Mesh mesh(ctx.value(1));

    // Get a read only accessor on the mesh vertices
    BufferConstV3f input_points = mesh.read_points();

    // Get a pointer on the input points, for speed
    gsl::span<const V3f> input_points_ptr = input_points.read();

    // Get a read only accessor on the mesh UV's
    SparseBufferConstV2f input_uvs = mesh.read_attribute("UV", Shape::Topology::face_varying);

    // * Output

    // Get a mutable copy of that mesh
    Mesh result = mesh.duplicate();

    // Get a writable accessor on the mesh vertices
    BufferV3f output_points = result.write_points();

    // Get a pointer on the output points, for speed
    gsl::span<V3f> output_points_ptr = output_points.write();

    // Modify the vertices, one might use parallel_for
    for(V3f& p : output_points_ptr)
        p = ...;

    // Return the new mesh
    return result;
}
def eval_result(ctx):
    # Get a float value
    envelope = ctx.as_float(0)
    if envelope == 0.0:
        return ctx.value(1)    # It's legal to return input values

    # * Input

    # Cast the dependance #1 to a Mesh value. Beware we must not modify that one
    mesh = Mesh(ctx.value(1))

    # Get a read only accessor on the mesh vertices
    input_points = mesh.read_points()

    # Get a read only accessor on the mesh UV's
    input_uvs = mesh.read_attribute("UV", Shape.Topology.face_varying)

    # * Output

    # Get a mutable copy of that mesh
    result = mesh.duplicate()

    # Get a writable accessor on the mesh vertices
    output_points = result.write_points()

    # Modify the vertices
    for i in range(output_points.size()):
        output_points[i] = ...

    # Return the new mesh
    return result

User Data

Users can create their own value types by deriving the maquina::UserData class. User data are allocated inside an evaluation function with std::make_shared and retrieved with EvaluationContext::as_user_data().

Values are destroyed by Maquina’s evaluation engine when they are not referenced any more. The destructor may be called by an arbitrary thread.

Warning

Maquina’s user data are available only in C++.

Maquina’s user data can’t be serialized, they can only be used for intermediate graph results.

Here is an example of how to declare, access and compute user data:

  • c++
// A user data
class MyUserData : public maquina::UserData
{
public:

  // Must provide a type_name function
  virtual StringView type_name() const { return "MyUserData"; };

  ...

private:
  // Whatever you need inside
  int _a, _b;

  // Including Values
  Mesh _mesh;
};

// The evaluation function
static Value eval_result( EvalContext& ctx )
{
    // Retrieve a user data from the plug's second dependance (#1)
    std::shared_ptr<const MyUserData> user_data = std::dynamic_pointer_cast<const MyUserData>(ctx.as_user_data(1));

    // Create a user data and return it as result
    std::shared_ptr<MyUserData> result = std::make_shared<MyUserData>();

    return result;
}