[Maya C++ API] Save MPxData attribute on file

Introduction

In Maya nodes are connected through attributes, Maya provides base types (e.g. matrices, vector of floats) but sometimes you want to use your own type to transfer data from one node to another. In this case you need to inherit from MPxData. There are functions to override in MPxData to specify how to write and load your custom data into the Maya scene file. I found the official documentation to be a bit thin on the topic, so I'm leaving additional tips here related to:

Attribute settings

First to make sure those functions are called, you should ensure your custom attribute (inheriting from MPxData) is set to storable and writable:

MFnTypedAttribute typed_attr;
_my_attrib = typed_attr.create("attr_name", "attr", Custom_data::_s_id, MObject::kNullObj, &status);
mayaCheck( status );
mayaCheck( typed_attr.setStorable(true) );
mayaCheck( typed_attr.setWritable(true) );
mayaCheck( addAttribute(_my_attrib) );
mayaCheck( attributeAffects(_my_attrib, _my_attrib) );

Binary scene file

An input and output stream (std::istream, std::ostream) are provided for you to directly read and write bytes:

// Save only for base types such as int, float, double, char, plain structures
template static inline
T read(std::istream& in) { T val; in.read( (char*)&val, sizeof(val) ); return val; }

template static inline
void write(std::ostream& out, T val) { out.write( (char*)&val, sizeof(val) ); }

template  static inline
std::vector read_std_vec_binary(std::istream& in){
    std::vector vec;
    uint32_t size;
    in.read( (char*)&size, sizeof(size));
    vec.resize( size );
    in.read( (char*)vec.data(), sizeof(T)*vec.size() );
    return vec;
}

template  static inline
void write_std_vec_binary(std::ostream& out, const std::vector& vec) {
    uint32_t size = (uint32_t)vec.size();
    out.write( (char*)&size, sizeof(size) );
    out.write( (char*)vec.data(), sizeof(T)*vec.size() );
}

MStatus	Custom_data::writeBinary( std::ostream& out )
{
    write(out, 54.0f);
    write(out, true);
    std::vector vec(40, 5.0f);
    write_std_vec_binary(out, vec);
}

MStatus Custom_data::readBinary( std::istream& in, unsigned int )
{
    float v = read(in);
    bool  s = read (in);
    std::vector vec = read_std_vec_binary(in);
}

How you read data from the stream only depends on how you decided to organize your data when writing. For some reason I could not use the stream operators << and >>. Prefer out.write() and in.read().

ASCII scene file

TODO

Code

One comment

MPxData copy method will copy your vectors each time when you will read it in your nodes compute methods. Sometimes, twice. To avoid wasting the time, you should store the internal data pointer in your custom MPxData.

vuf3d - 23/07/2022 -- 14:58
(optional field, I won't disclose or spam but it's necessary to notify you if I respond to your comment)
All html tags except <b> and <i> will be removed from your comment. You can make links by just typing the url or mail-address.
Anti-spam question: