def create_rig_controls(shape=shapes.Plus, driven=[], **kwargs): if not driven: driven = ls(selection=True, transforms=True) assert driven, "Must supply one or more transforms to drive." assert len(driven) == len(ls(driven, transforms=True)), \ "Rig controls can only drive transforms." rcs = [RigControl(shape, d, **kwargs) for d in driven] select([rc.get_transform() for rc in rcs]) return rcs
def split_joints(n=5): selection = ls(selection=True) if JointSplitter.validate_for_split_joint(selection): first_joint = ls(selection=True)[0] fj = pm.joint(pm.general.ls(selection=True)[0], query=True, position=True) lj = pm.joint(pm.general.ls(selection=True)[1], query=True, position=True) fj_vector = dt.Vector(fj[0], fj[1], fj[2]) lj_vector = dt.Vector(lj[0], lj[1], lj[2]) new_joint = 0 pm.select(deselect=True) for i in range(0, n - 1): split_point = fj_vector.__mul__((n - i - 1.0) / n).__add__(lj_vector.__mul__(i + 1.0) / n) new_joint = pm.insertJoint(new_joint if i > 0 else first_joint) pm.joint(new_joint, edit=True, component=True, position=split_point)
def __new__(cls, **kwargs): s = super(Custom, cls).__new__(cls, **kwargs) transforms = ls(selection=True, transforms=True) for t in transforms: shapes = t.getShapes() if shapes: s.extend(shapes) elif isinstance(t, nt.Joint): s.append(t) xform(t, translation=(0, 0, 0)) else: # Delete empty transforms. delete(t) s.extend([n for n in ls(selection=True, shapes=True) if n not in s]) return s
def create_shapes(shape_cls=Plus, snaps=[], **kwargs): if not snaps: snaps = ls(selection=True, transforms=True) if snaps: return [shape_cls(snap_to=s) for s in snaps] verts = [v for v in ls(selection=True, flatten=True) if isinstance(v, MeshVertex)] [verts.extend(e.connectedVertices()) for e in ls(selection=True, flatten=True) \ if isinstance(e, MeshEdge)] if verts: verts = uniquify(verts) select(verts, replace=True) transform = cluster()[1] shape = shape_cls(snap_to=transform) delete(transform) return [shape] return [shape_cls()]
def export_mesh(self, **kwargs): format, ext = str(self.format.text()), str(self.formatExt.text()) format = self.name_pat.sub( \ lambda m: '%(name)' + m.group(1)[1:], format) format = self.frame_pat.sub( \ lambda m: '%(frame)' + m.group(1)[1:], format) path = Path(self.path.text()) if not self.animation.isChecked() and self.oneFilePerNode.isChecked(): sel = ls(selection=True) for s in sel: select(s) name = format % dict(name=s.name().replace('|', '')) + ext self.write_mesh(path, name, **kwargs) select(sel) else: end, by = self.end.value(), self.by.value() frame, renum_frame, renum_by = (self.frame, self.renum_frame, self.renum_by) info('Exporting frames... Press Esc to cancel.') self.progress_init(1) while (by > 0 and frame <= end) or (by < 0 and frame >= end): if self.aborted: return setCurrentTime(frame) if self.oneFilePerNode.isChecked(): sel = ls(selection=True) for s in sel: select(s) name = format % dict(name=s.shortName(), frame=renum_frame) + ext if not self.write_mesh(path, name): break else: name = format % dict(frame=renum_frame) + ext if not self.write_mesh(path, name, **kwargs): break # Prepare for the next iteration. frame += by renum_frame += renum_by self.export_count += 1 self.progress_step()
def createSequenceRenderFile(): renderFile = open(getRenderCommandFileName(), 'w+') for shot in ls(type='shot'): renderCommand = createRenderStringFromShot(shot) # renderCommands.append(createRenderStringFromShot(shot)) renderFile.write(renderCommand + '\n') renderFile.close()
def create_shapes(shape_cls=Plus, snaps=[], **kwargs): if not snaps: snaps = ls(selection=True, transforms=True) if snaps: return [shape_cls(snap_to=s) for s in snaps] verts = [ v for v in ls(selection=True, flatten=True) if isinstance(v, MeshVertex) ] [verts.extend(e.connectedVertices()) for e in ls(selection=True, flatten=True) \ if isinstance(e, MeshEdge)] if verts: verts = uniquify(verts) select(verts, replace=True) transform = cluster()[1] shape = shape_cls(snap_to=transform) delete(transform) return [shape] return [shape_cls()]
def __init__(self, *args, **kwargs): super(Exporter, self).__init__(*args, **kwargs) self.name_pat = re.compile('(%s)') self.frame_pat = re.compile('(%[\d\.]*(?:f|d))') self.split_pat = re.compile('((?:%s|%[\d\.]*(?:d|f)))') self.run_showers = (self.progress, self.status) self.run_disablers = (self.reload, self.toolBox, self.exportOptions, self.exportButton) [o.hide() for o in self.run_showers] self.animation_widgets = () for i in range(1, 3): self.animation_widgets += ((self.toolBox.widget(i), self.toolBox.itemText(i)), ) self.main_progress = getMainProgressBar() self._aborted = False # Look at the selection to predict what kind of object the user is going # to export and auto-select it in the export type combo box. kwargs = dict(selection=True, dagObjects=True) jroots = len( dict(((j, None) for j in ls(type='joint', **kwargs))).keys()) cams = len(ls(cameras=True, **kwargs)) meshes, skins = ls(geometry=True, **kwargs), 0 del_meshes = [] for i, m in enumerate(meshes): if mel.findRelatedSkinCluster(m): skins += 1 del_meshes.append(i) for i in del_meshes: del meshes[i] if not jroots and not cams and not meshes and not skins: comboIndex = 2 # Meshes as default else: comboIndex = sorted(((i, c) for i, c in enumerate( \ (jroots, cams, meshes, skins))), key=lambda x: x[1])[-1][0] self.exportCombo.setCurrentIndex(comboIndex) self.setFromTimeSlider.click() self.fix_format()
def on_loadWeightsButton_clicked(self): for mesh in selected(): sc = mel.findRelatedSkinCluster(mesh) if not sc: continue sc = ls(sc)[0] doc = ElementTree(file=path + mesh.nodeName().replace('|', '').replace(':', '.') + '.xml') influences = [inf.attrib['name'] for inf in doc.findall('//Influence')] for i, vtx in enumerate(doc.findall('//Vertex')): weights = [(influences[int(w.attrib['influence'])], float(w.attrib['value'])) for w in vtx.findall('Weight')] skinPercent(sc, '%s.vtx[%d]' % (mesh, i), transformValue=weights)
def get_affected_nodes(self, dagObjects=True, **kwargs): """ Reads the UI's "Affecting: Hierarchy, Selected, All" radios and returns the appropriate selection of nodes. """ if self.affectingAllRadio.isChecked(): nodes = ls(dagObjects=dagObjects, **kwargs) else: nodes = selected(dagObjects=dagObjects, **kwargs) if nodes and self.affectingHierarchyRadio.isChecked(): nodes += [n for n in \ listRelatives(allDescendents=True, **kwargs) \ if n not in nodes] return nodes
def __init__(self, *args, **kwargs): super(Exporter, self).__init__(*args, **kwargs) self.name_pat = re.compile('(%s)') self.frame_pat = re.compile('(%[\d\.]*(?:f|d))') self.split_pat = re.compile('((?:%s|%[\d\.]*(?:d|f)))') self.run_showers = (self.progress, self.status) self.run_disablers = (self.reload, self.toolBox, self.exportOptions, self.exportButton) [o.hide() for o in self.run_showers] self.animation_widgets = () for i in range(1, 3): self.animation_widgets += ((self.toolBox.widget(i), self.toolBox.itemText(i)),) self.main_progress = getMainProgressBar() self._aborted = False # Look at the selection to predict what kind of object the user is going # to export and auto-select it in the export type combo box. kwargs = dict(selection=True, dagObjects=True) jroots = len(dict(((j, None) for j in ls(type='joint', **kwargs))).keys()) cams = len(ls(cameras=True, **kwargs)) meshes, skins = ls(geometry=True, **kwargs), 0 del_meshes = [] for i, m in enumerate(meshes): if mel.findRelatedSkinCluster(m): skins += 1 del_meshes.append(i) for i in del_meshes: del meshes[i] if not jroots and not cams and not meshes and not skins: comboIndex = 2 # Meshes as default else: comboIndex = sorted(((i, c) for i, c in enumerate( \ (jroots, cams, meshes, skins))), key=lambda x: x[1])[-1][0] self.exportCombo.setCurrentIndex(comboIndex) self.setFromTimeSlider.click() self.fix_format()
def __init__(self, transform, **kwargs): """ Flags: - real_world_length: rwl (unicode, default:None) The longest length of the object in the real world (e.g. '11in' for a normal 8.5x11" sheet of paper. - shared_transforms: st (list, default:None) Any number of transforms that share the same nucleus. """ super(ScaledNCloth, self).__init__() self.transform = transform self.nucleus = ls(mel.getActiveNucleusNode(0, 1))[0] self.shared_transforms = kwargs.pop( 'st', kwargs.pop('shared_transforms', None)) self.real_world_length = kwargs.pop( 'rwl', kwargs.pop('real_world_length', None))
def __init__(self, transform, **kwargs): """ Flags: - real_world_length: rwl (unicode, default:None) The longest length of the object in the real world (e.g. '11in' for a normal 8.5x11" sheet of paper. - shared_transforms: st (list, default:None) Any number of transforms that share the same nucleus. """ super(ScaledNCloth, self).__init__() self.transform = transform self.nucleus = ls(mel.getActiveNucleusNode(0, 1))[0] self.shared_transforms = kwargs.pop('st', kwargs.pop('shared_transforms', None)) self.real_world_length = kwargs.pop('rwl', kwargs.pop('real_world_length', None))
def insert_bind_joints(self, cls, amount): inserted_joints = [] for bj in self.bind_joints[cls]: nj = bj.getChildren()[0] # next joint d = nj.attr('t').get() / (amount + 1) parent(nj, world=True) ij = bj for i in range(amount): ns = ij.name_sequence + 1 ij = ls(insertJoint(ij))[0] ij.attr('t').set(d) ij.__class__ = cls ij.name_sequence = ns self.name_helper.rename(ij, jt=bj.jtype, s=bj.side, ss=bj.side_sequence, n=bj.__name__, ns=ns) inserted_joints.append(ij) parent(nj, ij) self.set_bone_radii(bj) self.bind_joints[cls].extend(inserted_joints)
def on_loadWeightsButton_clicked(self): for mesh in selected(): sc = mel.findRelatedSkinCluster(mesh) if not sc: continue sc = ls(sc)[0] doc = ElementTree( file=path + mesh.nodeName().replace('|', '').replace(':', '.') + '.xml') influences = [ inf.attrib['name'] for inf in doc.findall('//Influence') ] for i, vtx in enumerate(doc.findall('//Vertex')): weights = [(influences[int(w.attrib['influence'])], float(w.attrib['value'])) for w in vtx.findall('Weight')] skinPercent(sc, '%s.vtx[%d]' % (mesh, i), transformValue=weights)
def on_runButton_clicked(self): self._nodes = self.get_affected_nodes() if not self._nodes: return error('No affected nodes to manipulate.') # Filter-out shape nodes from the list, but only if their # parents are also in the list, because they will get renamed # automatically. for n in [n for n in ls(self._nodes, geometry=True) \ if n.getParent(1) in self._nodes]: del self._nodes[self._nodes.index(n)] undoInfo(openChunk=True) if self.searchReplaceRadio.isChecked(): self.search_replace_names() else: self.assign_new_names() undoInfo(closeChunk=True) self.display_renamed_nodes()
def on_exportButton_clicked(self): if not ls(selection=True): return error('Nothing is currently selected.') # Load the objExport plug-in if it hasn't been already. kwargs = {} if self.formatExt.text() == '.obj': mll = 'objExport.mll' if not pluginInfo(mll, query=True, loaded=True): try: loadPlugin(mll) info('Loaded plug-in: ' + mll) except: return error('Failed loading plug-in: ' + mll) #kwargs = dict(force=True, constructionHistory=False, # channels=False, constraints=False, expressions=True, # shader=False, preserveReferences=False, type='OBJexport') options = dict(groups=self.groups, ptgroups=self.pointGroups, materials=self.materials, smoothing=self.smoothing, normals=self.normals) options = ';'.join('%s=%d' % (k, cb.isChecked()) \ for k, cb in options.items()) kwargs = dict(exportSelected=True, type='OBJexport', force=True, options=options) elif self.exportCombo.currentIndex() == 2: # mesh return error('Unsupported extension: %s.' % self.formatExt.text()) # Validate the output path. output_path = Path(self.path.text()) if not output_path.exists(): output_path = Path(self.set_path(workspace.getPath())) if not output_path.exists(): return # Validate the frame range. start, end, by = self.start.value(), self.end.value(), self.by.value() remainder = (end - start) % by if remainder: click_result = confirmDialog(title='Confirm', message=os.linesep.join(( \ 'The end frame will not be exported because', 'the "by frame" overshoots it by %.2f.' % remainder)), button=('OK', 'Cancel'), cancelButton='Cancel', defaultButton='OK', dismissString='Cancel') if click_result == 'Cancel': return # Validate the format. format = str(self.format.text()) try: format % (start + by) except TypeError: return error('Invalid format: "%s". ' % format + \ 'Click the \'...\' tool button for help.' % format) # Disable UI elements while running. [o.show() for o in self.run_showers] [o.setEnabled(False) for o in self.run_disablers] # Set the range. if self.renumFrames.isChecked(): renum_start = self.renumStart.value() self.renum_by = self.renumBy.value() else: renum_start = start self.renum_by = by self.frame, self.renum_frame = start, renum_start # Set loop vars. self.aborted = False self.export_count = 0 self.copy_and_replace_all = False # Call the appropriate export function. (self.export_skeleton, self.export_camera, self.export_mesh, self.export_skin_weights)[self.exportCombo.currentIndex()](**kwargs) self.main_progress.endProgress() # Enable UI elements back. [o.hide() for o in self.run_showers] [o.setEnabled(True) for o in self.run_disablers] # Report results. if self.aborted: msg = 'Aborted with %s exported' else: msg = 'Successfully exported %s' plural = self.export_count != 1 and 's' or '' frames = '%d frame' % self.export_count + plural result(msg % frames + ' to: %s.' % output_path)
def export_skin_weights(self): format, ext = str(self.format.text()), str(self.formatExt.text()) format = self.name_pat.sub( \ lambda m: '%(name)' + m.group(1)[1:], format) path = Path(self.path.text()) # Validate selection. sel = selected() if not sel: error('Selection is empty.') # Find the skin cluster. sc = mel.findRelatedSkinCluster(sel[0]) skin_cluster = None for s in sel: sc = mel.findRelatedSkinCluster(s) if sc: skin_cluster = ls(sc)[0] break if not skin_cluster: error('No skin cluster found.') for mesh in sel: mesh_element = Element('Mesh', name=mesh) xml_tree = ElementTree(mesh_element) sc = mel.findRelatedSkinCluster(mesh) if not sc: continue sc = ls(sc)[0] influences = sc.influenceObjects() inf_tag = SubElement(mesh_element, 'Influences') for i, inf in enumerate(influences): SubElement(inf_tag, 'Influence', index=str(i), name=inf) #joints = ls(ios, type='joint') #if len(joints) < len(ios): # error('Remove non-joint influences before exporting to Massive.') # TODO: progress bar name = format % dict(name=mesh.name().replace('|', '') \ .replace(':', '.')) + ext with open(path / name, 'w') as f: #f.write(os.linesep + '# influences') #for i, inf in enumerate(ios): # if inf in influences: # inf_index = influences.index(j) # else: # influences += (inf,) # inf_index = len(influences) #f.write('%sdeformer %d %s' % (os.linesep, i, inf)) #f.write(os.linesep) vertices = SubElement(mesh_element, 'Vertices') #f.write(os.linesep + '# weights') for i, vtx in enumerate(mesh.vtx): vertex = SubElement(vertices, 'Vertex', pos=str(vtx.getPosition())) #f.write('%s%d: ' % (os.linesep, vi)) for ii, inf in enumerate(influences): weight_val = skinPercent(sc, '%s.vtx[%d]' % (mesh, i), transform=inf, query=True) if weight_val: SubElement(vertex, 'Weight', influence=str(ii), value=str(weight_val)) #f.write(' %d %f' % (ii, weight_val)) #f.write(os.linesep + ':') rough_string = tostring(xml_tree.getroot(), 'utf-8') reparsed = minidom.parseString(rough_string) f.write(reparsed.toprettyxml(indent='\t'))
def __init__(self, root_cls=None, *args, **kwargs): """ Flags: - bone_radius: br (int, default:1) Sets all joints' bone radii. This flag only works if -vary_bone_radius is False. - nhpat (string, default:<nt>_<s><ss>_<n><ns>) Establishes a naming convention where 'nt' is the node type (drive or bind joint), 's' in the side, 'ss' is the side sequence, 'n' is the name and 'ns' is the name sequence. - long_bone_radius: lbr (float, default:2.0) Sets -vary_bone_radius' maximum range. This flag only works if -vary_bone_radius is True. - short_bone_radius: sbr (float, default:0.5) Sets -vary_bone_radius' minimum range. This flag only works if -vary_bone_radius is True. - test_bone_radius: tebr (bool, default:False) Tests the bone radius settings without continuing the rigging process. - tip_bone_radius: tbr (float, default:0.25) Sets all tip joints' bone radii. This flag only works if -vary_bone_radius is True. """ # Find the joint-chain's root joint. joints = ls(selection=True, type='joint') roots = [] for j in joints: while True: pj = j.listRelatives(parent=True, type='joint') if pj: j = pj[0] elif j not in roots: roots.append(j) break assert len(roots), 'Selection requires at least one joint.' # Vary bone radius. self._short_bone_radius = kwargs.pop('sbr', kwargs.pop('short_bone_radius', self._short_bone_radius)) self._long_bone_radius = kwargs.pop('lbr', kwargs.pop('long_bone_radius', self._long_bone_radius)) self._tip_bone_radius = kwargs.pop('tbr', kwargs.pop('tip_bone_radius', self._tip_bone_radius)) for r in roots: self.set_bone_length_range(r) self.set_bone_radii(r) test_bone_radius = kwargs.pop('tebr', kwargs.pop('test_bone_radius', False)) if test_bone_radius: return if not issubclass(root_cls, CharacterJoint): raise TypeError("%s class must be a subclass of %s." \ % (root_cls.__name__, CharacterJoint)) # NameHelper segments establish a naming convention for this character. self.name_helper = kwargs.pop('nh', kwargs.pop('name_helper', None)) if not self.name_helper: self.name_helper = NameHelper() # In order to distinguish the character's left and right sides, first we need to # define the character's front axis. self.front = kwargs.pop('front', 'z') for jdict in [self.drive_joints, self.bind_joints]: jdict[root_cls] = [] for i, root in enumerate(roots): # Clean-up the joint chain by freezing rotate and scale makeIdentity(root, apply=True, rotate=True, scale=True) # Recurse through the entire joint chain, assigning the appropriate # CharacterJoint class to each joint. self.drive_joints[root_cls].append(root_cls(root, self, jdict=self.drive_joints, *args, **kwargs)) self.bind_joints[root_cls].append(root_cls(root.duplicate()[0], self, jdict=self.bind_joints, *args, **kwargs)) # Recursion added joints to the lists backwards, so reverse it to # keep the joints in a top-down relationship. for jdict in [self.drive_joints, self.bind_joints]: [jdict[cls].reverse() for cls in jdict.keys()] # Change the name of the joints to something they would not use # to prevent any naming conflicts in the future. roots.extend(self.bind_joints[root_cls]) function_on_hierarchy(roots, rename, 'FooJoint#') # Name joints. for cls, dj_list in self.drive_joints.items(): for i, dj in enumerate(dj_list): while True: self.rename_part(dj) if len(ls(dj.nodeName())) == 1: bj = self.bind_joints[cls][i] dj.bind_joint = bj bj.drive_joint = dj bj.side_sequence = dj.side_sequence self.rename_part(bj) break dj.side_sequence += 1
def export_camera(self): start, end = self.start.value(), self.end.value() path = Path(self.path.text()) # Validate the selection. sel = ls(selection=True, dagObjects=True, cameras=True) if not ls(selection=True): return error('No cameras in selection.') # Associate the camera shapes with their parents. cams = dict((s, s.getParent()) for s in sel) # Pull-out only the attributes that are checked. shape_atts = [] for cb in self.cameraChannelsLayout.findChildren(QCheckBox): if cb.isChecked(): [shape_atts.extend(str(cb.property(n).toString()).split('|')) \ for n in cb.dynamicPropertyNames() if n == 'shortName'] cam_atts = (cb.objectName() for cb \ in self.translation.findChildren(QCheckBox) if cb.isChecked()) attributes = (shape_atts, cam_atts) # Enable any locked or non-keyable channels. for shape, cam in cams.items(): for i, obj in enumerate((shape, cam)): for att in attributes[i]: obj.attr(att).set('locked', False) obj.attr(att).set('keyable', True) # Initialize the progress bar. lc = len(cams) self.progress_init(lc + lc * len([ x for x in (self.createStandIn.isChecked(), self.oneFile.isChecked() and self.oneFilePerNode.isChecked) if x ])) # Bake the keys to the camera shape. frame_range = self.animation.isChecked() and (start, end) or (start, ) for shape, cam in cams.items(): if self.aborted: return info('Baking keys to %s: %d-%d...' % \ ((shape,) + frame_range)) bakeResults(shape, time=frame_range, simulation=True, attribute=shape_atts) info('%s keys %d-%d baked.' % ((shape, ) + frame_range)) self.progress_step() # Disable the cycle check warning. cycleCheck(evaluation=False) # Create a null stand-in for the camera and bake keys to it. #mel.source('channelBoxCommand.mel') if self.createStandIn.isChecked(): for cam in cams.values(): if self.aborted: return stand_in = Transform(name='standInNull') parentConstraint(cam, stand_in, name='nullParentConstraint') info('Baking keys to the stand-in null...') bakeResults(stand_in, time=frame_range, shape=True, simulation=True, attribute=cam_atts) info('Null keys baked.') # If the camera is a child, parent it to the world. if cam.firstParent2(): cam.setParent(world=True) # Break existing connections between the rotate or translate # attributes. for att in cam_atts: if connectionInfo(cam, isExactDestination=True): disconnectAttr( connectionInfo(cam, getExactDestination=True)) #mel.CBdeleteConnection(getExactDestination=True) # Constrain the camera to the null. parentConstraint(stand_in, cam, name='cameraParentConstraint') # Bake the camera translate/rotate keys. info('Baking keys to the camera...') bakeResults(cam, time=frame_range, disableImplicitControl=True, simulation=True, attribute=cam_atts) info('Transform keys baked.') self.progress_step() # Remove excess elements unless optimize has been disabled. if self.optimize.isChecked(): info('Optimizing scene...') delete([s for s in ls(dagObjects=True) if s not in cams.keys() + \ cams.values() + ls(selection=True, type='animCurve')]) # Save-out the cameras. kwargs = dict(force=True, constructionHistory=False, channels=True, constraints=False, expressions=False, shader=False, type='mayaAscii') ext = str(self.formatExt.text()) if self.oneFile.isChecked(): if self.oneFilePerNode.isChecked(): for cam in cams.values(): if self.aborted: return select(cam) exportSelected(path / cam.name() + ext, **kwargs) self.progress_step() else: select(cams.values()) exportSelected(path / 'camera' + ext, **kwargs) else: error('Not implemented yet. Coming soon...')
def __init__(self, driver=shapes.Plus, driven=None, **kwargs): # Driver if not isinstance(driver, shapes.Shape) and issubclass( driver, shapes.Shape): driver = driver() assert isinstance(driver, shapes.Shape), \ ("Parameter 'driver' must be an instance or subclass of %s." % shapes.Shape.__name__) self._driver = driver self._transform = driver.get_transform() self._shapes = self._transform.getShapes() # Driven if not driven: driven = ls(selection=True, transforms=True) assert len( driven ) == 1, "Parameter 'driven' requires exactly one transform." driven = driven[0] self._driven = driven # Face Axis face_x = kwargs.pop('fx', kwargs.pop('faceX', False)) face_y = kwargs.pop('fy', kwargs.pop('faceY', False)) face_z = kwargs.pop('fz', kwargs.pop('faceZ', False)) face_sum = sum([face_x, face_y, face_z]) if not face_sum: face_x = True face_sum = 1 else: assert face_sum == 1, "Rig control can only face one axis." rotate(self._transform, [face_z and 90 or 0, 0, face_x and -90 or 0]) select(self._transform) FreezeTransformations() # Constraints do_parent_constraint = kwargs.pop( 'pc', kwargs.pop('parentConstraint', False)) do_point_constraint = kwargs.pop('xc', kwargs.pop('pointConstraint', False)) do_orient_constraint = kwargs.pop( 'oc', kwargs.pop('orientConstraint', False)) do_scale_constraint = kwargs.pop('sc', kwargs.pop('scaleConstraint', False)) if do_parent_constraint or do_point_constraint or do_orient_constraint or \ do_scale_constraint: self._buffer = Transform() snap(self._buffer, self._driven, scale=True) select(self._buffer) parent(self._transform, self._buffer) if do_parent_constraint: parentConstraint(self._transform, self._driven) else: if do_point_constraint: pointConstraint(self._transform, self._driven) if do_orient_constraint: orientConstraint(self._transform, self._driven) if do_scale_constraint: scaleConstraint(self._transform, self._driven) elif isinstance(self._driven, Joint): # Parent the drivers directly underneath the driven joint. parent(self._driver, self._driven, relative=True, shape=True) delete(self._transform) self._transform = self._driven elif isinstance(self._driven, IkHandle): self._buffer = self._transform self._transform = self._driven snap(self._ebuffer, self._transform) parent(self._transform, self._buffer) parent(self._driver, self._transform, relative=True, shape=True) else: # Parent the drivers underneath a new buffered transform. self._buffer = self._driven parent(self._transform, self._buffer) parent(self._buffer.getShapes(), self._transform, relative=True, shape=True) # Pop the shape nodes out and back in to reorder the driven shape(s) to # the top. This way, the Outliner icons for this transform will reflect the # appropriate first-child shape node. parent(self._driver, self._buffer, relative=True, shape=True) parent(self._driver, self._transform, relative=True, shape=True) if self._buffer: select(self._transform) ResetTransformations() for trs in 'trs': for xyz in 'xyz': self._buffer.attr(trs + xyz).lock() if isinstance(self._driven, IkHandle): self.__class__ = IkRigControl self.__init__()
def saveFile(self, type=0): #So this function needs to look into the proper component folder (if it exists), find the Working folder (if it exists, if not make it) #Then save an iteration of this file. project = self.getSelectedProject() if project!="None": if windows.optionMenu("partOptionMenu", q=True, v=True)!="None": part_index = int(windows.optionMenu("partOptionMenu", q=True, v=True).split(":")[0]) - 1 part_directory, part_name, part_numname = project.modelingComponents[part_index] if os.path.isdir(part_directory): #part_name = project.modelingComponents[part_index][1] working_dir = os.path.join(part_directory, "Working") qa_dir = os.path.join(part_directory, "QA") publish_dir = os.path.join(part_directory, "Publish") if os.path.isdir(working_dir)==False: os.makedirs(working_dir) if os.path.isdir(qa_dir)==False: os.makedirs(qa_dir) if os.path.isdir(publish_dir)==False: os.makedirs(publish_dir) #If save type is 0 (which is a regular work file incremental save) #Save format: part_modeler_v001.mb if type==0: if self.username!="": files = glob.glob(working_dir+"/*") if len(files)>0: highest_num=0 for file in files: if os.path.isfile(file): filenum = int(os.path.split(file)[1].split(".")[0][-3:]) if filenum>highest_num: highest_num = filenum else: highest_num+=1 num = ("0"*max(0,3-len(str(highest_num)))+str(highest_num)) print("Num: " + num) else: num = "001" if num=="001": if windows.confirmDialog(title = "Save Part File?", message = "Save the first version of this part? You will not be prompted when saving new versions after this.", button = ['Yes', 'No'], defaultButton='Yes', cancelButton='No', dismissString='No')=='Yes': file_name = os.path.join(working_dir , part_name + "_" + self.username + "_" + "v" + num + ".mb") system.saveAs(file_name) else: file_name = os.path.join(working_dir , part_name + "_" + self.username + "_" + "v" + num + ".mb") system.saveAs(file_name) else: windows.confirmDialog(title="No username entered.", message="Please enter a valid username to save with.",button="Dismiss") #If the save file is type 1, its a publish attempt elif type==1: if windows.confirmDialog(title = "Publish File", message = "Publish this scene file?", button = ['Yes', 'No'], defaultButton='Yes', cancelButton='No', dismissString='No')=='Yes': file_name = os.path.join(publish_dir, part_name + "_publish.mb") if os.path.isfile(file_name): ctime = os.path.getctime(file_name) moveFolder = os.path.join(publish_dir,"_old",time.strftime("%b%d_%Y %H-%M-%S",time.localtime(ctime))) if not os.path.isdir(moveFolder): os.makedirs(moveFolder) shutil.move(file_name, moveFolder) #Save the current file, then move on to cleaning up this file in preparation for publishing current_filename = system.sceneName() system.saveAs(current_filename) #Clean up all references reference_files = [] references = general.ls(type = "reference") if len(references)>0: for reference in references: if "sharedReferenceNode"!=reference: reference_files.append(system.referenceQuery(reference, filename=True)) else: for file in reference_files: system.FileReference(pathOrRefNode = file).remove() general.select(clear = True) general.select(general.ls(geometry = True)) layerName = os.path.split(system.sceneName())[1].split("_")[0].replace(" ", "_") general.createDisplayLayer(name = layerName) system.saveAs(file_name) system.openFile(current_filename, f = True) #If its type 2, its a QA submit elif type==2: if windows.confirmDialog(title = "Submit for QA", message = "Submit this scene file for QA?", button = ['Yes', 'No'], defaultButton='Yes', cancelButton='No', dismissString='No')=='Yes': _time = time.strftime("%b%d_%Y_%H-%M-%S", time.localtime(time.time())) file_name = os.path.join(qa_dir, part_name + "_%s_%s.mb"%(self.username,_time)) _files = glob.glob(qa_dir+"/*.mb") if len(_files)>0: found=False for i in _files: if file_name == i: found=True if windows.confirmDialog(title = "Overwrite?", message = "A QA file with this name already exists. Overwrite it?", button = ['Yes', 'No'], defaultButton='Yes', cancelButton='No', dismissString='No')=='Yes': current_filename = system.sceneName() system.saveAs(file_name) system.saveAs(current_filename) else: _folder = os.path.join(qa_dir,os.path.split(i)[1].split(".")[0]) os.makedirs(_folder) shutil.move(i, _folder) else: if found==False: current_filename = system.sceneName() system.saveAs(file_name) system.saveAs(current_filename) else: current_filename = system.sceneName() system.saveAs(file_name) system.saveAs(current_filename) else: windows.confirmDialog(title = "Part Not Found", message = "The selected part folder cannot be found.", button=["Dismiss"])
def performSlice(self): #Make sure theres a gizmo, otherwise theres no point in doing anything if general.objExists("WaffleSliceGizmo"): #Get the step size and step count from the appropriate sliders step_size = windows.floatSliderGrp("stepSizeSlider", q = True, v = True) step_count = int(windows.floatSliderGrp("stepCountSlider", q = True, v = True)) #Get the axes filter from the radio buttons axes = windows.radioButtonGrp("axesRadioButtonGrp", q = True, sl = True) #Iterate through the selected objects and create an array of sliceable ones sliceArray = [] for child in general.ls(sl = True): if (child!="WaffleSliceGizmo"): #Make sure the selection is either a transform or mesh if (general.objectType(child)=="transform" or general.objectType(child)=="mesh"): sliceArray.append(child) else: #If anything was added to the array, then move forwards with the waffle slice if len(sliceArray)>0: #Create the slicing proxies that will push the proper transforms and rotates into the slice arguments general.group(n = "slice_proxy_x", em = True) general.xform("slice_proxy_x", t=[general.getAttr("WaffleSliceGizmo.translateX"), general.getAttr("WaffleSliceGizmo.translateY"), general.getAttr("WaffleSliceGizmo.translateZ"),] , ro = [general.getAttr("WaffleSliceGizmo.rotateX"), general.getAttr("WaffleSliceGizmo.rotateY"), general.getAttr("WaffleSliceGizmo.rotateZ"),] ,ws = True) general.group(n = "slice_proxy_y", em = True) general.xform("slice_proxy_y", t=[general.getAttr("WaffleSliceGizmo.translateX"), general.getAttr("WaffleSliceGizmo.translateY"), general.getAttr("WaffleSliceGizmo.translateZ"),] , ro = [general.getAttr("WaffleSliceGizmo.rotateX"), general.getAttr("WaffleSliceGizmo.rotateY"), general.getAttr("WaffleSliceGizmo.rotateZ"),] ,ws = True) general.rotate("slice_proxy_y", (90, 0, 0), r = True, os = True) general.parent("slice_proxy_x", "WaffleSliceGizmo") general.parent("slice_proxy_y", "WaffleSliceGizmo") #Iterate through the list of objects for child in sliceArray: #Move the slicers by half of the total distance they're going to need to slice through general.move("slice_proxy_x", [0,0,(-1*((step_size*step_count)/2))] , r = True, ls = True)#, z = True) general.move("slice_proxy_y", [0, (-1*((step_size*step_count)/2)),0], r = True, ls = True)#, y = True) #Get the options for x, y, or both #Do the slices, and for each iteration, bump each proxy forwards by their allotted amount for i in range(step_count): if (axes == 1 or axes == 3): general.move("slice_proxy_x", [0, 0, step_size] , r = True, ls = True)#, z = True) pos = general.xform("slice_proxy_x", ws = True, q = True, t = True) rot = general.xform("slice_proxy_x", ws = True, q = True, ro = True) modeling.polyCut(child, ro = rot , pc = pos) general.delete(child, ch = True) if (axes == 2 or axes == 3): general.move("slice_proxy_y", [0, step_size, 0], r = True, ls = True)#, y = True) pos = general.xform("slice_proxy_y", ws = True, q = True, t = True) rot = general.xform("slice_proxy_y", ws = True, q = True, ro = True) modeling.polyCut(child, ro = rot , pc = pos) general.delete(child, ch = True) else: #Reset the position of the proxies after each object so they dont fly off into the distance general.xform("slice_proxy_x", t=[general.getAttr("WaffleSliceGizmo.translateX"), general.getAttr("WaffleSliceGizmo.translateY"), general.getAttr("WaffleSliceGizmo.translateZ"),] , ws = True) general.xform("slice_proxy_y", t=[general.getAttr("WaffleSliceGizmo.translateX"), general.getAttr("WaffleSliceGizmo.translateY"), general.getAttr("WaffleSliceGizmo.translateZ"),] , ws = True) else: #Clean up the slice proxies general.delete("slice_proxy_x") general.delete("slice_proxy_y") else: print("No slice gizmo")
def __init__(self, root_cls=None, *args, **kwargs): """ Flags: - bone_radius: br (int, default:1) Sets all joints' bone radii. This flag only works if -vary_bone_radius is False. - nhpat (string, default:<nt>_<s><ss>_<n><ns>) Establishes a naming convention where 'nt' is the node type (drive or bind joint), 's' in the side, 'ss' is the side sequence, 'n' is the name and 'ns' is the name sequence. - long_bone_radius: lbr (float, default:2.0) Sets -vary_bone_radius' maximum range. This flag only works if -vary_bone_radius is True. - short_bone_radius: sbr (float, default:0.5) Sets -vary_bone_radius' minimum range. This flag only works if -vary_bone_radius is True. - test_bone_radius: tebr (bool, default:False) Tests the bone radius settings without continuing the rigging process. - tip_bone_radius: tbr (float, default:0.25) Sets all tip joints' bone radii. This flag only works if -vary_bone_radius is True. """ # Find the joint-chain's root joint. joints = ls(selection=True, type='joint') roots = [] for j in joints: while True: pj = j.listRelatives(parent=True, type='joint') if pj: j = pj[0] elif j not in roots: roots.append(j) break assert len(roots), 'Selection requires at least one joint.' # Vary bone radius. self._short_bone_radius = kwargs.pop( 'sbr', kwargs.pop('short_bone_radius', self._short_bone_radius)) self._long_bone_radius = kwargs.pop( 'lbr', kwargs.pop('long_bone_radius', self._long_bone_radius)) self._tip_bone_radius = kwargs.pop( 'tbr', kwargs.pop('tip_bone_radius', self._tip_bone_radius)) for r in roots: self.set_bone_length_range(r) self.set_bone_radii(r) test_bone_radius = kwargs.pop('tebr', kwargs.pop('test_bone_radius', False)) if test_bone_radius: return if not issubclass(root_cls, CharacterJoint): raise TypeError("%s class must be a subclass of %s." \ % (root_cls.__name__, CharacterJoint)) # NameHelper segments establish a naming convention for this character. self.name_helper = kwargs.pop('nh', kwargs.pop('name_helper', None)) if not self.name_helper: self.name_helper = NameHelper() # In order to distinguish the character's left and right sides, first we need to # define the character's front axis. self.front = kwargs.pop('front', 'z') for jdict in [self.drive_joints, self.bind_joints]: jdict[root_cls] = [] for i, root in enumerate(roots): # Clean-up the joint chain by freezing rotate and scale makeIdentity(root, apply=True, rotate=True, scale=True) # Recurse through the entire joint chain, assigning the appropriate # CharacterJoint class to each joint. self.drive_joints[root_cls].append( root_cls(root, self, jdict=self.drive_joints, *args, **kwargs)) self.bind_joints[root_cls].append( root_cls(root.duplicate()[0], self, jdict=self.bind_joints, *args, **kwargs)) # Recursion added joints to the lists backwards, so reverse it to # keep the joints in a top-down relationship. for jdict in [self.drive_joints, self.bind_joints]: [jdict[cls].reverse() for cls in jdict.keys()] # Change the name of the joints to something they would not use # to prevent any naming conflicts in the future. roots.extend(self.bind_joints[root_cls]) function_on_hierarchy(roots, rename, 'FooJoint#') # Name joints. for cls, dj_list in self.drive_joints.items(): for i, dj in enumerate(dj_list): while True: self.rename_part(dj) if len(ls(dj.nodeName())) == 1: bj = self.bind_joints[cls][i] dj.bind_joint = bj bj.drive_joint = dj bj.side_sequence = dj.side_sequence self.rename_part(bj) break dj.side_sequence += 1
def export_camera(self): start, end = self.start.value(), self.end.value() path = Path(self.path.text()) # Validate the selection. sel = ls(selection=True, dagObjects=True, cameras=True) if not ls(selection=True): return error('No cameras in selection.') # Associate the camera shapes with their parents. cams = dict((s, s.getParent()) for s in sel) # Pull-out only the attributes that are checked. shape_atts = [] for cb in self.cameraChannelsLayout.findChildren(QCheckBox): if cb.isChecked(): [shape_atts.extend(str(cb.property(n).toString()).split('|')) \ for n in cb.dynamicPropertyNames() if n == 'shortName'] cam_atts = (cb.objectName() for cb \ in self.translation.findChildren(QCheckBox) if cb.isChecked()) attributes = (shape_atts, cam_atts) # Enable any locked or non-keyable channels. for shape, cam in cams.items(): for i, obj in enumerate((shape, cam)): for att in attributes[i]: obj.attr(att).set('locked', False) obj.attr(att).set('keyable', True) # Initialize the progress bar. lc = len(cams) self.progress_init(lc + lc * len([x for x in (self.createStandIn.isChecked(), self.oneFile.isChecked() and self.oneFilePerNode.isChecked) if x])) # Bake the keys to the camera shape. frame_range = self.animation.isChecked() and (start, end) or (start,) for shape, cam in cams.items(): if self.aborted: return info('Baking keys to %s: %d-%d...' % \ ((shape,) + frame_range)) bakeResults(shape, time=frame_range, simulation=True, attribute=shape_atts) info('%s keys %d-%d baked.' % ((shape,) + frame_range)) self.progress_step() # Disable the cycle check warning. cycleCheck(evaluation=False) # Create a null stand-in for the camera and bake keys to it. #mel.source('channelBoxCommand.mel') if self.createStandIn.isChecked(): for cam in cams.values(): if self.aborted: return stand_in = Transform(name='standInNull') parentConstraint(cam, stand_in, name='nullParentConstraint') info('Baking keys to the stand-in null...') bakeResults(stand_in, time=frame_range, shape=True, simulation=True, attribute=cam_atts) info('Null keys baked.') # If the camera is a child, parent it to the world. if cam.firstParent2(): cam.setParent(world=True) # Break existing connections between the rotate or translate # attributes. for att in cam_atts: if connectionInfo(cam, isExactDestination=True): disconnectAttr(connectionInfo(cam, getExactDestination=True)) #mel.CBdeleteConnection(getExactDestination=True) # Constrain the camera to the null. parentConstraint(stand_in, cam, name='cameraParentConstraint') # Bake the camera translate/rotate keys. info('Baking keys to the camera...') bakeResults(cam, time=frame_range, disableImplicitControl=True, simulation=True, attribute=cam_atts) info('Transform keys baked.') self.progress_step() # Remove excess elements unless optimize has been disabled. if self.optimize.isChecked(): info('Optimizing scene...') delete([s for s in ls(dagObjects=True) if s not in cams.keys() + \ cams.values() + ls(selection=True, type='animCurve')]) # Save-out the cameras. kwargs = dict(force=True, constructionHistory=False, channels=True, constraints=False, expressions=False, shader=False, type='mayaAscii') ext = str(self.formatExt.text()) if self.oneFile.isChecked(): if self.oneFilePerNode.isChecked(): for cam in cams.values(): if self.aborted: return select(cam) exportSelected(path / cam.name() + ext, **kwargs) self.progress_step() else: select(cams.values()) exportSelected(path / 'camera' + ext, **kwargs) else: error('Not implemented yet. Coming soon...')
def __init__(self, driver=shapes.Plus, driven=None, **kwargs): # Driver if not isinstance(driver, shapes.Shape) and issubclass(driver, shapes.Shape): driver = driver() assert isinstance(driver, shapes.Shape), \ ("Parameter 'driver' must be an instance or subclass of %s." % shapes.Shape.__name__) self._driver = driver self._transform = driver.get_transform() self._shapes = self._transform.getShapes() # Driven if not driven: driven = ls(selection=True, transforms=True) assert len(driven) == 1, "Parameter 'driven' requires exactly one transform." driven = driven[0] self._driven = driven # Face Axis face_x = kwargs.pop('fx', kwargs.pop('faceX', False)) face_y = kwargs.pop('fy', kwargs.pop('faceY', False)) face_z = kwargs.pop('fz', kwargs.pop('faceZ', False)) face_sum = sum([face_x, face_y, face_z]) if not face_sum: face_x = True face_sum = 1 else: assert face_sum == 1, "Rig control can only face one axis." rotate(self._transform, [face_z and 90 or 0, 0, face_x and -90 or 0]) select(self._transform) FreezeTransformations() # Constraints do_parent_constraint = kwargs.pop('pc', kwargs.pop('parentConstraint', False)) do_point_constraint = kwargs.pop('xc', kwargs.pop('pointConstraint', False)) do_orient_constraint = kwargs.pop('oc', kwargs.pop('orientConstraint', False)) do_scale_constraint = kwargs.pop('sc', kwargs.pop('scaleConstraint', False)) if do_parent_constraint or do_point_constraint or do_orient_constraint or \ do_scale_constraint: self._buffer = Transform() snap(self._buffer, self._driven, scale=True) select(self._buffer) parent(self._transform, self._buffer) if do_parent_constraint: parentConstraint(self._transform, self._driven) else: if do_point_constraint: pointConstraint(self._transform, self._driven) if do_orient_constraint: orientConstraint(self._transform, self._driven) if do_scale_constraint: scaleConstraint(self._transform, self._driven) elif isinstance(self._driven, Joint): # Parent the drivers directly underneath the driven joint. parent(self._driver, self._driven, relative=True, shape=True) delete(self._transform) self._transform = self._driven elif isinstance(self._driven, IkHandle): self._buffer = self._transform self._transform = self._driven snap(self._ebuffer, self._transform) parent(self._transform, self._buffer) parent(self._driver, self._transform, relative=True, shape=True) else: # Parent the drivers underneath a new buffered transform. self._buffer = self._driven parent(self._transform, self._buffer) parent(self._buffer.getShapes(), self._transform, relative=True, shape=True) # Pop the shape nodes out and back in to reorder the driven shape(s) to # the top. This way, the Outliner icons for this transform will reflect the # appropriate first-child shape node. parent(self._driver, self._buffer, relative=True, shape=True) parent(self._driver, self._transform, relative=True, shape=True) if self._buffer: select(self._transform) ResetTransformations() for trs in 'trs': for xyz in 'xyz': self._buffer.attr(trs + xyz).lock() if isinstance(self._driven, IkHandle): self.__class__ = IkRigControl self.__init__()