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
    • Categories
      • Overview
      • News & Information
      • Cinema 4D SDK Support
      • Cineware SDK Support
      • ZBrush 4D SDK Support
      • Bugs
      • General Talk
    • Unread
    • Recent
    • Tags
    • Users
    • Login

    Getting MoData in GVO of a ObjectData Plugin

    Cinema 4D SDK
    c++ windows macos
    2
    13
    3.4k
    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

      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