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

    Why won't my python generator update? R2024

    Cinema 4D SDK
    python s26 windows
    3
    5
    983
    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.
    • S
      SweepingMotion
      last edited by

      I'm using user data to change rotations in a python generator. But it doesn't seem to want to update when I play the timeline? Should I add anything special to the script?

      from typing import Optional
      import c4d
      from c4d import utils
      
      doc: c4d.documents.BaseDocument # The document evaluating this python generator
      op: c4d.BaseObject # The python generator
      hh: Optional["PyCapsule"] # A HierarchyHelp object, only defined when main is executed
      
      distance = op[c4d.ID_USERDATA,1]
      offset = op[c4d.ID_USERDATA,2]
      rotation = op[c4d.ID_USERDATA,3]
      
      def main() -> c4d.BaseObject:
      
          # create hierarchy of nulls
      
          points = 100
          points_list = []
      
          for p in range(points):
              pt = c4d.BaseObject(c4d.Onull)
              pt.SetParameter(c4d.NULLOBJECT_DISPLAY,c4d.NULLOBJECT_DISPLAY_SPHERE,c4d.DESCFLAGS_SET_NONE)
      
              if p==0:
                  points_list.append(pt)
              else:
                  pt.InsertUnder(points_list[p-1])
                  points_list.append(pt)
      
          # adjust position and rotation
      
      
          for i,pt in enumerate(points_list[::-1]):
      
              off = c4d.Vector(distance * i,0,0 )
              mg = pt.GetMg()
              mg.off = off
              print(rotation.x)
              rm = c4d.utils.HPBToMatrix(rotation)
              pt.SetMg(mg * rm)
      
      
      
      
      
      
          return points_list[0]
      
      
      
      
      
      
      
      
      
      bacaB ferdinandF 2 Replies Last reply Reply Quote 0
      • bacaB
        baca @SweepingMotion
        last edited by

        Hi @SweepingMotion,

        There's no time dependency in the code.

        Most probably you're trying to animate with parameters, so you need to put user data getters under the main() function.

            distance = op[c4d.ID_USERDATA,1]
            offset = op[c4d.ID_USERDATA,2]
            rotation = op[c4d.ID_USERDATA,3]
        

        In some specific cases it's also required to uncheck "Optimize Cache" checkbox.

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

          Hello @SweepingMotion ,

          Welcome to the Plugin Café forum and the Cinema 4D development community, it is great to have you with us!

          Getting Started

          Before creating your next postings, we would recommend making yourself accustomed with our Forum and Support Guidelines, as they line out details about the Maxon SDK Group support procedures. Of special importance are:

          • Support Procedures: Scope of Support: Lines out the things we will do and what we will not do.
          • Support Procedures: Confidential Data: Most questions should be accompanied by code but code cannot always be shared publicly. This section explains how to share code confidentially with Maxon.
          • Forum Structure and Features: Lines out how the forum works.
          • Structure of a Question: Lines out how to ask a good technical question. It is not mandatory to follow this exactly, but you should follow the idea of keeping things short and mentioning your primary question in a clear manner.

          About your First Question

          There are two layers to your question so to speak. Let us start with the outer more abstract layer.

          What you are trying to do here, have the object update every time the time changes, is not an intended functionality of generator objects. And while you can achieve this more or less directly, this will be quite costly. It is fine when you do this for a couple of objects which you do not ship as plugins, but for everything else, you should do this properly. Th best way would be to expose an animatable parameter Time on the object, akin to what the Explosion deformer does for example. Updates of generator caches should always be tied to data changes on scene elements, either the cache holding element itself, or one of its inputs (things being "dirty" as Cinema calls it).

          The second layer to this is object dirtiness and evaluating when to build the cache. You have probably ticked Optimize Cache in your generator, which will cause it only to update when its data container is dirty. In the video below I demonstrate the effect. We also have talked about the subject of evaluating dirtiness multiple times, a good starting point could be this answer of mine.

          Fig. I: Unticking the cache optimization will cause the generator cache to react to time changes. But that is only an indirect effect, as unticking that option means that your cache is build every time Cinema 4D asks a scene to update itself (which can happen very often).

          And while as indicated above you can take the performance penalty of just always building your cache, you should consider either the parameter route as suggested by @baca or done by the explosion deformer, or build yourself a dirty condition which checks if the time has changed (or the data container is dirty) since the last time you build the cache (see the link from above for details).

          Cheers,
          Ferdinand

          Code:

          """Returns a cube object that is rotated based on the time of the document it is contained in.
          
          I used this script in the video above.
          """
          import c4d
          
          op: c4d.BaseObject # The Python generator object.
          
          def main() -> c4d.BaseObject:
              cube: c4d.BaseObject = c4d.BaseObject(c4d.Ocube)
              if not cube:
                  return c4d.BaseObject(c4d.Onull)
          
              t: float = op.GetDocument().GetTime().Get()
              cube.SetMg(c4d.utils.MatrixRotX(t))
              return cube
          

          MAXON SDK Specialist
          developers.maxon.net

          bacaB 1 Reply Last reply Reply Quote 0
          • bacaB
            baca @ferdinand
            last edited by

            @ferdinand I think issue is only with user data variables, because those are not being updated during playback, once they are out of main() function

            Just a guess, because there's no sample project.
            It probably should be like so:

            from typing import Optional
            import c4d
            from c4d import utils
            
            doc: c4d.documents.BaseDocument # The document evaluating this python generator
            op: c4d.BaseObject # The python generator
            hh: Optional["PyCapsule"] # A HierarchyHelp object, only defined when main is executed
            
            def main() -> c4d.BaseObject:
                distance = op[c4d.ID_USERDATA,1]
                offset = op[c4d.ID_USERDATA,2]
                rotation = op[c4d.ID_USERDATA,3]
            
                # create hierarchy of nulls
                points = 100
                points_list = []
            
                for p in range(points):
                    pt = c4d.BaseObject(c4d.Onull)
                    pt.SetParameter(c4d.NULLOBJECT_DISPLAY,c4d.NULLOBJECT_DISPLAY_SPHERE,c4d.DESCFLAGS_SET_NONE)
            
                    if p==0:
                        points_list.append(pt)
                    else:
                        pt.InsertUnder(points_list[p-1])
                        points_list.append(pt)
            
                # adjust position and rotation
                for i,pt in enumerate(points_list[::-1]):
                    off = c4d.Vector(distance * i,0,0 )
                    mg = pt.GetMg()
                    mg.off = off
                    print(rotation.x)
                    rm = c4d.utils.HPBToMatrix(rotation)
                    pt.SetMg(mg * rm)
            
                return points_list[0]
            
            1 Reply Last reply Reply Quote 0
            • i_mazlovI i_mazlov referenced this topic on
            • S
              SweepingMotion
              last edited by

              @baca @ferdinand Thank you both.

              It was the fact that the user data was not collected in the main function. Silly I didn't catch that.
              It's working fine now.

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