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

    Trouble with ExecutePasses()

    SDK Help
    0
    9
    1.0k
    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.
    • H
      Helper
      last edited by

      On 17/04/2017 at 22:44, xxxxxxxx wrote:

      User Information:
      Cinema 4D Version:   17 
      Platform:      
      Language(s) :     C++  ;

      ---------
      Hello,
      I am trying to get volumetric data of an animated object at arbitrary frames. As far as i understand, i need to set the frames and call ExecutePasses(). however, that triggers a break....

      here's my code

      	//get frame and fps
      	Int32 fps = hh->GetDocument()->GetFps(); 
      	BaseTime time = hh->GetDocument()->GetTime();
      	Int32 frame = time.GetFrame(fps);
        
      	// increment frame and set time
      	frame+=10;
        
      	hh->GetDocument()->SetTime(BaseTime(frame, fps));
      	hh->GetDocument()->ExecutePasses(bt, true, true, true, BUILDFLAGS_0);
      

      Any help appreciated 🙂

      1 Reply Last reply Reply Quote 0
      • H
        Helper
        last edited by

        On 18/04/2017 at 02:58, xxxxxxxx wrote:

        Hi,

        unfortunately you are not telling us, where you try to execute the posted code. From the use of "hh" (HierarchyHelp?) I can only assume, you are trying to do this in GetVirtualObjects() of an ObjectData plugin. That would not be a good idea, as you are trying to animate the document, while C4D is in the middle of evaluating it.

        If you need to do something like this in GetVirtualObjects() (or similar places like Execute(), GetContour(), ModifyObject(), similar for TagData, ...), you either need to clone the document or set up a new doc and copy the needed stuff into it. Then animate the new doc.

        One more point: Depending on your needs and use-case (basically if your data is based on the outcome/state of previous frames) you might need to pre-roll (i.E. call ExecutePasses() for all previous frames, too).

        1 Reply Last reply Reply Quote 0
        • H
          Helper
          last edited by

          On 19/04/2017 at 01:31, xxxxxxxx wrote:

          Hi Andreas. Yes it is an ObjectData plugin, but the call hierearchy is this:

          GetVirtualObjects(BaseObject * op, HierarchyHelp * hh) 
          

          calls

          Recurse(HierarchyHelp * hh, BaseContainer * bc, BaseThread * bt, BaseObject * main, BaseObject * op, const Matrix & ml) 
          

          calls

          static PolygonObject* BuildPolyHull(PolygonObject* op, BaseContainer* bc, HierarchyHelp* hh, BaseThread* bt)
          

          it is in BuildPolyHull() that the ExecutePasses() is called...

          I guess i should copy the doc

          1 Reply Last reply Reply Quote 0
          • H
            Helper
            last edited by

            On 19/04/2017 at 02:26, xxxxxxxx wrote:

            Hi,

            as far as I understand your last post, it is indeed as I assumed and you are calling ExecutePasses() within GetVirtualObjects(). It doesn't matter if there's an arbitrary number of call levels in between. You'll need to look into the suggestions from my last post.

            1 Reply Last reply Reply Quote 0
            • H
              Helper
              last edited by

              On 19/04/2017 at 06:21, xxxxxxxx wrote:

              Yes Andreas, you were right. 
              for the record, this is how i'm copying the document

              	BaseDocument * doc = BaseDocument::Alloc();
              	*doc = *hh->GetDocument();
              

              not entirely sure it's the right way, but it no longer gives any error.

              I'm a bit mystified about how the copy operator works for the BaseDocument class. Are all the document objects copied? if so, if i have BaseObject * op in the original BaseDocument * bd, how do i find the copy of op in the copy of bd....?

              1 Reply Last reply Reply Quote 0
              • H
                Helper
                last edited by

                On 20/04/2017 at 06:15, xxxxxxxx wrote:

                Hi,

                C4D doesn't make use of copy constructors, instead you use either CopyTo() or (more suited in your case) GetClone(). I suggest to also peek into the C4DAtom manual.
                So basically:

                BaseDocument *myDoc = hh->GetDocument().GetClone();
                if (myDoc == nullptr) // never forget nullptr checks
                	// handle error
                // have fun with the cloned doc
                

                For the other part of the question, I'd actually suggest to create a new thread, but as we are here, a few notes/ideas on that as well:

                In order to identify the object in the new doc, there are several approaches, depending on your needs.

                One could be to only clone the needed object into a new scene, instead of cloning the entire scene. In this case IsolateObjects() could help immensely.

                Another approach could be the use the GeMarker system, although I have to admit, I never used it, especially not across multiple documents.
                There are a few threads on this topic though:
                Unique identification of scene elements?
                UniqueObjectId,GetMarkerStampEx,GetMarker
                Also BaseList2D manual contains a few words on this topic.

                Or you could use "custom markers" by for example writing your plugin ID (some value with plugin ID as ID) into the BaseContainer of the object(s) you want to identify. In this case you should remove the entry from the original scene, when you are done (not only, because you will need it, but also for good house keeping).

                As I said, just a few ideas, if you have further issues with this, please let us discuss it in a new thread.

                1 Reply Last reply Reply Quote 0
                • H
                  Helper
                  last edited by

                  On 21/04/2017 at 02:03, xxxxxxxx wrote:

                  Hi Andreas, thanks for the pointers. 
                  here's my test setup. I have a cube that i have animated it's points, without changing its modeling axis. what i'm after is to read the points at frame 0 and frame 10, and insert them all into a new PolygonObject. What i'm expecting is to have 16 non-overlapping vertices.

                  here's my test code, that doesn't update.

                  	PolygonObject			*pp = nullptr; //create return object
                  	Vector*					out_Vertices = nullptr; //return points
                  	
                  	//get source scene document
                  	BaseDocument * bd = hh->GetDocument();
                    
                  	//read time info from source scene
                  	Int32 fps = bd ->GetFps();
                  	BaseTime time = bd->GetTime();
                  	Int32 frame = time.GetFrame(fps);
                    
                  	//get object clone
                  	BaseObject *clone = (BaseObject* )op->GetClone(COPYFLAGS_0,nullptr);
                    
                  	//isolate objects and move to new document
                  	AtomArray * aa = AtomArray::Alloc();
                  	aa->Append(clone);
                  	BaseDocument * doc = IsolateObjects(bd, *aa);
                    
                  	//set time to new document
                  	doc->SetFps(fps);
                  	doc->SetTime(time);
                    
                  	//container for all instances
                  	std::vector<Mesh> meshes;
                  	meshes.push_back(Mesh(ToPoly(clone)));
                    
                  	// increment frame and set time
                  	int fr_inc=10;
                  	doc->SetTime(BaseTime(frame + fr_inc, fps));
                  	doc->ExecutePasses(bt, true, true, true, BUILDFLAGS_0);
                  	meshes.push_back(Mesh(ToPoly(clone)));
                    
                  	//free memory
                  	BaseDocument::Free(doc);
                  	AtomArray::Free(aa);
                  	BaseObject::Free(clone);
                    
                  	// allocate main object
                  	pp = PolygonObject::Alloc(meshes[0].points.size()*2, meshes[0].edges.size());
                  	out_Vertices = pp->GetPointW();
                    
                  	//build mesh points at frame 0;
                  	for (int i = 0; i < meshes[0].points.size(); i++) {
                  		out_Vertices[i] = meshes[0].points[i];
                  	}
                  	//build mesh points at frame 10;
                  	for (int i = 0; i < meshes[1].points.size(); i++) {
                  		out_Vertices[i + meshes[0].points.size()] = meshes[1].points[i];
                  	}
                    
                  	// update object as point geometry has changed
                  	pp->Message(MSG_UPDATE);
                  	return pp;
                  

                  What i'm getting instead is two overlapping sets of 8 vertices, meaning that ExecutePasses() didn't animate the cloned object in the cloned document.

                  1 Reply Last reply Reply Quote 0
                  • H
                    Helper
                    last edited by

                    On 21/04/2017 at 08:48, xxxxxxxx wrote:

                    I haven't had time to test your code, yet. But as weekend's nearing, I'd like to share a thought:
                    You are cloning the object before calling IsolateObjects(). This is not only not needed (as IsolateObjects() creates copies), but might well be the culprit. Especially as it's not in any document. I'd say, try to simply append op to aa.

                    1 Reply Last reply Reply Quote 0
                    • H
                      Helper
                      last edited by

                      On 24/04/2017 at 00:05, xxxxxxxx wrote:

                      Hi Andreas.  It seems that you were right again, IsolateObjects() does create copies. For some reason, i was assuming that only a pointer was passed to the new document.

                      So instead i used BaseDocument::InsertObject() function. that way i can retain control over the object itself. (i don't know how to get access to the objects cloned by IsolateObjects() as of yet)

                      so this version of the code works

                      	//get source scene document
                      	BaseDocument * bd = hh->GetDocument();
                        
                      	//read time info from source scene
                      	Int32 fps = bd ->GetFps();
                      	BaseTime time = bd->GetTime();
                      	Int32 frame = time.GetFrame(fps);
                        
                      	//create object clone
                      	BaseObject *clone = static_cast<BaseObject*>(op->GetClone(COPYFLAGS_0,nullptr));
                        
                      	//create new dummy document
                      	BaseDocument * doc = BaseDocument::Alloc();
                        
                      	//set time to new scene
                      	doc->SetFps(fps);
                      	doc->SetTime(time);
                        
                      	//insert clone in new scene
                      	doc->InsertObject(clone, nullptr, nullptr);
                        
                      	//container for all instances
                      	std::vector<Mesh> meshes;
                        
                      	// increment frame and set time
                      	for (int f = strframe; f < endframe+1; f += frame_incr) {
                      		doc->SetTime(BaseTime(f, fps));
                      		doc->ExecutePasses(bt, true, true, true, BUILDFLAGS_0);
                      		meshes.push_back(Mesh(ToPoly(clone)));
                      	}
                      

                      thanks for the help! cheers!

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