Problem with plugin example
-
Hi,
I think I found an issue with this:
https://github.com/PluginCafe/cinema4d_py_sdk_extended/blob/master/plugins/py-osffset_y_spline_r16/py-osffset_y_spline_r16.pyp
If the spline (or splines) are under a null and that null is the child of the offset spline object, the offsetting works as expected... all splines get moved. But if I try to change the position of the splines, for example, or anything about the objects under the null, it's not working. It just gets "stuck" in whatever state they were when they were put under the offset object. The only way to update is to take the null with the children from under the offset object and then putting it back it.Any suggestions on how to fix this? I'm guessing it must be something related to "dirty" detection, but that code is really complicated, I can't quite figure it out so far.
Thank you.
-
Hello @filipst,
Thank you for reaching out to us. The example you quoted documents itself as:
Retrieves the first child object and offset all its points on the y-axis by a specific value. Tangents are unaffected.
This plugin is not intended to look anything beyond the dirtyness of the first child.
# 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 # Checks if the dirty of the child changed opDirty |= op.IsDirty(c4d.DIRTYFLAGS_DATA | c4d.DIRTYFLAGS_MATRIX) childDirty = child.GetDirty(c4d.DIRTYFLAGS_DATA | c4d.DIRTYFLAGS_MATRIX | c4d.DIRTYFLAGS_CACHE)
To also evaluate other children for their data or other dirty states, you would have to add addtional checks here. There should also be one extra step you have to take for
DIRTYFLAGS_MATRIX
, i.e., the case that you want to react not only to data container changes of the input objects but also transform changes.GetVirtualObjects
andGetContour
will not be called for pure matrix changes on scene objects out of the box. You would have to overwrite ObjectData.CheckDirty to manually flag yourself as dirty when such event occurs so that the cache building is being invoked.Cheers,
Ferdinand -
@ferdinand said in Problem with plugin example:
Hello @filipst,
Thank you for reaching out to us. The example you quoted documents itself as:
Retrieves the first child object and offset all its points on the y-axis by a specific value. Tangents are unaffected.
This plugin is not intended to look anything beyond the dirtyness of the first child.
# 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 # Checks if the dirty of the child changed opDirty |= op.IsDirty(c4d.DIRTYFLAGS_DATA | c4d.DIRTYFLAGS_MATRIX) childDirty = child.GetDirty(c4d.DIRTYFLAGS_DATA | c4d.DIRTYFLAGS_MATRIX | c4d.DIRTYFLAGS_CACHE)
To also evaluate other children for their data or other dirty states, you would have to add addtional checks here. There should also be one extra step you have to take for
DIRTYFLAGS_MATRIX
, i.e., the case that you want to react not only to data container changes of the input objects but also transform changes.GetVirtualObjects
andGetContour
will not be called for pure matrix changes on scene objects out of the box. You would have to overwrite ObjectData.CheckDirty to manually flag yourself as dirty when such event occurs so that the cache building is being invoked.Cheers,
FerdinandThank you, I thought modifications to the child of an object were included in the detection for that object.
I'll see if I can figure it out.
Would the suggestions you gave also fix the fact that removing a child of the first child (or adding another child) doesn't update the object either or does that need to be checked a different way? -
I'm guessing there's no shortcut way to update the object whenever any change occurs in the hierarchy, right?
-
Hey @filipst,
It depends on what you would consider to be a shortcut. But in general, what I showed you above is exactly doing this.
- The cache pass of a scene is executed on each scene update events and with it your
MyObjectData::GetVirtualObjects
. - In C++, plugin authors are always expected to filter out the events where it is sensible to update their cache and otherwise just keep using the old cache (what I showed above).
- In Python there is
ObjectData.SetOptimizeCache
and "Optimize Cache" in the Python Generator object to streamline things a bit for the less technically inclined. They do both the same and evaluate the dirtiness of a node over itsDIRTYFLAGS_DATA
flag. - So, when you follow the example I have linked to, and turn off
SetOptimizeCache
, yourGVO
will already be called on pretty much everything and nothing. - It is then your job as a plugin author to filter out changes in the scene state you are interested in.
Cheers,
FerdinandTurning on and off cache optimization demonstrated with the Generator Object.
ObjectData.SetOptimizeCache
will behave identically.
- The cache pass of a scene is executed on each scene update events and with it your
-
Thank you very much!
For now I think I just commented out the part that does the "current state to object" on the hierarchy. That's the part that causes the issue I think.
I only need the first child, and it would be nice if I could get it to work similar to how the Spline Mask object works which operates on the splines even if they are under a null, but I need to understand more before being able to do that.Somewhat related, although not a SDK question, but if you don't mind, do you know why "current state to object" and "make editable" produce different results on splines? I'm not sure, but I think this started happening some versions ago, I seem to remember it was not the case.
As far as I understand, there's no equivalent to "make editable" in scripting, right? -
Hey @filipst,
please adhere to our rule for a topic being a singular subject/line of questioning.
I strongly doubt that Current State to Object (CSTO) and Make Editable (ME) were ever the same for splines; and if so, this was probably a bug. There is a fundamental difference between these two operations.
- Current State to Object: Collapses the cache of the entity it is being called upon and inserts it into the scene.
- Make Editable: Replaces an object with its (direct and uncollapsed) cache.
Aside from the obvious difference that CTSO produces a new object and ME replaces its input, there is a fundamental difference in getting the cache of something (ME) or getting the collapsed cache of something (CSTO). Caches tend to be hierarchical structures in Cinema 4D and can become very complex. A simple example would be to collapse a spline with a bend deformer attached to it.
Input:
Make Editable output (with deformer disabled for clarity):
CSTO output:
I went over the topic of caches and our geometry model here. For this hierarchy,
the Circle object will have a cache tree as follows:
+ 1: Circle (BaseObject Generator) + 2: Cache of 1: Circle (SplineObject Generator) + 3: Cache of 2: Circle (LineObject) + 4: Deform Cache of 3: Circle (LineObject)
The Circle object is a
BaseObject
generator which has aSplineObject
as its cache which itself is a generator and has aLineObject
as its cache (i.e., the discrete representation of the spline for its current interpolation settings). The bend deformer deforms this terminal node in the cache chain, theLineObject
, and not theSplineObject
.- CSTO collapses the whole cache of an object, i.e., exhausts it. In this case this means returning
4
, which includes deformation and the Bezier spline converted to its linear spline representation. CSTO can also mean joining objects in a cache, which is not represented by this simple example. - ME on the other hand returns
2
, i.e., whatever is the direct cache of the entity it has been invoked on. We do not collapse the cache of the cache and therefore neither include theLineObject
cache nor its deform cache (they are of course still implicitly generated as the cache for theSplineObject
we return because ME replaces its input object).
Cheers,
Ferdinand