Python Generator: Getting polygon data from new generators



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



  • 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()
    
    
    
    


  • 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



  • 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.



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



  • 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


Log in to reply