Maxon Developers Maxon Developers
    • Documentation
      • Cinema 4D Python API
      • Cinema 4D C++ API
      • Cineware 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

    Problem with plugin example

    Cinema 4D SDK
    2023 python
    2
    7
    1.1k
    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.
    • F
      filipst
      last edited by

      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.

      ferdinandF 1 Reply Last reply Reply Quote 0
      • ferdinandF
        ferdinand @filipst
        last edited by ferdinand

        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)
        

        Link to code

        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 and GetContour 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

        MAXON SDK Specialist
        developers.maxon.net

        F 1 Reply Last reply Reply Quote 0
        • F
          filipst @ferdinand
          last edited by

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

          Link to code

          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 and GetContour 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

          Thank 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?

          1 Reply Last reply Reply Quote 0
          • F
            filipst
            last edited by

            I'm guessing there's no shortcut way to update the object whenever any change occurs in the hierarchy, right?

            1 Reply Last reply Reply Quote 0
            • ferdinandF
              ferdinand
              last edited by ferdinand

              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.

              1. The cache pass of a scene is executed on each scene update events and with it your MyObjectData::GetVirtualObjects.
              2. 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).
              3. 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 its DIRTYFLAGS_DATA flag.
              4. So, when you follow the example I have linked to, and turn off SetOptimizeCache, your GVO will already be called on pretty much everything and nothing.
              5. It is then your job as a plugin author to filter out changes in the scene state you are interested in.

              Cheers,
              Ferdinand

              Turning on and off cache optimization demonstrated with the Generator Object. ObjectData.SetOptimizeCache will behave identically.

              MAXON SDK Specialist
              developers.maxon.net

              1 Reply Last reply Reply Quote 0
              • F
                filipst
                last edited by

                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?

                ferdinandF 1 Reply Last reply Reply Quote 0
                • ferdinandF
                  ferdinand @filipst
                  last edited by ferdinand

                  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:
                  735753e6-3276-4ae8-b19a-369d5e9aaf01-image.png

                  Make Editable output (with deformer disabled for clarity):

                  c20a09cd-83a4-47c4-bd4c-7dd774733144-image.png

                  CSTO output:

                  787e44c3-bb86-4efd-9633-94271266326d-image.png

                  I went over the topic of caches and our geometry model here. For this hierarchy,

                  5bb9fe31-178b-4967-821f-ebfccb153e47-image.png

                  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 a SplineObject as its cache which itself is a generator and has a LineObject 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, the LineObject, and not the SplineObject.

                  • 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 the LineObject cache nor its deform cache (they are of course still implicitly generated as the cache for the SplineObject we return because ME replaces its input object).

                  Cheers,
                  Ferdinand

                  MAXON SDK Specialist
                  developers.maxon.net

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