Plugin Cafe Homepage
Forum Home Forum Home > Plugin Cafe > SDK Help
  New Posts New Posts
  FAQ FAQ  Forum Search   Register Register  Login Login

Trouble with ExecutePasses()

 Post Reply Post Reply
Author
Message
adl architetto View Drop Down
Member
Member


Joined: 2016 May 01
Online Status: Offline
Posts: 26
Post Options Post Options   Quote adl architetto Quote  Post ReplyReply Direct Link To This Post Topic: Trouble with ExecutePasses()
    Posted: 2017 Apr 17 at 10:44pm

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


Edited by adl architetto - 2017 Apr 17 at 10:45pm
Back to Top
Andreas Block View Drop Down
Forum Moderator
Forum Moderator
Avatar

Joined: 2014 Oct 01
Location: Hannover
Online Status: Offline
Posts: 1599
Post Options Post Options   Quote Andreas Block Quote  Post ReplyReply Direct Link To This Post Posted: 2017 Apr 18 at 2:58am
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).

Cheers,
Andreas
SDK Support Engineer
Back to Top
adl architetto View Drop Down
Member
Member


Joined: 2016 May 01
Online Status: Offline
Posts: 26
Post Options Post Options   Quote adl architetto Quote  Post ReplyReply Direct Link To This Post Posted: 2017 Apr 19 at 1:31am
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



Edited by adl architetto - 2017 Apr 19 at 1:35am
Back to Top
Andreas Block View Drop Down
Forum Moderator
Forum Moderator
Avatar

Joined: 2014 Oct 01
Location: Hannover
Online Status: Offline
Posts: 1599
Post Options Post Options   Quote Andreas Block Quote  Post ReplyReply Direct Link To This Post Posted: 2017 Apr 19 at 2:26am
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.

Cheers,
Andreas
SDK Support Engineer
Back to Top
adl architetto View Drop Down
Member
Member


Joined: 2016 May 01
Online Status: Offline
Posts: 26
Post Options Post Options   Quote adl architetto Quote  Post ReplyReply Direct Link To This Post Posted: 2017 Apr 19 at 6:21am
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....?


Edited by adl architetto - 2017 Apr 19 at 6:51am
Back to Top
Andreas Block View Drop Down
Forum Moderator
Forum Moderator
Avatar

Joined: 2014 Oct 01
Location: Hannover
Online Status: Offline
Posts: 1599
Post Options Post Options   Quote Andreas Block Quote  Post ReplyReply Direct Link To This Post Posted: 2017 Apr 20 at 6:15am
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:
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.



Edited by Andreas Block - 2017 Apr 20 at 6:16am
Cheers,
Andreas
SDK Support Engineer
Back to Top
adl architetto View Drop Down
Member
Member


Joined: 2016 May 01
Online Status: Offline
Posts: 26
Post Options Post Options   Quote adl architetto Quote  Post ReplyReply Direct Link To This Post Posted: 2017 Apr 21 at 2:03am
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. 



Edited by adl architetto - 2017 Apr 21 at 2:05am
Back to Top
Andreas Block View Drop Down
Forum Moderator
Forum Moderator
Avatar

Joined: 2014 Oct 01
Location: Hannover
Online Status: Offline
Posts: 1599
Post Options Post Options   Quote Andreas Block Quote  Post ReplyReply Direct Link To This Post Posted: 2017 Apr 21 at 8:48am
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.

Cheers,
Andreas
SDK Support Engineer
Back to Top
adl architetto View Drop Down
Member
Member


Joined: 2016 May 01
Online Status: Offline
Posts: 26
Post Options Post Options   Quote adl architetto Quote  Post ReplyReply Direct Link To This Post Posted: 2017 Apr 24 at 12:05am
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!
Back to Top
 Post Reply Post Reply

Forum Jump Forum Permissions View Drop Down

Bulletin Board Software by Web Wiz Forums® version 9.61 [Free Express Edition]
Copyright ©2001-2009 Web Wiz

This page was generated in 0.109 seconds.