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.


  • Global Moderator

    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://plugincafe.maxon.net/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.


  • Global Moderator

    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.


  • Global Moderator

    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.


  • Global Moderator

    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.


  • Global Moderator

    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?