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
    • Register
    • Login

    Python Generator: Getting polygon data from new generators

    Cinema 4D SDK
    python sdk
    4
    6
    1.0k
    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.
    • orestiskonO
      orestiskon
      last edited by

      Hi all,
      I'm trying to see if I can access the polygon data from generators that I create within the Python Generator.
      E.g. the default python generator creates a cube, is it possible to print out the polygon count of that cube?

      GetCache() returns None as there doesn't seem to be any cache yet.
      What is the designated way to do this? Is CurrentStateToObject an optimal way?

      1 Reply Last reply Reply Quote 0
      • P
        pyr
        last edited by

        The default python generator returns a parametric object (c4d.Ocube). So you have to convert it to a editable poly in the generator itself. So you don't need a cso in your script but in the generator when using parametric objects.

        Python Generator

        import c4d
        #Welcome to the world of Python
        
        
        def main():
            c = c4d.BaseObject(c4d.Ocube)
            return c4d.utils.SendModelingCommand(command = c4d.MCOMMAND_CURRENTSTATETOOBJECT,list    = [c],
                                                         bc      = c4d.BaseContainer(),
                                                         mode    = c4d.MODELINGCOMMANDMODE_ALL,
                                                         doc     = doc,
                                                         flags   = 0)[0]
        

        script

        import c4d
        
        doc = c4d.documents.GetActiveDocument()
        gen =doc.GetActiveObject()
        print gen.GetCache()
        
        
        
        
        1 Reply Last reply Reply Quote 1
        • ferdinandF
          ferdinand
          last edited by ferdinand

          Hi,

          there are two different things here at play.

          1. Caches of objects are hierarchical (see docs). So when you want to evaluate the polygon count of your Python Generator Object (PGO) you haven to get the cache of the cube object returned by the cache of the PGO. Here is a little script that will spit out the cumulative polygon count of basically anything you throw at it.
          import c4d
          
          def get_cumlative_polygon_count(op):
              """ Returns the cumlative polygon count of the passed node and its 
               descendants. Will also inspcect caches.
          
              Args:
                  op (c4d.BaseObject): The node to evaluate the polygon count for.
          
              Returns:
                  int: The cumlative polygon count of the passed node and its 
                   descendants.
              """
              if not isinstance(op, c4d.BaseObject):
                  return 0
          
              # Op is not a polygon object, walk down the cache chain.
              if not isinstance(op, c4d.PolygonObject):
                  cache = op.GetCache()
                  res = get_cumlative_polygon_count(cache) if cache else 0
              # else get the polygon count
              else:
                  res = op.GetPolygonCount()
          
              # Evaluate the children
              for child in op.GetChildren():
                  res += get_cumlative_polygon_count(child)
              return res
          
          
          def main():
              """ 
              """
              print get_cumlative_polygon_count(op)
          
          if __name__=='__main__':
              main()
          
          1. Generator objects (e.g. a cube object) are recipes for generating objects, instantiating them does not produce any geometry. If you want to evaluate the output of a generator you have to add it to a document and execute its passes (or specifically the cache pass). As an example for your scenario:
          import c4d
          # Welcome to the world of Python
          
          
          def get_cumlative_polygon_count(op):
              """ Returns the cumlative polygon count of the passed node and its 
               descendants. Will also inspcect caches.
          
              Args:
                  op (c4d.BaseObject): The node to evaluate the polygon count for.
          
              Returns:
                  int: The cumlative polygon count of the passed node and its 
                   descendants.
              """
              if not isinstance(op, c4d.BaseObject):
                  return 0
          
              # Op is not a polygon object, walk down the cache chain.
              if not isinstance(op, c4d.PolygonObject):
                  cache = op.GetCache()
                  res = get_cumlative_polygon_count(cache) if cache else 0
              # else get the polygon count
              else:
                  res = op.GetPolygonCount()
          
              # Evaluate the children
              for child in op.GetChildren():
                  res += get_cumlative_polygon_count(child)
              return res
          
          
          def main():
              """
              """
              cube = c4d.BaseObject(c4d.Ocube)
              msg = "Cube polygon count before document execution:"
              print msg, get_cumlative_polygon_count(cube)
              temp_doc = c4d.documents.BaseDocument()
              temp_doc.InsertObject(cube)
              temp_doc.ExecutePasses(bt=None, animation=False,
                                     expressions=False, caches=True, flags=0)
              msg = "Cube polygon count after document execution:"
              print msg, get_cumlative_polygon_count(cube)
              cube.Remove()
              return cube
          

          Cheers
          zipit

          MAXON SDK Specialist
          developers.maxon.net

          1 Reply Last reply Reply Quote 1
          • M
            m_adam
            last edited by m_adam

            Hi @orestiskon

            So if you want to have a new generator within your own generator you need to evaluate this generator.

            def main():
                # Create a Cube Generator in memory
                cube = c4d.BaseObject(c4d.Ocube)
                if cube is None:
                    raise RuntimeError("Failed to create a cube")
            
                # Creates a temporary document that will be used to evaluate the cache of the object
                tempDoc = c4d.documents.BaseDocument()
                if tempDoc is None:
                    raise RuntimeError("Failed to create a temporary doc")
            
                # Inserts the cube that exists only in memory into our tempo doc
                tempDoc.InsertObject(cube)
            
                # Computes cache from the document (aka compute the cache for our cube generator)
                tempDoc.ExecutePasses(bt=c4d.threading.GeGetCurrentThread(), animation=False, expressions=False, caches=True, flags=c4d.BUILDFLAGS_EXPORT)
            
                # Retrieve a copy of the cache (don't return directly the cache, since this cache belongs to the other document)
                clonedCube = cube.GetCache().GetClone(c4d.COPYFLAGS_NONE)
                return clonedCube
            

            Cheers,
            Maxime.

            MAXON SDK Specialist

            Development Blog, MAXON Registered Developer

            1 Reply Last reply Reply Quote 1
            • orestiskonO
              orestiskon
              last edited by

              Wow much obliged for all the replies everyone, it is really helpful!
              I think evaluating in a tempdocument is what I was looking for. I have another question about best practices:

              In zipit's example the original cube is removed from the temp document after use. Is there a reason to do that? Does it help with performance and/or memory management?

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

                I did that for the same reason @m_adam created a copy in his version: A node can only be member of one document at a time and also only be inserted exactly one time into the same document (long way of saying that Cinema is monohierachical).

                Cheers
                zipit

                MAXON SDK Specialist
                developers.maxon.net

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