Messages between objects [SOLVED]
-
On 09/04/2015 at 09:24, xxxxxxxx wrote:
Originally posted by xxxxxxxx
if not link.IsInstanceOf(c4d.Opolygon) :link = link.GetCache()
This line produces an error if the linked atom is a material. I used try except...I think you'd better check the classification of the linked base list and discard all that aren't objects, in Obase classification.
Originally posted by xxxxxxxx
Another problem occured!
If the linked object is a primitiv, the dirty check only triggers once and after that the generator wont update anymore.
Could you please tell me what´s wrong with the code?You're getting the dirty checksum of the cache, not of the actual object, in the case of a primitive.
I think you'd better have 2 functions: one to get the linked object and another to get the linked geometry.Also, an object (at least an empty Null object in the case of an error) should be always returned by a generator, otherwise Cinema 4D will try to rebuild the cache again and again.
Here's the working code I came up with:
import c4d from c4d import utils, gui global dirtyCount dirtyCount = 0 def GetLink(op) : udOK = False for udID, udBC in op.GetUserDataContainer() : if udID[1].id==1 and udID[1].dtype==c4d.DTYPE_BASELISTLINK: udOK = True break if not udOK: dialog = gui.MessageDialog("No appropriate UserData available! \n" "Please insert a linkfield \n" "and activate the generator again.",c4d.GEMB_OK) op[c4d.ID_BASEOBJECT_GENERATOR_FLAG] = False return None link = op[c4d.ID_USERDATA,1] if link.GetClassification()!=c4d.Obase: dialog = gui.MessageDialog("Please insert a valid object in the user data link!",c4d.GEMB_OK) op[c4d.ID_BASEOBJECT_GENERATOR_FLAG] = False return None return link def GetGeom(op) : geom = op if not op.IsInstanceOf(c4d.Opolygon) : geom = op.GetCache() deform = geom.GetDeformCache() if deform: geom = deform return geom def main() : global dirtyCount if op[c4d.OPYTHON_OPTIMIZE] == True: dialog=gui.MessageDialog("Please uncheck Optimize Cache! \n" "and activate the generator again.",c4d.GEMB_OK) op[c4d.ID_BASEOBJECT_GENERATOR_FLAG] = False return c4d.BaseObject(c4d.Onull) link = GetLink(op) if not link: return c4d.BaseObject(c4d.Onull) #custom dirty test with linked object dirty = link.GetDirty(c4d.DIRTYFLAGS_DATA|c4d.DIRTYFLAGS_MATRIX) if dirty != dirtyCount: print "Dirty" dirtyCount = dirty op.SetDirty(c4d.DIRTYFLAGS_DATA|c4d.DIRTYFLAGS_MATRIX) else: print "Not Dirty" if not op.IsDirty(c4d.DIRTYFLAGS_DATA|c4d.DIRTYFLAGS_MATRIX) : return op.GetCache() geom = GetGeom(link) #parent virtual object null = c4d.BaseObject(c4d.Onull) child = geom.GetClone() #child.SetMg(op.GetMg()) child.InsertUnder(null) return null
-
On 09/04/2015 at 18:04, xxxxxxxx wrote:
Hi Yannick,
thanks a lot for developing this further with me!
That was the solution to differentiate the link itself and the geometry, great!
And good to know that the generator needs a least one object to return.
Two minor issues, but really minimal:
After line 20 in your code there must be another if not clause, if there is no object in the link field.
Otherwise an error occured None doesn´t have GetClassification().
And the GetGeom function needs to be called before the dirty check lines, that the deform cache could be taken into account while checking the dirty state.Again, that was very helpful thanks.
One can do a lot of nice stuff with this combination, generator and linked object.Best wishes
Martin -
On 10/04/2015 at 00:33, xxxxxxxx wrote:
Hi Martin,
You're welcome. Thanks for pointing the errors in my code.
I'll tag the topic as solved. -
On 10/04/2015 at 00:34, xxxxxxxx wrote:
Hi Yannick,
I guess I was overhasty stating that your code is the solution.
If you change an attribute of a primitiv in the link field it again wont work.
Also if you grab the handels and scale the primitiv, the generator won´t reflect this.
What else could be wrong?
Sorry to bother you again.Best wishes
Martin -
On 10/04/2015 at 00:36, xxxxxxxx wrote:
Originally posted by xxxxxxxx
I guess I was overhasty stating that your code is the solution.
If you change an attribute of a primitiv in the link field it again wont work.
Also if you grab the handels and scale the primitiv, the generator won´t reflect this.
What else could be wrong?Are you checking the dirty on the linked primitive object and not on its cache?
-
On 10/04/2015 at 01:04, xxxxxxxx wrote:
Hi Yannick,
this is driving me nuts, even if I differentiate the dirtytest within the GetGeom function and pass the value.
I´m always one step behind the update.
If you e.g. change a parameter of the primitiv numerically and press enter, nothing happens.
Thanks in advance for your patience!Martin
import c4d from c4d import utils, gui global dirtyCount dirtyCount = 0 def GetLink(op) : udOK = False for udID, udBC in op.GetUserDataContainer() : if udID[1].id==1 and udID[1].dtype==c4d.DTYPE_BASELISTLINK: udOK = True break if not udOK: dialog = gui.MessageDialog("No appropriate UserData available! \n" "Please insert a linkfield \n" "and activate the generator again.",c4d.GEMB_OK) op[c4d.ID_BASEOBJECT_GENERATOR_FLAG] = False return None link = op[c4d.ID_USERDATA,1] if not link:return None if link.GetClassification()!=c4d.Obase: dialog = gui.MessageDialog("Please insert a valid object in the user data link!",c4d.GEMB_OK) op[c4d.ID_BASEOBJECT_GENERATOR_FLAG] = False return None return link def GetGeom(op) : geom = op dirty = op.GetDirty(c4d.DIRTYFLAGS_DATA|c4d.DIRTYFLAGS_MATRIX) if not op.IsInstanceOf(c4d.Opolygon) : dirty = op.GetDirty(c4d.DIRTYFLAGS_DATA|c4d.DIRTYFLAGS_MATRIX) geom = op.GetCache() deform = geom.GetDeformCache() if deform: dirty = deform.GetDirty(c4d.DIRTYFLAGS_DATA|c4d.DIRTYFLAGS_MATRIX) geom = deform return geom,dirty def main() : global dirtyCount if op[c4d.OPYTHON_OPTIMIZE] == True: dialog=gui.MessageDialog("Please uncheck Optimize Cache! \n" "and activate the generator again.",c4d.GEMB_OK) op[c4d.ID_BASEOBJECT_GENERATOR_FLAG] = False return c4d.BaseObject(c4d.Onull) link = GetLink(op) if not link: return c4d.BaseObject(c4d.Onull) geom,dirty = GetGeom(link) #custom dirty test with linked object #dirty = link.GetDirty(c4d.DIRTYFLAGS_DATA|c4d.DIRTYFLAGS_MATRIX) if dirty != dirtyCount: dirtyCount = dirty op.SetDirty(c4d.DIRTYFLAGS_DATA|c4d.DIRTYFLAGS_MATRIX) if not op.IsDirty(c4d.DIRTYFLAGS_DATA|c4d.DIRTYFLAGS_MATRIX) : return op.GetCache() #parent virtual object null = c4d.BaseObject(c4d.Onull) child = geom.GetClone() child.InsertUnder(null) return null
-
On 10/04/2015 at 01:14, xxxxxxxx wrote:
an additional note.
This behaviour is again hierarchy dependend.
If the primitiv is above the generator in the hierarchy everything works fine.
If the primitiv is below it won´t -
On 10/04/2015 at 02:57, xxxxxxxx wrote:
It works fine for me with polygon objects, primitives, deformers etc.
2 notes on GetGeom() :
op.GetDirty() is called twice in the case of a primitive.
It would be better to add the dirty count from op.GetDirty() and deform.GetDirty().def GetGeom(op) : geom = op dirty = op.GetDirty(c4d.DIRTYFLAGS_DATA|c4d.DIRTYFLAGS_MATRIX) if not op.IsInstanceOf(c4d.Opolygon) : ~~dirty = op.GetDirty(c4d.DIRTYFLAGS_DATA|c4d.DIRTYFLAGS_MATRIX)~~ geom = op.GetCache() deform = geom.GetDeformCache() if deform: dirty = **dirty +** deform.GetDirty(c4d.DIRTYFLAGS_DATA|c4d.DIRTYFLAGS_MATRIX) geom = deform return geom,dirty
-
On 10/04/2015 at 04:13, xxxxxxxx wrote:
Hi Yannick,
thanks for the next optimization hint!
But still, the problem with the primitiv exists.
I decided to make a small video and an example file to show you what I was talking about.
I´ll send you a PM.Thanks for your staying power!
Best wishes
Martin -
On 10/04/2015 at 06:51, xxxxxxxx wrote:
Hi Martin,
Thanks for the example scene and video. I've been able to see the issue and reproduce it.
It's strange this only happens when editing the primitive attribute by hand and pressing enter.I think the problem is with GetCache() in GetGeom(). The cache of the linked primitive object hasn't been updated yet when retrieving it.
The only way to obtain the updated polygonal representation of a primitive object is to call the current state to object command. This command rebuild the cache for the passed object if needed, and then clone the polygonal cache object for you. -
On 10/04/2015 at 08:05, xxxxxxxx wrote:
Hi Yannick,
testing further I figured out that this not an update problem.
It´s a problem with what we a getting back from the generators link field.
Getting the cache with link.GetCache() from a parametric object within a linkfield
produces a polygon object within a python tag and a null object with every face as a child inside a generator object.That seems like a buggy behaviour to me.
Could you please give it a try and confirm or counter my assumption?
Best wishes
Martin -
On 10/04/2015 at 09:51, xxxxxxxx wrote:
Originally posted by xxxxxxxx
testing further I figured out that this not an update problem.
It´s a problem with what we a getting back from the generators link field.
Getting the cache with link.GetCache() from a parametric object within a linkfield
produces a polygon object within a python tag and a null object with every face as a child inside a generator object.That seems like a buggy behaviour to me.
Could you please give it a try and confirm or counter my assumption?
I can't reproduce this strange behavior.
Have you tried the current state to object modelling command solution I explained in my previous post? It seems to work fine in all situations.Also, please start a new topic if you have different questions than the initial one. This make it easier to follow the topic and search the forum.
-
On 10/04/2015 at 13:44, xxxxxxxx wrote:
The strange behaviour was gone after I started a new Cinema 4d session and built up a new scene.
Maybe a corruption in between development...Yannick, I tried your current state to object suggestion, but then I won´t get a valid deform cache from the object nor the deformed polygon object.
With [c4d.MDATA_CURRENTSTATETOOBJECT_NOGENERATE] set to False I should get a deformed object from current state to object.Could you please post your solution?
I´m a little lost at the moment...
This thread is really not solved for me , sorryBest wishes
Martin -
On 13/04/2015 at 09:09, xxxxxxxx wrote:
Now it is solved,
the polygonal representation from the parametric object should be taken from current state to object.
(like Yannick suggested)
but the dirty state needs to be read from the cache.Yannick, thanks!
Could you please explain why the cache hasn´t been updated ?
Best wishes
Martinimport c4d from c4d import utils, gui global dirtyCount dirtyCount = 0 def GetLink(op) : udOK = False for udID, udBC in op.GetUserDataContainer() : if udID[1].id==1 and udID[1].dtype==c4d.DTYPE_BASELISTLINK: udOK = True break if not udOK: dialog = gui.MessageDialog("No appropriate UserData available! \n" "Please insert a linkfield \n" "and activate the generator again.",c4d.GEMB_OK) op[c4d.ID_BASEOBJECT_GENERATOR_FLAG] = False return None link = op[c4d.ID_USERDATA,1] if not link:return None if link.GetClassification()!=c4d.Obase: dialog = gui.MessageDialog("Please insert a valid object in the user data link!",c4d.GEMB_OK) op[c4d.ID_BASEOBJECT_GENERATOR_FLAG] = False return None return link def GetGeom(op) : geom = op dirty = op.GetDirty(c4d.DIRTYFLAGS_DATA|c4d.DIRTYFLAGS_MATRIX) if not op.IsInstanceOf(c4d.Opolygon) : settings = c4d.BaseContainer() settings[c4d.MDATA_CURRENTSTATETOOBJECT_NOGENERATE] = False settings[c4d.MDATA_CURRENTSTATETOOBJECT_KEEPANIMATION] = True settings[c4d.MDATA_CURRENTSTATETOOBJECT_INHERITANCE] = False polylist = utils.SendModelingCommand(command= c4d.MCOMMAND_CURRENTSTATETOOBJECT, list= [op.GetClone()], mode =c4d.MODELINGCOMMANDMODE_ALL, bc = settings, doc= doc) if not polylist : return None geom = polylist[0] if op.GetCache().GetDeformCache() : deform = op.GetCache().GetDeformCache() dirty = dirty + deform.GetDirty(c4d.DIRTYFLAGS_DATA|c4d.DIRTYFLAGS_MATRIX) print dirty, "parametric deform" if op.GetDeformCache() : deform = geom.GetDeformCache() print dirty,"polygonal deform " dirty = dirty + deform.GetDirty(c4d.DIRTYFLAGS_DATA|c4d.DIRTYFLAGS_MATRIX) geom = deform return geom,dirty def main() : global dirtyCount if op[c4d.OPYTHON_OPTIMIZE] == True: dialog=gui.MessageDialog("Please uncheck Optimize Cache! \n" "and activate the generator again.",c4d.GEMB_OK) op[c4d.ID_BASEOBJECT_GENERATOR_FLAG] = False return c4d.BaseObject(c4d.Onull) link = GetLink(op) if not link: return c4d.BaseObject(c4d.Onull) geom,dirty = GetGeom(link) if not geom: return c4d.BaseObject(c4d.Onull) #custom dirty test with linked object if dirty != dirtyCount: dirtyCount = dirty op.SetDirty(c4d.DIRTYFLAGS_DATA|c4d.DIRTYFLAGS_MATRIX) if not op.IsDirty(c4d.DIRTYFLAGS_DATA|c4d.DIRTYFLAGS_MATRIX) : return op.GetCache() #parent virtual object null = c4d.BaseObject(c4d.Onull) child = geom.GetClone() child.InsertUnder(null) return null
-
On 13/04/2015 at 09:32, xxxxxxxx wrote:
The initial question for this topic has been solved: messaging between the generator and its linked object, more precisely getting the dirty state from the linked object (the original title of the topic isn't event not meaningful).
Please create a new thread for new questions. -
On 13/04/2015 at 09:54, xxxxxxxx wrote:
Feel free to rename this thread to suit the topic, Yannick, no problem.
That´s all not that meaningful...enjoy your finishing time
martin -
On 14/04/2015 at 06:19, xxxxxxxx wrote:
Hi Martin,
I'd really like to help you but we need to have an organized forum.
You can create a new topic with the current script for the Python generator, the issues with it and I'll be happy to help you .