Maxon Developers Maxon Developers
    • Documentation
      • Cinema 4D Python API
      • Cinema 4D C++ API
      • Cineware API
      • ZBrush GoZ API
      • Code Examples on Github
    • Forum
    • Downloads
    • Support
      • Support Procedures
      • Registered Developer Program
      • Plugin IDs
      • Contact Us
    • Unread
    • Recent
    • Tags
    • Users
    • Login

    Getting MoData in GVO of a ObjectData Plugin

    Cinema 4D SDK
    c++ windows macos
    2
    13
    3.2k
    Loading More Posts
    • Oldest to Newest
    • Newest to Oldest
    • Most Votes
    Reply
    • Reply as topic
    Log in to reply
    This topic has been deleted. Only users with topic management privileges can see it.
    • codysorgenfreyC
      codysorgenfrey
      last edited by a_block

      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;
      }
      
      1 Reply Last reply Reply Quote 0
      • codysorgenfreyC
        codysorgenfrey
        last edited by

        Also the mograph cache tag never returns modata, even when it's present and baked.

        1 Reply Last reply Reply Quote 0
        • M
          m_adam
          last edited by m_adam

          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.

          MAXON SDK Specialist

          Development Blog, MAXON Registered Developer

          codysorgenfreyC 1 Reply Last reply Reply Quote 0
          • codysorgenfreyC
            codysorgenfrey @m_adam
            last edited by

            @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!

            1 Reply Last reply Reply Quote 0
            • codysorgenfreyC
              codysorgenfrey
              last edited by

              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.

              1 Reply Last reply Reply Quote 0
              • M
                m_adam
                last edited by

                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.

                MAXON SDK Specialist

                Development Blog, MAXON Registered Developer

                1 Reply Last reply Reply Quote 0
                • M
                  m_adam
                  last edited by

                  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.

                  MAXON SDK Specialist

                  Development Blog, MAXON Registered Developer

                  1 Reply Last reply Reply Quote 0
                  • M
                    m_adam
                    last edited by

                    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.

                    MAXON SDK Specialist

                    Development Blog, MAXON Registered Developer

                    codysorgenfreyC 1 Reply Last reply Reply Quote 3
                    • codysorgenfreyC
                      codysorgenfrey @m_adam
                      last edited by

                      @m_adam Thanks for the thorough response! This solution actually fits my needs better anyways.

                      1 Reply Last reply Reply Quote 0
                      • M
                        m_adam
                        last edited by

                        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.

                        MAXON SDK Specialist

                        Development Blog, MAXON Registered Developer

                        codysorgenfreyC 1 Reply Last reply Reply Quote 0
                        • codysorgenfreyC
                          codysorgenfrey @m_adam
                          last edited by codysorgenfrey

                          @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?

                          1 Reply Last reply Reply Quote 0
                          • M
                            m_adam
                            last edited by m_adam

                            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

                            MAXON SDK Specialist

                            Development Blog, MAXON Registered Developer

                            1 Reply Last reply Reply Quote 2
                            • codysorgenfreyC
                              codysorgenfrey
                              last edited by

                              @m_adam thanks so much for all your help on this!

                              1 Reply Last reply Reply Quote 0
                              • First post
                                Last post