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.5k
    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 @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