Advertisement
nux95

Cinema 4D - PoseGhost Script 1.7

Sep 22nd, 2012
191
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
  1. # coding: UTF-8
  2. #
  3. # Copyright (C) 2012, Athanasios Pozantzis
  4. # Copyright (C) 2012, Niklas Rosenstein (rewrite)
  5. #
  6. # Changelog (newest at top)
  7. # -------------------------
  8. #
  9. # v1.7 September 22, 2012 (Niklas Rosenstein):
  10. #   - Fixed bug with the *find_object* function. (Invoked error with the T-Rex
  11. #     character from the Content browser).
  12. #   - Fixed bug with finding available Sketch & Toon video post (which was
  13. #     thought to be fixed in 1.5)
  14. #   - *find_object* has a new parameter `include_toplevel`.
  15. #
  16. # v1.6 September 22, 2012 (Niklas Rosenstein):
  17. #   - Name of the resulting ghost-object is now correct.
  18. #   - The added material is now included into the undo-step.
  19. #   - After the script is executed, the selected object is now the source-object
  20. #     and not the resulting ghost-object.
  21. #   - The flicker when executing was fixed. Instead of using a temporary
  22. #     document, the *join_hierarchy* function now uses a modeling-command.
  23. #   - The resulting ghost-object is now inserted *after* the source object,
  24. #     no longer before it.
  25. #
  26. # v1.5 September 22, 2012 (Niklas Rosenstein):
  27. #   - Complete rewrite
  28. #   - Abstraction of components
  29. #   - A bug has been fixed, where a second Sketch & Toon video post was created
  30. #     when the avaialble video post was not the first element in the list.
  31. #   - HyperNURBS are now reactivated if they were activated when running the
  32. #     script. Turned off HyperNURBS will stay turned off.
  33. #   - The whole script is now merged into a single undo-step.
  34. #   - Hidden objects are no more included in the resulting ghost-object.
  35. #
  36. # v1.4 September 22, 2012 (Athanasios Pozantzis):
  37. #   - Initial version
  38.  
  39. import c4d
  40.  
  41. # Missing Symbols in the c4d module.
  42. VPsketchandtoon = 1011015
  43. Tsketchandtoon = 1011012
  44. Msketchandtoon = 1011014
  45.  
  46. def collect_objects(root, doc=None, callback=lambda x: True):
  47.     """ *Generator*. Collects all objects starting from *root* recursively that
  48.        match by the passed callback. If root is None, the document must have
  49.        been passed to start from the top-level of the hierarchy. The passed
  50.        object for *root* can be a `c4d.BaseList2D` instance, but if it is None
  51.        and the document is used, it will search for the objects in the Object
  52.        Manager. """
  53.  
  54.     def procedure(object, callback):
  55.         if callback(object): yield object
  56.         for child in object.GetChildren():
  57.             for sub in procedure(child, callback):
  58.                 yield sub
  59.  
  60.     if root:
  61.         for sub in procedure(root, callback):
  62.             yield sub
  63.     else:
  64.         for object in doc.GetObjects():
  65.             for sub in procedure(object, callback):
  66.                 yield sub
  67.  
  68. def find_object(root, callback, include_toplevel=False):
  69.     """ Finds an object in the hierarchy of *root* that matches the passed
  70.        callback. When True was passed for *include_toplevel*, the function
  71.        will search including on the same level as the root-object. (First,
  72.        previous elements are scanned, then the passed objects' hierarchy,
  73.        then new elements). """
  74.     if not root: return None
  75.  
  76.     def procedure(object):
  77.         if callback(object): return object
  78.         for child in object.GetChildren():
  79.             child = find_object(child)
  80.             if child: return child
  81.         return None
  82.  
  83.     if include_toplevel:
  84.         start = root
  85.         prev  = start.GetPred()
  86.         while prev:
  87.             start = prev
  88.             prev  = start.GetPrev()
  89.  
  90.         while start:
  91.             object = procedure(start)
  92.             if object: return object
  93.             start = start.GetNext()
  94.     else:
  95.         return procedure(root)
  96.  
  97. def filter_hierarchy(root, callback, rwnull=True):
  98.     """ Filters a hierarchy, which means to remove all objects that do not
  99.        match the passed callback. *rwnull* stands for "replace with null".
  100.        If this parameter is True (by default) and an object is about to be
  101.        removed from the hierarchy, it is replaced by a Null object in case
  102.        it has children. The passed callback must return True to notify
  103.        an object needs to be removed. """
  104.     children = root.GetChildren()
  105.     if callback(root):
  106.         if not children:
  107.             root.Remove()
  108.             return
  109.         null = c4d.BaseObject(c4d.Onull)
  110.         null.SetName(root.GetName())
  111.         for child in children:
  112.             child.InsertUnder(null)
  113.         if root.GetUp() or root.GetPred() or root.GetNext():
  114.             null.InsertAfter(root)
  115.         root.Remove()
  116.         root = null
  117.  
  118.     for child in children:
  119.         filter_hierarchy(child, callback)
  120.  
  121. def delete_tags(object, keep=lambda x: False, delete=lambda x: True):
  122.     """ Iterates over all tags of the passed *object* and determines wether
  123.        the tag should be kept or not. This is determined by calling the passed
  124.        *keep* and *delete* functions. When the former returns True, the tag
  125.        is kept. If not, the latter must return True to delete it. Both
  126.        functions are passed a `c4d.BaseTag` instance. """
  127.  
  128.     tag = object.GetFirstTag()
  129.     while tag:
  130.         next = tag.GetNext()
  131.         if not keep(tag) and delete(tag):
  132.             tag.Remove()
  133.         tag = next
  134.  
  135. def polygonize_objects(objects, hierarchy=True):
  136.     """ Polygonizes the hierarchy of the passed `c4d.BaseObject` instances
  137.        with a little trick using a temporary `c4d.BaseDocument`. The
  138.        full hierarchies are used, except *hierarchy* is set to False. """
  139.  
  140.     flags = c4d.COPYFLAGS_NO_MATERIALPREVIEW
  141.     if not hierarchy:
  142.         flags |= c4d.COPYFLAGS_NO_HIERARCHY
  143.  
  144.     # Create a new temporary document and insert a clone of the passed objects
  145.     # into it.
  146.     doc = c4d.documents.BaseDocument()
  147.     for object in objects:
  148.         if object.GetDocument():
  149.             object = object.GetClone(flags)
  150.         doc.InsertObject(object)
  151.  
  152.     # Polygonize the document, obtain the objects, release them from the
  153.     # document and return them.
  154.     new_doc = doc.Polygonize()
  155.     objects = new_doc.GetObjects()
  156.  
  157.     # Release all original objects from the temporary document.
  158.     for object in doc.GetObjects():
  159.         object.Remove()
  160.  
  161.     # Release all polygonized objects from the polygonized document.
  162.     for object in objects:
  163.         object.Remove()
  164.  
  165.     return objects
  166.  
  167. def join_hierarchy(object, doc=None):
  168.     """ Joins the passed objects' hierarchy into one using a Modeling Command.
  169.        """
  170.     new_object = c4d.utils.SendModelingCommand(c4d.MCOMMAND_JOIN, [object])[0]
  171.     return new_object
  172.  
  173. def apply_options(doc, poly):
  174.     """ Applies the general options for the Ghost object. """
  175.     dtag = poly.MakeTag(c4d.Tdisplay)
  176.     dtag[c4d.DISPLAYTAG_AFFECT_DISPLAYMODE] = True
  177.     dtag[c4d.DISPLAYTAG_SDISPLAYMODE] = c4d.DISPLAYTAG_SDISPLAY_HIDDENLINE
  178.  
  179.     def apply_snt(doc, poly):
  180.         # Change an option on the display-tag.
  181.         dtag[c4d.DISPLAYTAG_WDISPLAYMODE] = c4d.DISPLAYTAG_WDISPLAY_SKELETON
  182.  
  183.         # Find the first Sketch & Toon Video Post effect, or insert one if it does
  184.         # not exist.
  185.         rd = doc.GetActiveRenderData()
  186.         vp = find_object(
  187.             rd.GetFirstVideoPost(),
  188.             lambda x: x.CheckType(VPsketchandtoon),
  189.             include_toplevel=True
  190.         )
  191.  
  192.         if not vp:
  193.             vp = c4d.BaseList2D(VPsketchandtoon)
  194.             rd.InsertVideoPostLast(vp)
  195.  
  196.         # Create a new material for the Sketch & Toon editor outline.
  197.         name = poly.GetName()
  198.         mat = c4d.BaseMaterial(Msketchandtoon)
  199.         mat.SetName(name + " Material")
  200.         doc.InsertMaterial(mat)
  201.         doc.AddUndo(c4d.UNDOTYPE_NEW, mat)
  202.         tag = poly.MakeTag(Tsketchandtoon)
  203.         doc.AddUndo(c4d.UNDOTYPE_NEW, tag)
  204.         tag.SetName(name + " Tag")
  205.         tag[c4d.OUTLINEMAT_LINE_DEFAULT_MAT_V] = mat
  206.  
  207.         # Set the required information.
  208.         vp[c4d.OUTLINEMAT_EDLINES_SHOWLINES] = True
  209.         vp[c4d.OUTLINEMAT_EDLINES_REDRAW_FULL] = True
  210.         vp[c4d.OUTLINEMAT_EDLINES_LINE_OBJECTS_MODE] = 0 #include
  211.         vp[c4d.OUTLINEMAT_EDLINES_LINE_OUTLINE] = False
  212.         vp[c4d.OUTLINEMAT_EDLINES_LINE_CREASE] = False
  213.         vp[c4d.OUTLINEMAT_EDLINES_LINE_MATERIAL] = False
  214.         vp[c4d.OUTLINEMAT_EDLINES_LINE_INTERSECTION] = False
  215.         vp[c4d.OUTLINEMAT_EDLINES_LINE_BORDER] = False
  216.         vp[c4d.OUTLINEMAT_EDLINES_LINE_EDGES] = False
  217.         vp[c4d.OUTLINEMAT_EDLINES_LINE_FOLD] = True
  218.         vp[c4d.OUTLINEMAT_SCENE_AA] = 0
  219.  
  220.         lst = vp[c4d.OUTLINEMAT_EDLINES_LINE_OBJECTS] or c4d.InExcludeData()
  221.         lst.InsertObject(poly, 0)
  222.         vp[c4d.OUTLINEMAT_EDLINES_LINE_OBJECTS] = lst
  223.  
  224.     def apply_alt(doc, poly):
  225.         poly[c4d.ID_BASEOBJECT_XRAY] = True
  226.  
  227.     if c4d.modules.CheckSketch():
  228.         apply_snt(doc, poly)
  229.     else:
  230.         apply_alt(doc, poly)
  231.  
  232. def main():
  233.     """ The final procedure. """
  234.  
  235.     if not op:
  236.         c4d.gui.MessageDialog('Please select exactly one object.')
  237.         return False
  238.  
  239.     # Information for future use.
  240.     fps = doc.GetFps()
  241.     time = doc.GetTime()
  242.     frame = time.GetFrame(fps)
  243.  
  244.     # This list will be filled with all HyperNURBS objects contained in the
  245.     # hierarchy of the selected object. They need to be turned off before
  246.     # converting the hierarchy to a ghost.
  247.     hypernurbs_objects = []
  248.  
  249.     # Fill the HyperNURBS-objects list and turn off all of them.
  250.     for hn in collect_objects(op, callback=lambda x: x.CheckType(c4d.Osds)):
  251.         hypernurbs_objects.append([hn, hn.GetDeformMode()])
  252.         hn.SetDeformMode(False)
  253.  
  254.     # Clone the hierarchy and sort out unnecessary objects.
  255.     object = op.GetClone()
  256.     filter_hierarchy(object, lambda x: x.GetEditorMode() == c4d.MODE_OFF)
  257.     poly = polygonize_objects([object])[0]
  258.  
  259.     # Join the hierarchy and adjust the objects name and render-mode.
  260.     poly = join_hierarchy(poly, doc)
  261.     poly.SetName(op.GetName() + " Ghost(%d)" % frame)
  262.     poly.SetRenderMode(c4d.MODE_OFF)
  263.  
  264.     # Delete the objects tags except point and polygon tags.
  265.     delete_tags(poly, keep=lambda x: any(map(x.CheckType, [c4d.Tpoint, c4d.Tpolygon])))
  266.  
  267.     # Insert the object into the document and make sure the only selected object
  268.     # will be our original object.
  269.     doc.InsertObject(poly, pred=op)
  270.     doc.AddUndo(c4d.UNDOTYPE_NEW, poly)
  271.     doc.SetActiveObject(op)
  272.  
  273.     # Invoke the procedure for applying the display options.
  274.     apply_options(doc, poly)
  275.  
  276.     # Reactivate all HyperNURBS objects to their original state.
  277.     for hn, state in hypernurbs_objects:
  278.         hn.SetDeformMode(state)
  279.  
  280.     # Tell Cinema 4D to update its interface.
  281.     c4d.EventAdd()
  282.  
  283. main()
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement