[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:
MPxData::writeBinary()
/MPxData::readBinary()
MPxData::writeASCII()
/MPxData::readASCII()
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