Solved Accessing a virtual matrix object.


I am attempting to get the MoData from a Matrix object that hasn't been inserted in the open document, instead its been inserted into a virtual document. Inside of the virtual document I set the parameters of the Matrix object so that it is in Object mode. Once the mode has been changed I insert a clone of an object into the virtual document that is then linked with the Object field of the Matrix object.

	BaseDocument *virtualDoc = BaseDocument::Alloc();
	BaseObject *matrixObj = BaseObject::Alloc(1018545); // Matrix
	if (matrixObj == nullptr)
		return nullptr;
	BaseObject *cloneObj = (BaseObject*)op->GetDown()->GetClone(COPYFLAGS::NONE, nullptr);
	virtualDoc->InsertObject(matrixObj, nullptr, nullptr);
	virtualDoc->InsertObject(cloneObj, nullptr, nullptr);

	BaseContainer *matrixData = matrixObj->GetDataInstance();
	matrixData->SetInt32(ID_MG_MOTIONGENERATOR_MODE, 0);
	matrixData->SetLink(MG_OBJECT_LINK, cloneObj);
	matrixData->SetInt32(MG_POLY_MODE_, 0);

	BaseTag *tmp = matrixObj->GetTag(ID_MOTAGDATA); // Newly inserted Matrix does not have an ID_MOTAGDATA tag
	if (!tmp)
		return nullptr;

The code runs properly until it attempts to get the tag from the Matrix object, on the initial insertion of the Matrix it doesn't generate its MoTagData tag. Is there a way to force a refresh on the Matrix object so that it generates the MoTagData tag so that I can access the MoData?

Any help would be appreciated,

John Thomas


you can update the document using ExecutePasses

be aware sometimes you have to call it several times.

BaseContainer *matrixData = matrixObj->GetDataInstance();
	matrixData->SetInt32(ID_MG_MOTIONGENERATOR_MODE, 0);
	matrixData->SetLink(MG_OBJECT_LINK, cloneObj);
	matrixData->SetInt32(MG_POLY_MODE_, 0);

	virtualDoc->ExecutePasses(nullptr, true, true, true, BUILDFLAGS::NONE);

	BaseTag *tag = matrixObj->GetTag(ID_MOTAGDATA); 
	if (tag == nullptr)
		return maxon::NullptrError(MAXON_SOURCE_LOCATION);
	GetMoDataMessage msg = GetMoDataMessage();
	tag->Message(MSG_GET_MODATA, &msg);
	MoData *md = msg.modata;
	if (md == nullptr)
		return maxon::NullptrError(MAXON_SOURCE_LOCATION);

	MDArray<maxon::Matrix> mdmg = md->GetMatrixArray(MODATA_MATRIX);


MAXON SDK Specialist

MAXON Registered Developer

@m_magalhaes Speaking of ExecutePasses(): The documentation is using it per frame to forward to a certain frame for rendering. That makes sense, as the simulation (and any related task that is relying on previous-frame information) needs to be processed completely from frame 0 (or maybe even farther back).

But what happens when you enter a frame number on the GUI and jump there? Usually, simulations that are not cached do not work properly with direct frame jumps, so I assume ExecutePasses() is only called once in these functions? It would probably be too time-consuming to run through all previous frames.

If so, what is the underlying difference between DrawViews() with animation allowed in the flags, and ExecutePasses()? Which calls which? Am I correct in assuming that ExecutePasses() just evaluates the object tree, and is called by DrawViews() when the animation flag is set, so DrawViews() will have the current (animated) object states? Is ExecutePasses() called in any way by DrawViews() when that flag is NOT set?


DrawViews() draws the views (editor windows), which includes ExecutePasses(). ExecutePasses() itself just updates the associated BaseDocument.

You find some information here: Scene Execution Pipeline and Thread

For questions unrelated to this thread, please open a new thread. Thanks.

Best wishes,

@m_magalhaes Thanks for the response Manuel, that was exactly what I needed.

John Thomas