Advertisement
Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- # coding: UTF-8
- #
- # Copyright (C) 2012, Athanasios Pozantzis
- # Copyright (C) 2012, Niklas Rosenstein (rewrite)
- #
- # Changelog (newest at top)
- # -------------------------
- #
- # v1.6 September 22, 2012 (Niklas Rosenstein):
- # - Name of the resulting ghost-object is now correct.
- # - The added material is now included into the undo-step.
- # - After the script is executed, the selected object is now the source-object
- # and not the resulting ghost-object.
- # - The flicker when executing was fixed. Instead of using a temporary
- # document, the *join_hierarchy* function now uses a modeling-command.
- # - The resulting ghost-object is now inserted *after* the source object,
- # no longer before it.
- #
- # v1.5 September 22, 2012 (Niklas Rosenstein):
- # - Complete rewrite
- # - Abstraction of components
- # - A bug has been fixed, where a second Sketch & Toon video post was created
- # when the avaialble video post was not the first element in the list.
- # - HyperNURBS are now reactivated if they were activated when running the
- # script. Turned off HyperNURBS will stay turned off.
- # - The whole script is now merged into a single undo-step.
- # - Hidden objects are no more included in the resulting ghost-object.
- #
- # v1.4 September 22, 2012 (Athanasios Pozantzis):
- # - Initial version
- import c4d
- # Missing Symbols in the c4d module.
- VPsketchandtoon = 1011015
- Tsketchandtoon = 1011012
- Msketchandtoon = 1011014
- def collect_objects(root, doc=None, callback=lambda x: True):
- """ *Generator*. Collects all objects starting from *root* recursively that
- match by the passed callback. If root is None, the document must have
- been passed to start from the top-level of the hierarchy. The passed
- object for *root* can be a `c4d.BaseList2D` instance, but if it is None
- and the document is used, it will search for the objects in the Object
- Manager. """
- def procedure(object, callback):
- if callback(object): yield object
- for child in object.GetChildren():
- for sub in procedure(child, callback):
- yield sub
- if root:
- for sub in procedure(root, callback):
- yield sub
- else:
- for object in doc.GetObjects():
- for sub in procedure(object, callback):
- yield sub
- def find_object(root, callback):
- """ Finds an object in the hierarchy of *root* that matches the passed
- callback. """
- if not root: return None
- def procedure(object):
- if callback(object): return object
- for child in object.GetObjects():
- child = find_object(child)
- if child: return child
- return None
- return procedure(root)
- def filter_hierarchy(root, callback, rwnull=True):
- """ Filters a hierarchy, which means to remove all objects that do not
- match the passed callback. *rwnull* stands for "replace with null".
- If this parameter is True (by default) and an object is about to be
- removed from the hierarchy, it is replaced by a Null object in case
- it has children. The passed callback must return True to notify
- an object needs to be removed. """
- children = root.GetChildren()
- if callback(root):
- if not children:
- root.Remove()
- return
- null = c4d.BaseObject(c4d.Onull)
- null.SetName(root.GetName())
- for child in children:
- child.InsertUnder(null)
- if root.GetUp() or root.GetPred() or root.GetNext():
- null.InsertAfter(root)
- root.Remove()
- root = null
- for child in children:
- filter_hierarchy(child, callback)
- def delete_tags(object, keep=lambda x: False, delete=lambda x: True):
- """ Iterates over all tags of the passed *object* and determines wether
- the tag should be kept or not. This is determined by calling the passed
- *keep* and *delete* functions. When the former returns True, the tag
- is kept. If not, the latter must return True to delete it. Both
- functions are passed a `c4d.BaseTag` instance. """
- tag = object.GetFirstTag()
- while tag:
- next = tag.GetNext()
- if not keep(tag) and delete(tag):
- tag.Remove()
- tag = next
- def polygonize_objects(objects, hierarchy=True):
- """ Polygonizes the hierarchy of the passed `c4d.BaseObject` instances
- with a little trick using a temporary `c4d.BaseDocument`. The
- full hierarchies are used, except *hierarchy* is set to False. """
- flags = c4d.COPYFLAGS_NO_ANIMATION | c4d.COPYFLAGS_NO_BITS | c4d.COPYFLAGS_NO_MATERIALPREVIEW
- if not hierarchy:
- flags |= c4d.COPYFLAGS_NO_HIERARCHY
- # Create a new temporary document and insert a clone of the passed objects
- # into it.
- doc = c4d.documents.BaseDocument()
- for object in objects:
- if object.GetDocument():
- object = object.GetClone(flags)
- doc.InsertObject(object)
- # Polygonize the document, obtain the objects, release them from the
- # document and return them.
- new_doc = doc.Polygonize()
- objects = new_doc.GetObjects()
- # Release all original objects from the temporary document.
- for object in doc.GetObjects():
- object.Remove()
- # Release all polygonized objects from the polygonized document.
- for object in objects:
- object.Remove()
- return objects
- def join_hierarchy(object, doc=None):
- """ Joins the passed objects' hierarchy into one using a Modeling Command.
- """
- new_object = c4d.utils.SendModelingCommand(c4d.MCOMMAND_JOIN, [object])[0]
- return new_object
- def apply_options(doc, poly):
- """ Applies the general options for the Ghost object. """
- dtag = poly.MakeTag(c4d.Tdisplay)
- dtag[c4d.DISPLAYTAG_AFFECT_DISPLAYMODE] = True
- dtag[c4d.DISPLAYTAG_SDISPLAYMODE] = c4d.DISPLAYTAG_SDISPLAY_HIDDENLINE
- def apply_snt(doc, poly):
- # Change an option on the display-tag.
- dtag[c4d.DISPLAYTAG_WDISPLAYMODE] = c4d.DISPLAYTAG_WDISPLAY_SKELETON
- # Find the first Sketch & Toon Video Post effect, or insert one if it does
- # not exist.
- rd = doc.GetActiveRenderData()
- vp = find_object(rd.GetFirstVideoPost(), lambda x: x.CheckType(VPsketchandtoon))
- if not vp:
- vp = c4d.BaseList2D(VPsketchandtoon)
- rd.InsertVideoPostLast(vp)
- # Create a new material for the Sketch & Toon editor outline.
- name = poly.GetName()
- mat = c4d.BaseMaterial(Msketchandtoon)
- mat.SetName(name + " Material")
- doc.InsertMaterial(mat)
- doc.AddUndo(c4d.UNDOTYPE_NEW, mat)
- tag = poly.MakeTag(Tsketchandtoon)
- doc.AddUndo(c4d.UNDOTYPE_NEW, tag)
- tag.SetName(name + " Tag")
- tag[c4d.OUTLINEMAT_LINE_DEFAULT_MAT_V] = mat
- # Set the required information.
- vp[c4d.OUTLINEMAT_EDLINES_SHOWLINES] = True
- vp[c4d.OUTLINEMAT_EDLINES_REDRAW_FULL] = True
- vp[c4d.OUTLINEMAT_EDLINES_LINE_OBJECTS_MODE] = 0 #include
- vp[c4d.OUTLINEMAT_EDLINES_LINE_OUTLINE] = False
- vp[c4d.OUTLINEMAT_EDLINES_LINE_CREASE] = False
- vp[c4d.OUTLINEMAT_EDLINES_LINE_MATERIAL] = False
- vp[c4d.OUTLINEMAT_EDLINES_LINE_INTERSECTION] = False
- vp[c4d.OUTLINEMAT_EDLINES_LINE_BORDER] = False
- vp[c4d.OUTLINEMAT_EDLINES_LINE_EDGES] = False
- vp[c4d.OUTLINEMAT_EDLINES_LINE_FOLD] = True
- vp[c4d.OUTLINEMAT_SCENE_AA] = 0
- lst = vp[c4d.OUTLINEMAT_EDLINES_LINE_OBJECTS] or c4d.InExcludeData()
- lst.InsertObject(poly, 0)
- vp[c4d.OUTLINEMAT_EDLINES_LINE_OBJECTS] = lst
- def apply_alt(doc, poly):
- poly[c4d.ID_BASEOBJECT_XRAY] = True
- if c4d.modules.CheckSketch():
- apply_snt(doc, poly)
- else:
- apply_alt(doc, poly)
- def main():
- """ The final procedure. """
- if not op:
- c4d.gui.MessageDialog('Please select exactly one object.')
- return False
- # Information for future use.
- fps = doc.GetFps()
- time = doc.GetTime()
- frame = time.GetFrame(fps)
- # This list will be filled with all HyperNURBS objects contained in the
- # hierarchy of the selected object. They need to be turned off before
- # converting the hierarchy to a ghost.
- hypernurbs_objects = []
- # Fill the HyperNURBS-objects list and turn off all of them.
- for hn in collect_objects(op, callback=lambda x: x.CheckType(c4d.Osds)):
- hypernurbs_objects.append([hn, hn.GetDeformMode()])
- hn.SetDeformMode(False)
- # Clone the hierarchy and sort out unnecessary objects.
- object = op.GetClone()
- filter_hierarchy(object, lambda x: x.GetEditorMode() == c4d.MODE_OFF)
- poly = polygonize_objects([object])[0]
- # Join the hierarchy and adjust the objects name and render-mode.
- poly = join_hierarchy(poly, doc)
- poly.SetName(op.GetName() + " Ghost(%d)" % frame)
- poly.SetRenderMode(c4d.MODE_OFF)
- # Delete the objects tags except point and polygon tags.
- delete_tags(poly, keep=lambda x: any(map(x.CheckType, [c4d.Tpoint, c4d.Tpolygon])))
- # Insert the object into the document and make sure the only selected object
- # will be our original object.
- doc.InsertObject(poly, pred=op)
- doc.AddUndo(c4d.UNDOTYPE_NEW, poly)
- doc.SetActiveObject(op)
- # Invoke the procedure for applying the display options.
- apply_options(doc, poly)
- # Reactivate all HyperNURBS objects to their original state.
- for hn, state in hypernurbs_objects:
- hn.SetDeformMode(state)
- # Tell Cinema 4D to update its interface.
- c4d.EventAdd()
- main()
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement