Trouble with ExecutePasses()



  • 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 :)



  • 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).



  • 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



  • 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.



  • 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....?



  • 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.



  • 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.



  • 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.



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


Log in to reply