Advertisement
nux95

Cinema 4D - PoseGhost Script 1.6

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