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