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:
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:
// 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.
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
See also
The C++ SparseBuffer, SparseBufferConst and Python rumba.SparseBufferFloat, rumba.SparseBufferConstFloat documentation.
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
See also
The C++ IndexedBuffer, IndexedBufferConst and Python rumba.IndexedBufferFloat, rumba.IndexedBufferConstFloat documentation.
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:
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:
// 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;
}