Getting MoData in GVO of a ObjectData Plugin
-
Hello,
I'm trying to get the positions of the mograph matrix object in my ObjectData plugin and i'm having trouble with checking if it's cache is dirty and updating.I'm using GetAndCheckHierarchyClone to tell if the cache is dirty, which is working, but for some reason it's saying that the cache is dirty twice.
Also when it does say the cache is dirty, I go to read the Matrix Array, and it returns outdated data.
Am I missing a step somewhere?
I'm developing on Mac OSX with C4D R18.
Here's my code (shortened for clarity and no error checking):
BaseObject* GetVirtualObjects(BaseObject* op, HierarchyHelp* hh) { GeData myData; Bool dirty; BaseObject *outObject, *inObject, *hClone; outObject = BaseObject::Alloc(Ocube); dirty = false; hClone = nullptr; inObject = op->GetDown(); hClone = op->GetAndCheckHierarchyClone(hh, inObject, HIERARCHYCLONEFLAGS_ASIS, &dirty, nullptr, false); if (!dirty) { blDelete(outObject); return hClone; } maxon::BaseArray<Vector> pointList; MoData *md; GetMoDataMessage mdm; mdm.modata = nullptr; mdm.index = 0; // Get first set of modata BaseTag *mct = hClone->GetTag(ID_MOBAKETAG); // check for cache BaseTag *mdt = hClone->GetTag(ID_MOTAGDATA); // get mograph tag if (!mct && !mdt) // we need at least one return nullptr; if (mct) // check cache first mct->Message(MSG_GET_MODATA, &mdm); if (!mdm.modata) // if cache didn't work, or if there is no cache mdt->Message(MSG_GET_MODATA, &mdm); if (mdm.user_owned) md = mdm.Release(); else md = mdm.modata; MDArray<Matrix> marr = md->GetMatrixArray(MODATA_MATRIX); for (Int32 x = 0; x < md->GetCount(); x++) { pointList.Append(marr[x].off); } if (mdm.user_owned) MoData::Free(md); GePrint( String::IntToString( pointList.GetCount() ) ); return outObject; }
-
Also the mograph cache tag never returns modata, even when it's present and baked.
-
Hi @codysorgenfrey even if your topic is older than a day and we try to answers as soon as possible.
Your question needs some investigation, and with the DevKitchen we are pretty busy. But you can be sure if I didn't find some time to tackle today I will do Monday!Maybe you can find valid answers in this topic https://developers.maxon.net/forum/topic/8650/11316_modata-arrays--mograph-cache-tag-problem-solved But as I see you already use mdm.Release So I'm doubtful.
Thanks for your patience.
Cheers,
Maxime. -
@m_adam Thanks for the update. I'm in no hurry as I can work on other parts of the project while I wait. I look forward to your investigation!
-
So interesting find today. I think in order to get updates on the cache of a mograph matrix object I need to respond to MSG_MOGRAPH_REEVAULATE. Is this correct?
It seems to be the only way to get notified of when the mograph cache is updated, especially when using effectors.
-
Hi @codysorgenfrey while I was able to reproduce the issue. I'm still investigating it. Sadly due to the Devktchen, I won't be able to work on it the whole week.
At least, what I can't tell is the fact that touching the matrix object which prohibits the tag to be refreshed.Regarding MSG_MOGRAPH_REEVALUATE I'm doubtful but it's something I have to investigate also thanks for your finding, patience anyway.
Cheers,
Maxime. -
Hi @codysorgenfrey, just to inform you I've made some progress and I'm currently in discussion with the development team about your topic.
Hopefully, I will be able to provide you a concrete solution in short delay. Anyway thanks a lot for your patience.
Cheers,
Maxime. -
Hi @codysorgenfrey.
First of all, I would like to present my apologies for the time your topic took to get at least a constructive answer.Since matrix object is a bit special MoData are often out of data. It is not an issue for you, here is another solution.
If you want to read the point position of a matrix, you should convert it into a polygonObject and read Dpoint.
The con of that is you are losing the Modata (flags, etc, but deformer/effector are still working of course).BaseObject* GetVirtualObjects (BaseObject* op, HierarchyHelp* hh) { // Create a Null master BaseObject* outObject = BaseObject::Alloc(Onull); if (!outObject) return nullptr; // Get the cache BaseObject* matrixObj = op->GetDown(); if (!matrixObj || !matrixObj->IsInstanceOf(1018545)) // 1018545 = Matrix Object return outObject; // Get the Matrix as a poly, it do not proper touch the Matrix Object, so you have to do it manually Bool dirty; BaseObject* clone = op->GetAndCheckHierarchyClone(hh, matrixObj, HIERARCHYCLONEFLAGS::ASPOLY, &dirty, nullptr, false); if(!dirty) return outObject; // Touch the original matrix in order to hide it in viewport matrixObj->Touch(); // Get ptCount and Point Array Int32 ptCount = ToPoly(clone)->GetPointCount() / 4; const Vector* padr = ToPoint(clone)->GetPointR(); Dpoint *d = (Dpoint *) padr; // iterate over the point and create null at the pt matrix maxon::BaseArray<Vector> pointList; for(Int32 x = 0; x < ptCount; x++) { BaseObject* n = BaseObject::Alloc(Onull); if(!n) return outObject; // Get the Correct World Matrix Matrix result(d[x].m.off + matrixObj->GetMl().off, d[x].m.sqmat.v1 + matrixObj->GetMl().sqmat.v1, d[x].m.sqmat.v2 + matrixObj->GetMl().sqmat.v2, d[x].m.sqmat.v3 + matrixObj->GetMl().sqmat.v3); n->SetMg(result); n->InsertUnder(outObject); pointList.Append(d[x].GetPos()); } ApplicationOutput("@", pointList.GetCount()); return outObject; }
Note in this example it only works with 1 matrice object, and as you can see you need to manually touch the object and I assume the result of GetAndCheckHierarchyClone is the result of the Matrix Object itself.
If you have multiple objects and a matrice is within, it may be worth doing the cache system yourself, please take a look at BaseObject Manual - Generating for more information.If you have any question, please let me know.
Cheers,
Maxime. -
@m_adam Thanks for the thorough response! This solution actually fits my needs better anyways.
-
Hi @codysorgenfrey please if your thread has been solved please mark the answers as the correct answers or at least mark the topic as solved.
For more information please read the Q&A New Functionality.Cheers,
Maxime. -
@m_adam I'm finally getting around to implementing this fix, and it's working really well except for it's alway rebuilding the cache, GetAndCheckHeirarchyClone is always saying the input object is dirty.
Is this how it's supposed to work?
-
Hi @codysorgenfrey.
Thanks a lot for writing to us. Actually Touching the matrix object, clean the cache of its. Since Matrix object is a bit special and only consist of a kind of cached version. If there is no cache (which is what happens when you touch an object), the matrix object rebuilds itself. So we end up with an infinite dirtiness issue.With that's said here a working example for handling matrix object. Note that we have to check the dirtiness manually.
class ModataGvoObject : public ObjectData { INSTANCEOF(ModataGvoObject, ObjectData) private: UInt32 previousDirty; public: BaseObject* GetVirtualObjects(BaseObject* op, HierarchyHelp* hh) { // Create a Null master BaseObject* outObject = BaseObject::Alloc(Onull); if(!outObject) return nullptr; // Get the cache BaseObject* matrixObj = op->GetDown(); if(!matrixObj || !matrixObj->IsInstanceOf(1018545)) // 1018545 = Matrix Object return outObject; // Calculate dirtyCount UInt32 newDirty = 0; newDirty += matrixObj->GetDirty(DIRTYFLAGS::MATRIX | DIRTYFLAGS::DATA | DIRTYFLAGS::CACHE); newDirty += matrixObj->GetHDirty(HDIRTYFLAGS::OBJECT | HDIRTYFLAGS::OBJECT_HIERARCHY | HDIRTYFLAGS::OBJECT_MATRIX); if(previousDirty == newDirty) return op->GetCache(hh); // Get the Matrix as a poly (We could have call CurrentState To object also) BaseObject* clone = op->GetHierarchyClone(hh, matrixObj, HIERARCHYCLONEFLAGS::ASPOLY, nullptr, nullptr); // Hide the matrix object (handle are still drawn if matrix object is selected) previousDirty = newDirty; matrixObj->SetBit(BIT_IGNOREDRAW); // Get ptCount and Point Array Int32 ptCount = ToPoly(clone)->GetPointCount() / 4; const Vector* padr = ToPoint(clone)->GetPointR(); Dpoint *d = (Dpoint *) padr; // iterate over the point and create null at the pt matrix maxon::BaseArray<Vector> pointList; for(Int32 x = 0; x < ptCount; x++) { BaseObject* n = BaseObject::Alloc(Onull); if(!n) return outObject; // Get the Correct World Matrix Matrix result(d[x].m.off + matrixObj->GetMl().off, d[x].m.sqmat.v1 + matrixObj->GetMl().sqmat.v1, d[x].m.sqmat.v2 + matrixObj->GetMl().sqmat.v2, d[x].m.sqmat.v3 + matrixObj->GetMl().sqmat.v3); n->SetMg(result); n->InsertUnder(outObject); pointList.Append(d[x].GetPos()); } ApplicationOutput("@", pointList.GetCount()); return outObject; }
Cheers,
Maxime -
@m_adam thanks so much for all your help on this!