Maxon Developers Maxon Developers
    • Documentation
      • Cinema 4D Python API
      • Cinema 4D C++ API
      • Cineware API
      • ZBrush Python 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

    Loft incorrectly returning input objects

    Cinema 4D SDK
    sdk r20 c++
    3
    10
    1.6k
    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.
    • J
      JohnThomas
      last edited by

      Hello,

      For my plugin I am creating a SplineObject by using a child PolygonObject as input. From the child object I am properly getting the polygon data and using it to create the SplineObject as seen below.

      Picture 1.png

      This is working exactly as I want it to, including the child objects not appearing in the viewport.

      The problem comes in when I create a Loft and place the copies of my plugin as its children.

      Picture 2.png

      For some reason the Loft is returning the child Cubes despite them being inputs to my plugin.

      When I make the Loft editable this is what the hierarchy is showing.

      Picture 3.png

      This is the stripped down code I am using to do this example. In the code I am just taking the points of the first polygon from the child object and using it to generate the spline. I know that it doesn't have the proper safeguards in place to prevent a crash outside of the scope of my test.

      
      class TestProblem : public ObjectData
      {
      	INSTANCEOF(TestProblem, ObjectData)
      
      public:
      
      	BaseObject* GetVirtualObjects(BaseObject *op, HierarchyHelp *hh);
      	virtual SplineObject* GetContour(BaseObject* op, BaseDocument* doc, Float lod, BaseThread* bt);
      	static NodeData* Alloc() { return NewObjClear(TestProblem); }
      };
      
      
      
      
      BaseObject* TestProblem::GetVirtualObjects(BaseObject * 	op, HierarchyHelp *hh)
      {
      	Bool dirtyBool;
      	BaseObject* down = op->GetDown();
      	op->NewDependenceList();
      	while (down != nullptr)
      	{
      		op->GetHierarchyClone(hh, down, HIERARCHYCLONEFLAGS::ASPOLY | HIERARCHYCLONEFLAGS::ASSPLINE, &dirtyBool, nullptr);
      
      		down = down->GetNext();
      	}
      	op->TouchDependenceList();
      
      	return nullptr;
      }
      
      
      
      SplineObject* TestProblem::GetContour(BaseObject* op, BaseDocument* doc, Float lod, BaseThread* bt)
      {
      
      	BaseObject *childObj = op->GetDown();
      	if (childObj == nullptr)
      	{
      		return nullptr;
      	}
      
      	BaseObject *cachedObject = childObj->GetCache();
      	PolygonObject *poly = (PolygonObject*)cachedObject;
      	Matrix polyObjMat = poly->GetMg();
      	if (poly == nullptr)
      	{
      		return nullptr;
      	}
      
      	// Get the data from the polygon object
      	const CPolygon *polyArray = poly->GetPolygonR();
      	if (polyArray == nullptr)
      	{
      
      		return nullptr;
      	}
      	const Vector *posArray = poly->GetPointR();
      
      
      	// Create a spline using the four points from the first polygon on the child object
      	SplineObject *spline;
      	spline = SplineObject::Alloc(2, SPLINETYPE::LINEAR);
      	spline->ResizeObject(4, 0);
      	Segment *splineSegment = spline->GetSegmentW();
      	Vector *vectors = spline->GetPointW();
      	vectors[0] = polyObjMat * posArray[polyArray[0].a];
      	vectors[1] = polyObjMat * posArray[polyArray[0].b];
      	vectors[2] = polyObjMat * posArray[polyArray[0].c];
      	vectors[3] = polyObjMat * posArray[polyArray[0].d];
      	BaseContainer *splineData = spline->GetDataInstance();
      	splineData->SetInt32(SPLINEOBJECT_CLOSED, TRUE);
      	spline->Message(MSG_UPDATE);
      
      	return spline;
      }
      
      
      
      Bool RegisterTestProblem()
      {
      	return RegisterObjectPlugin(ID_TestProblem, "Test"_s, OBJECT_GENERATOR | OBJECT_ISSPLINE | OBJECT_INPUT, TestProblem::Alloc, "Test"_s, AutoBitmap("circle.tif"_s), 0);
      }
      
      

      Is there some method to prevent the Loft, and any other similar Cinema objects, from returning the child objects of my plugin?

      Any help would be greatly appreciated.

      John Thomas

      1 Reply Last reply Reply Quote 0
      • J
        JohnThomas
        last edited by

        I've spent more time working on it and have still not found a solution. Any help would be greatly appreciated.

        John Thomas

        1 Reply Last reply Reply Quote 0
        • r_giganteR
          r_gigante
          last edited by r_gigante

          Hi @JohnThomas, first and foremost I sincerely apologise for getting back to this thread so lately.

          A few notes on your code that are very likely to prevent your cubes to disappear:

          • ObjectData::GetVirtualObjects() is not supposed to return a nullptr but rather return a BaseObject::Alloc(Onull);
          • it's rather awkward how DependencyList is used in your code: from the code it's actually doing nothing without calling BaseObject::AddDependence()
          • it's also useless to invoke BaseObject::GetHierarchyClone() without storing its results in somewhere and I also have doubts on the combination of HIERARCHYCLONEFLAGS you used.
          • always check a pointer before (see poly->GetMg()) calling any method belonging to the instance it points to or accessing its data ( see accessing posArray values)

          I recommend to have a look at the Generating section of the BaseObject Manual where fundamental concepts about BaseObject generation are explained.

          Cheers, R.

          1 Reply Last reply Reply Quote 0
          • J
            JohnThomas
            last edited by

            Thanks for the response.

            From my tests if GetHierarchyClone is commented out then the child object never disappears, as opposed to not appearing in the viewport. So it does seem to be doing something.

            To be clear, my goal is to have the child objects correctly marked, (so they wouldn't appear when under the loft or at all), and to correctly retrieve the polygon/spline objects of the children for use in either GetContour(since sometimes I want to return a spline) or GetVirtualObject(since sometimes I want to return an polygon object).

            From what I understand the ways to get the polygon/spline objects are CurrentStateToObject, GetCache, GetDeformCache, and GetHierarchyClone.

            It seems like CurrentStateToObject doesn't seem like an option because cloning the object over to a new document and rebuilding it can be slow.

            Using GetCache and GetDeformCache is faster but far more complicated given the number of exceptions that need to be handled. And these can't be used with AddDependence/TouchDependenceList clears the caches right?

            GetHierarchyClone seems to work but that's only available in GetVirtualObjects, so what should be done in GetContour?

            What would be the best approach to mark the children objects of my plugins and to retrieve the contents of those children in both GetContour and GetVirtualObject?

            John Thomas

            1 Reply Last reply Reply Quote 0
            • J
              JohnThomas
              last edited by

              I still haven't had any success in getting my code to work as expected. Any help would be appreciated.

              John Thomas

              1 Reply Last reply Reply Quote 0
              • r_giganteR
                r_gigante
                last edited by r_gigante

                Hi @JohnThomas, sorry for the delay in getting back to you.

                This topic was throughly discussed in a few threads already which I warmly recommend to look for.
                The first was back in 2016 with GetVirtualObjects v GetContour for Spline Gen which ended up in the creation of the Offset-Y Spline example available on @dskeithbuck / @dskeith GitHub repo.

                The second came on 2019 with GetRealSpline() not returning a result where @m_adam also come in to refine the Offset-Y Spline code in this post.

                Reading it and dissecting the code will answer all your answers.
                Last but not least, the spline example is registered passing the OBJECT_INPUT flag which as throughly discussed on OBJECT_INPUT Child Updating doesn't work in combination with Dynamic Tags.

                Cheers, R

                1 Reply Last reply Reply Quote 0
                • J
                  JohnThomas
                  last edited by JohnThomas

                  Thanks for the reply.

                  I went through the threads you linked but I've got a couple of clarification questions from them as I dig into them more.

                  I have concerns about the speed of some of the operations that are proposed.

                  From putting some prints in the GVO and GetContour of the OffsetYSpline, it seems like both GVO and GetContour are both getting called every time the plugin updates, so the entire spline is being rebuilt twice.

                  Is there a concern about the speed of the plugin given that it seems to be rebuilding twice?

                  From the code presented in https://developers.maxon.net/forum/topic/11408/getrealspline-not-returning-a-result/12

                  def GetCloneSpline(op):
                         
                          #Emulates the GetHierarchyClone in the GetContour by using the SendModelingCommand
                          #:param op: The Object to clones and retrieves the current state (take care the whole hierarchy is join into one object.
                          #:return: The merged object or None, if the retrieved object is not a Spline
                         
                          # Copies the original object
                          childSpline = op.GetClone(c4d.COPYFLAGS_NO_ANIMATION)
                          if childSpline is None:
                              raise RuntimeError("Failed to copy the child spline.")
                  
                          # Retrieves the original document (so all links are kept)
                          doc = op.GetDocument() if op.GetDocument() else c4d.documents.BaseDocument()
                          if not doc:
                              raise RuntimeError("Failed to retrieve a Doc")
                  
                          # Inserts the object into the document, this is needed for Current State To Object operation
                          doc.InsertObject(childSpline)
                  
                          # Performs a Current State to Object
                          resultCSTO = c4d.utils.SendModelingCommand(command=c4d.MCOMMAND_CURRENTSTATETOOBJECT, list=[childSpline], doc=doc)
                          if not isinstance(resultCSTO, list) or not resultCSTO:
                              raise RuntimeError("Failed to perform MCOMMAND_CURRENTSTATETOOBJECT.")
                  
                          # Removes the original clone object
                          childSpline.Remove()
                  
                          childSpline = resultCSTO[0]
                          # If the results is a Null, performs a Join command to retrieves only one object.
                          if childSpline.CheckType(c4d.Onull):
                              resultJoin = c4d.utils.SendModelingCommand(command=c4d.MCOMMAND_JOIN, list=[childSpline], doc=doc)
                              if not isinstance(resultJoin, list) or not resultJoin:
                                  raise RuntimeError("Failed to perform MCOMMAND_JOIN.")
                  
                              childSpline = resultJoin[0]
                  
                          if childSpline is None:
                              raise RuntimeError("Failed to retrieves cached spline.")
                  
                          # Checks if childSpline can be interpreted as a Spline.
                          if not childSpline.GetInfo() & c4d.OBJECT_ISSPLINE and not childSpline.IsInstanceOf(c4d.Ospline) and not childSpline.IsInstanceOf(c4d.Oline):
                              return None
                  
                          return childSpline
                  

                  It seems like cloning the object and inserting it back into the scene to CurrentStateToObject it and then removing it is going to be potentially really slow.

                  It seems like it would be a lot of overhead to just get the input points. Forgive my ignorance, but do native Cinema objects face this sort of overhead? Would this amount of overhead be a limiting factor?

                  John Thomas

                  1 Reply Last reply Reply Quote 0
                  • r_giganteR
                    r_gigante
                    last edited by

                    Hi @JohnThomas, consider that spline generators using children as input are not officially supported and the solution offered, although can show from case to case performance penalties, it's the sole way to go.

                    Forgive my ignorance, but do native Cinema objects face this sort of overhead?

                    Yes, they do.

                    Would this amount of overhead be a limiting factor?

                    It heavily depends on the implementation, but I'm pretty confident to see it as a little overhead.

                    Cheers, R

                    1 Reply Last reply Reply Quote 0
                    • J
                      JohnThomas
                      last edited by

                      Thanks for the response.

                      I'll spend some time looking into it.

                      John Thomas

                      1 Reply Last reply Reply Quote 0
                      • ferdinandF
                        ferdinand
                        last edited by

                        Hi,

                        without further feedback, we will consider this thread as solved by Monday and flag it accordingly.

                        Cheers,
                        Ferdinand

                        MAXON SDK Specialist
                        developers.maxon.net

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