def updateModel(self): """ Refresh the name_comboBox with the current Maya scene state. """ self.populateModel(self.model) col = lib_state.get_active_collection() if col is None: return # range_type_value = self.getRangeTypeValue(col) index = self.getRangeTypeActiveIndex(self.model, col) if index is None: LOG.error('Could not get the active range type index.') return frames_string = '1001-1101' increment = self.getIncrementByFrameValue(col) frames_enabled = False increment_enabled = False if index == const.RANGE_TYPE_CURRENT_FRAME_VALUE: frames_string = 'CURRENT FRAME' frames_enabled = False increment_enabled = False elif index == const.RANGE_TYPE_TIMELINE_INNER_VALUE: start, end = utils_time.get_maya_timeline_range_inner() frames_string = '{0}-{1}'.format(int(start), int(end)) frames_enabled = False increment_enabled = True elif index == const.RANGE_TYPE_TIMELINE_OUTER_VALUE: start, end = utils_time.get_maya_timeline_range_outer() frames_string = '{0}-{1}'.format(int(start), int(end)) frames_enabled = False increment_enabled = True elif index == const.RANGE_TYPE_CUSTOM_FRAMES_VALUE: frames_string = self.getFramesValue(col) if frames_string is None: start, end = utils_time.get_maya_timeline_range_outer() frames_string = '{0}-{1}'.format(int(start), int(end)) frames_enabled = True increment_enabled = True else: msg = "Not a valid 'range type' value: %r" % index raise ValueError(msg) block = self.blockSignals(True) self.rangeType_comboBox.setCurrentIndex(index) self.frames_lineEdit.setEnabled(frames_enabled) self.frames_lineEdit.setText(frames_string) self.incrementByFrame_spinBox.setEnabled(increment_enabled) self.incrementByFrame_spinBox.setValue(increment) self.blockSignals(block) return
def main(): """ Convert all selected transforms into 2D markers under a camera. """ # Get camera model_editor = utils_viewport.get_active_model_editor() if model_editor is None: msg = 'Please select an active 3D viewport.' LOG.warning(msg) return cam_tfm, cam_shp = utils_viewport.get_viewport_camera(model_editor) if cam_shp is None: LOG.error('Please select an active viewport to get a camera.') return if utils_camera.is_startup_cam(cam_shp) is True: LOG.error("Cannot create Markers in 'persp' camera.") return # Get transforms nodes = maya.cmds.ls( selection=True, long=True, type='transform', ) or [] if len(nodes) == 0: LOG.warning('Please select one or more transform nodes.') return mmapi.load_plugin() try: # Turn off Maya UI maya.mel.eval('paneLayout -e -manage false $gMainPane') # Compute the Marker Data. start_frame, end_frame = utils_time.get_maya_timeline_range_outer() mkr_data_list = __convert_nodes_to_marker_data_list( cam_tfm, cam_shp, nodes, start_frame, end_frame, ) cam = mmapi.Camera(shape=cam_shp) mkr_list = mayareadfile.create_nodes( mkr_data_list, cam=cam, mkr_grp=None, with_bundles=True, ) mkr_nodes = [mkr.get_node() for mkr in mkr_list] except: raise finally: # Turn on Maya UI maya.mel.eval('paneLayout -e -manage true $gMainPane') if len(mkr_nodes) > 0: maya.cmds.select(mkr_nodes, replace=True) return
def frameRangeModeIndexChanged(self, index): name = const.CONFIG_FRAME_RANGE_MODE_KEY value = const.FRAME_RANGE_MODE_VALUES[index] configmaya.set_scene_option(name, value, add_attr=True) LOG.debug('key=%r value=%r', name, value) enable_custom = value == const.FRAME_RANGE_MODE_CUSTOM_VALUE self.frameRangeStartSpinBox.setEnabled(enable_custom) self.frameRangeEndSpinBox.setEnabled(enable_custom) frame_start = configmaya.get_scene_option( const.CONFIG_FRAME_START_KEY, default=const.DEFAULT_FRAME_START) frame_end = configmaya.get_scene_option( const.CONFIG_FRAME_END_KEY, default=const.DEFAULT_FRAME_END) if value == const.FRAME_RANGE_MODE_CURRENT_FRAME_VALUE: frame_start = maya.cmds.currentTime(query=True) frame_end = frame_start elif value == const.FRAME_RANGE_MODE_TIMELINE_INNER_VALUE: frame_start, frame_end = time_utils.get_maya_timeline_range_inner() elif value == const.FRAME_RANGE_MODE_TIMELINE_OUTER_VALUE: frame_start, frame_end = time_utils.get_maya_timeline_range_outer() self.frameRangeStartSpinBox.setValue(frame_start) self.frameRangeEndSpinBox.setValue(frame_end)
def get_deviation_frames(self, frame_range_start=None, frame_range_end=None): """ Get the list of frames that this Marker has deviation set. If there is no animation curve on a Marker we use the frame_range_start and frame_range_end arguments to determine the deviation frame list. If these frame_range_* arguments are not given the default Maya outer timeline range is used. :param frame_range_start: The frame range start of the marker to consider when no animCurve exists. :type frame_range_start: int :param frame_range_end: The frame range end of the marker to consider when no animCurve exists. :type frame_range_end: int :returns: The deviation frame numbers of the marker. :rtype: [int, ..] """ start_frame, end_frame = time_utils.get_maya_timeline_range_outer() if frame_range_start is None: frame_range_start = start_frame if frame_range_end is None: frame_range_end = end_frame times = [] node = self.get_node() if node is None: msg = 'Could not get node. self=%r' LOG.warning(msg, self) return times anim_curve_fn = self.get_deviation_anim_curve_fn() if anim_curve_fn is None: enable_times = range(frame_range_start, frame_range_end + 1) enable_times = list(enable_times) else: num_keys = anim_curve_fn.numKeys() enable_times = [None] * num_keys for i in range(num_keys): mtime = anim_curve_fn.time(i) enable_times[i] = int(mtime.value()) if num_keys == 0: enable_times = range(frame_range_start, frame_range_end + 1) enable_times = list(enable_times) start_frame = int(min(enable_times)) end_frame = int(max(enable_times)) frame_range = list(range(start_frame, end_frame + 1)) dev_list = self.get_deviation(times=frame_range) for frm, dev_val in zip(frame_range, dev_list): if dev_val > 0.0: times.append(frm) return times
def get_enabled_frames(self, frame_range_start=None, frame_range_end=None): """ Get the list of frames that this Marker is enabled. If there is no animation curve on a Marker we use the frame_range_start and frame_range_end arguments to determine the enabled frame list. If these frame_range_* arguments are not given the default Maya outer timeline range is used. :param frame_range_start: The frame range start of the marker to consider when no animCurve exists. :type frame_range_start: int :param frame_range_end: The frame range end of the marker to consider when no animCurve exists. :type frame_range_end: int :returns: The enabled frame numbers of the marker. :rtype: [int, ..] """ start_frame, end_frame = time_utils.get_maya_timeline_range_outer() if frame_range_start is None: frame_range_start = start_frame if frame_range_end is None: frame_range_end = end_frame times = [] node = self.get_node() if node is None: LOG.warn('Could not get node. self=%r', self) return times plug = '{0}.{1}'.format(node, const.MARKER_ATTR_LONG_NAME_ENABLE) anim_curves = maya.cmds.listConnections(plug, type='animCurve') or [] if len(anim_curves) == 0: enable_times = list(range(frame_range_start, frame_range_end + 1)) else: anim_curve = anim_curves[0] enable_times = maya.cmds.keyframe( anim_curve, query=True, timeChange=True) or [] if len(enable_times) == 0: enable_times = list(range(frame_range_start, frame_range_end + 1)) start_frame = int(min(enable_times)) end_frame = int(max(enable_times)) for f in range(start_frame, end_frame + 1): v = self.get_enable(time=f) if v: times.append(f) return times
def bake_selected_attributes(attr_list): LOG.debug('bake_selected_attributes: %r', attr_list) frame_range = time_utils.get_maya_timeline_range_outer() plug_names = _get_plug_names_as_set(attr_list) plug_names = list(sorted(plug_names)) with tools_utils.tool_context(pre_update_frame=True, restore_current_frame=True, use_undo_chunk=True, use_dg_evaluation_mode=True, disable_viewport=True): maya.cmds.bakeResults(plug_names, time=(frame_range.start, frame_range.end)) return
def populateUi(self): """ Update the UI for the first time the class is created. """ name = const.CONFIG_FRAME_RANGE_MODE_KEY value = configmaya.get_scene_option( name, default=const.DEFAULT_FRAME_RANGE_MODE) index = const.FRAME_RANGE_MODE_VALUES.index(value) label = const.FRAME_RANGE_MODE_LABELS[index] LOG.debug('key=%r value=%r', name, value) self.frameRangeModeComboBox.setCurrentText(label) enable_custom = value == const.FRAME_RANGE_MODE_CUSTOM_VALUE self.frameRangeStartSpinBox.setEnabled(enable_custom) self.frameRangeEndSpinBox.setEnabled(enable_custom) frame_start = configmaya.get_scene_option( const.CONFIG_FRAME_START_KEY, default=const.DEFAULT_FRAME_START) frame_end = configmaya.get_scene_option( const.CONFIG_FRAME_END_KEY, default=const.DEFAULT_FRAME_END) if value == const.FRAME_RANGE_MODE_TIMELINE_INNER_VALUE: frame_start, frame_end = time_utils.get_maya_timeline_range_inner() elif value == const.FRAME_RANGE_MODE_TIMELINE_OUTER_VALUE: frame_start, frame_end = time_utils.get_maya_timeline_range_outer() LOG.debug('key=%r value=%r', const.CONFIG_FRAME_START_KEY, frame_start) LOG.debug('key=%r value=%r', const.CONFIG_FRAME_END_KEY, frame_end) self.frameRangeStartSpinBox.setValue(frame_start) self.frameRangeEndSpinBox.setValue(frame_end) name = const.CONFIG_BAKE_MODE_KEY value = configmaya.get_scene_option(name, default=const.DEFAULT_BAKE_MODE) index = const.BAKE_MODE_VALUES.index(value) label = const.BAKE_MODE_LABELS[index] LOG.debug('key=%r value=%r', name, value) self.rotateOrderModeComboBox.setCurrentText(label) name = const.CONFIG_ROTATE_ORDER_MODE_KEY value = configmaya.get_scene_option( name, default=const.DEFAULT_ROTATE_ORDER_MODE) index = const.ROTATE_ORDER_MODE_VALUES.index(value) label = const.ROTATE_ORDER_MODE_LABELS[index] LOG.debug('key=%r value=%r', name, value) self.rotateOrderModeComboBox.setCurrentText(label) name = const.CONFIG_DELETE_STATIC_ANIM_CURVES_KEY value = configmaya.get_scene_option( name, default=const.DEFAULT_DELETE_STATIC_ANIM_CURVES) LOG.debug('key=%r value=%r', name, value) self.deleteStaticAnimCurvesCheckBox.setChecked(value) return
def get_bake_frame_range(frame_range_mode, custom_start_frame, custom_end_frame): assert isinstance(frame_range_mode, basestring) assert frame_range_mode in const.FRAME_RANGE_MODE_VALUES assert isinstance(custom_start_frame, (int, long)) assert isinstance(custom_end_frame, (int, long)) frame_range = None if frame_range_mode == const.FRAME_RANGE_MODE_TIMELINE_INNER_VALUE: frame_range = time_utils.get_maya_timeline_range_inner() elif frame_range_mode == const.FRAME_RANGE_MODE_TIMELINE_OUTER_VALUE: frame_range = time_utils.get_maya_timeline_range_outer() elif frame_range_mode == const.FRAME_RANGE_MODE_CUSTOM_VALUE: frame_range = time_utils.FrameRange(custom_start_frame, custom_end_frame) else: LOG.error("Invalid frame range mode: %r", frame_range_mode) return frame_range
def populateUi(self): """ Update the UI for the first time the class is created. """ name = const.CONFIG_FRAME_RANGE_MODE_KEY value = configmaya.get_scene_option( name, default=const.DEFAULT_FRAME_RANGE_MODE) index = const.FRAME_RANGE_MODE_VALUES.index(value) label = const.FRAME_RANGE_MODE_LABELS[index] LOG.debug('key=%r value=%r', name, value) self.frameRangeModeComboBox.setCurrentText(label) enable_custom = value == const.FRAME_RANGE_MODE_CUSTOM_VALUE self.frameRangeStartSpinBox.setEnabled(enable_custom) self.frameRangeEndSpinBox.setEnabled(enable_custom) frame_start = configmaya.get_scene_option( const.CONFIG_FRAME_START_KEY, default=const.DEFAULT_FRAME_START) frame_end = configmaya.get_scene_option( const.CONFIG_FRAME_END_KEY, default=const.DEFAULT_FRAME_END) if value == const.FRAME_RANGE_MODE_CURRENT_FRAME_VALUE: frame_start = maya.cmds.currentTime(query=True) frame_end = frame_start elif value == const.FRAME_RANGE_MODE_TIMELINE_INNER_VALUE: frame_start, frame_end = time_utils.get_maya_timeline_range_inner() elif value == const.FRAME_RANGE_MODE_TIMELINE_OUTER_VALUE: frame_start, frame_end = time_utils.get_maya_timeline_range_outer() LOG.debug('key=%r value=%r', const.CONFIG_FRAME_START_KEY, frame_start) LOG.debug('key=%r value=%r', const.CONFIG_FRAME_END_KEY, frame_end) self.frameRangeStartSpinBox.setValue(frame_start) self.frameRangeEndSpinBox.setValue(frame_end) name = const.CONFIG_BUNDLE_ROTATE_MODE_KEY value = configmaya.get_scene_option( name, default=const.DEFAULT_BUNDLE_ROTATE_MODE) index = const.BUNDLE_ROTATE_MODE_VALUES.index(value) label = const.BUNDLE_ROTATE_MODE_LABELS[index] LOG.debug('key=%r value=%r', name, value) self.bundleRotateModeComboBox.setCurrentText(label) name = const.CONFIG_BUNDLE_UNLOCK_RELOCK_KEY value = configmaya.get_scene_option( name, default=const.DEFAULT_BUNDLE_UNLOCK_RELOCK) LOG.debug('key=%r value=%r', name, value) self.bundleUnlockRelockCheckBox.setChecked(value) return
def __compile_frame_list(range_type, frame_string, by_frame): assert isinstance(range_type, int) assert frame_string is None or isinstance(frame_string, basestring) assert isinstance(by_frame, int) frame_nums = [] if range_type == const.RANGE_TYPE_TIMELINE_INNER_VALUE: start, end = utils_time.get_maya_timeline_range_inner() frame_nums = [f for f in xrange(start, end + 1, by_frame)] elif range_type == const.RANGE_TYPE_TIMELINE_OUTER_VALUE: start, end = utils_time.get_maya_timeline_range_outer() frame_nums = [f for f in xrange(start, end + 1, by_frame)] elif range_type == const.RANGE_TYPE_CUSTOM_FRAMES_VALUE: if frame_string is None: start, end = utils_time.get_maya_timeline_range_inner() frame_string = '{0}-{1}'.format(start, end) frame_nums = converttypes.stringToIntList(frame_string) # Apply 'by_frame' to custom frame ranges. start = min(frame_nums) frame_nums = [ n for n in frame_nums if (float(n - start) % by_frame) == 0 ] return frame_nums
def main(): """ Convert all selected transforms into 2D markers under a camera. """ # Get camera model_editor = utils_viewport.get_active_model_editor() if model_editor is None: msg = 'Please select an active 3D viewport.' LOG.warning(msg) return cam_tfm, cam_shp = utils_viewport.get_viewport_camera(model_editor) if cam_shp is None: LOG.error('Please select an active viewport to get a camera.') return if utils_camera.is_startup_cam(cam_shp) is True: LOG.error("Cannot create Markers in 'persp' camera.") return # Get transforms nodes = maya.cmds.ls( selection=True, long=True, type='transform', ) or [] if len(nodes) == 0: LOG.warning('Please select one or more transform nodes.') return mmapi.load_plugin() try: utils_viewport.viewport_turn_off() # Compute the Marker Data. start_frame, end_frame = utils_time.get_maya_timeline_range_outer() mkr_data_list = lib.convert_nodes_to_marker_data_list( cam_tfm, cam_shp, nodes, start_frame, end_frame, ) # Get Camera cam = mmapi.Camera(shape=cam_shp) # Get or create Marker Group. mkr_grp = None mkr_grp_nodes = maya.cmds.ls( cam_tfm, dag=True, long=True, type='mmMarkerGroupTransform') or [] mkr_grp_nodes = sorted(mkr_grp_nodes) if len(mkr_grp_nodes) == 0: mkr_grp = mmapi.MarkerGroup().create_node(cam=cam) else: mkr_grp = mmapi.MarkerGroup(node=mkr_grp_nodes[0]) # Create Marker nodes mkr_list = mayareadfile.create_nodes( mkr_data_list, cam=cam, mkr_grp=mkr_grp, with_bundles=True, ) mkr_nodes = [mkr.get_node() for mkr in mkr_list] finally: utils_viewport.viewport_turn_on() if len(mkr_nodes) > 0: maya.cmds.select(mkr_nodes, replace=True) return
def remove(nodes, current_frame=None, eval_mode=None): """ Remove a controller and push the animation back to the controlled object. Order the nodes to remove by hierarchy depth. This means that children will be removed first, then parents, this ensures we don't delete a controller accidentally when a parent controller is deleted first. :param nodes: The nodes to delete. :type nodes: [str, ..] :param current_frame: What frame number is considered to be 'current' when evaluating transforms without any keyframes. :type current_frame: float or int :param eval_mode: What type of transform evaluation method to use? :type eval_mode: mmSolver.utils.constant.EVAL_MODE_* :returns: List of once controlled transform nodes, that are no longer controlled. :rtype: [str, ..] """ if current_frame is None: current_frame = maya.cmds.currentTime(query=True) assert current_frame is not None sparse = False nodes = _sort_by_hierarchy(nodes, children_first=True) tfm_nodes = [tfm_utils.TransformNode(node=n) for n in nodes] # Find controlled nodes from controller nodes ctrl_to_ctrlled_map = {} for tfm_node in tfm_nodes: node = tfm_node.get_node() constraints = _get_constraints_from_ctrls(node) dests = _get_destination_nodes_from_ctrls(constraints) if len(dests) == 0: continue dests = _sort_by_hierarchy(dests, children_first=True) ctrl_to_ctrlled_map[node] = (constraints, dests) # Query keyframe times on controller nodes. start_frame, end_frame = time_utils.get_maya_timeline_range_outer() keytime_obj = keytime_utils.KeyframeTimes() for node in nodes: keytime_obj.add_node_attrs(node, const.TFM_ATTRS, start_frame, end_frame) fallback_frame_range = keytime_obj.sum_frame_range_for_nodes(nodes) fallback_times = list( range(fallback_frame_range[0], fallback_frame_range[1] + 1)) # Query keyframe times on each node attribute key_times_map = time_utils.get_keyframe_times_for_node_attrs( nodes, const.TFM_ATTRS) # Query transform matrix on controlled nodes. cache = tfm_utils.TransformMatrixCache() for src_node, (constraints, dst_nodes) in ctrl_to_ctrlled_map.items(): times = key_times_map.get(src_node, [current_frame]) assert len(times) > 0 ctrl = tfm_utils.TransformNode(node=src_node) cache.add_node(ctrl, times) for dst_node in dst_nodes: dst = tfm_utils.TransformNode(node=dst_node) cache.add_node(dst, times) cache.process(eval_mode=eval_mode) # Get Controlled nodes ctrlled_nodes = set() for src_node, (_, dst_nodes) in ctrl_to_ctrlled_map.items(): for dst_node in dst_nodes: ctrlled_nodes.add(dst_node) # Delete constraints on controlled nodes. const_nodes = set() for src_node, (constraints, _) in ctrl_to_ctrlled_map.items(): assert src_node not in constraints const_nodes |= constraints if len(const_nodes) > 0: maya.cmds.delete(list(const_nodes)) # Set keyframes (per-frame) on controlled nodes for ctrl_node, (_, ctrlled_nodes) in ctrl_to_ctrlled_map.items(): times = key_times_map.get(ctrl_node, [current_frame]) ctrl = tfm_utils.TransformNode(node=ctrl_node) for ctrlled_node in ctrlled_nodes: ctrlled = tfm_utils.TransformNode(node=ctrlled_node) tfm_utils.set_transform_values(cache, times, ctrl, ctrlled, delete_static_anim_curves=False) parent_nodes = [] anim_curves = [] for src_node, (_, dst_nodes) in ctrl_to_ctrlled_map.items(): src_times = key_times_map.get(src_node, [current_frame]) assert len(src_times) > 0 ctrl = tfm_utils.TransformNode(node=src_node) for dst_node in dst_nodes: dst = tfm_utils.TransformNode(node=dst_node) tfm_utils.set_transform_values(cache, src_times, ctrl, dst, delete_static_anim_curves=False) # Re-parent controller child nodes under controlled node. ctrl_children = maya.cmds.listRelatives( src_node, children=True, shapes=False, fullPath=True, type='transform', ) or [] for child_node in ctrl_children: if child_node in nodes: continue child = tfm_utils.TransformNode(node=child_node) parent_nodes.append((child, dst)) src_had_keys = key_times_map.get(src_node) is not None if src_had_keys is True: continue # Maintain that destination node will not have keyframes now, the # same as the source node. dst_node = dst.get_node() keyable_attrs = _get_keyable_attrs(dst_node, const.TFM_ATTRS) anim_curves += anim_utils.get_anim_curves_from_nodes( list(keyable_attrs), ) # Reparent children back to under the controlled. for src, dst in parent_nodes: src_node = src.get_node() dst_node = dst.get_node() maya.cmds.parent(src_node, dst_node, absolute=True) # Remove animation curves. anim_curves = [ n for n in anim_curves if node_utils.node_is_referenced(n) is False ] if len(anim_curves) > 0: maya.cmds.delete(anim_curves) # Delete controller nodes ctrl_nodes = [n.get_node() for n in tfm_nodes] if len(ctrl_nodes) > 0: maya.cmds.delete(ctrl_nodes) return list(ctrlled_nodes)
def func(plug_name): node_name, sep, attr_name = plug_name.partition('.') frame_range = time_utils.get_maya_timeline_range_outer() time_range = (frame_range.start, frame_range.end) maya.cmds.cutKey(node_name, attribute=attr_name, time=time_range)
def create(nodes, current_frame=None, eval_mode=None): """ Create a Controller for the given nodes. :param nodes: The nodes to create Controller for. :type nodes: [str, ..] :param current_frame: What frame number is considered to be 'current' when evaluating transforms without any keyframes. :type current_frame: float or int :param eval_mode: What type of transform evaluation method to use? :type eval_mode: mmSolver.utils.constant.EVAL_MODE_* :returns: List of controller transform nodes. :rtype: [str, ..] """ if current_frame is None: current_frame = maya.cmds.currentTime(query=True) assert current_frame is not None sparse = False tfm_nodes = [tfm_utils.TransformNode(node=n) for n in nodes] # Force into long-names. nodes = [n.get_node() for n in tfm_nodes] # Ensure node attributes are editable. keyable_attrs = set() for node in nodes: keyable_attrs |= _get_keyable_attrs(node, const.TFM_ATTRS) # Query keyframe times on each node attribute start_frame, end_frame = time_utils.get_maya_timeline_range_outer() keytime_obj = keytime_utils.KeyframeTimes() for node in nodes: keytime_obj.add_node_attrs(node, const.TFM_ATTRS, start_frame, end_frame) fallback_frame_range = keytime_obj.sum_frame_range_for_nodes(nodes) fallback_times = list( range(fallback_frame_range[0], fallback_frame_range[1] + 1)) key_times_map = time_utils.get_keyframe_times_for_node_attrs( nodes, const.TFM_ATTRS) # Query the transform matrix for the nodes cache = tfm_utils.TransformMatrixCache() for tfm_node in tfm_nodes: node = tfm_node.get_node() times = key_times_map.get(node, [current_frame]) cache.add_node(tfm_node, times) cache.process(eval_mode=eval_mode) depth_to_tfm_node_map = _sort_hierarchy_depth_to_tfm_nodes(tfm_nodes) nodes_parent = _get_node_parent_map(nodes) # Create new (locator) node for each input node ctrl_list = [] node_to_ctrl_map = {} node_to_ctrl_tfm_map = {} depths = sorted(depth_to_tfm_node_map.keys()) for depth in depths: depth_tfm_nodes = depth_to_tfm_node_map.get(depth) assert depth_tfm_nodes is not None sorted_tfm_nodes = sorted(depth_tfm_nodes, key=lambda x: x.get_node()) for tfm_node in sorted_tfm_nodes: node = tfm_node.get_node() node_parent = nodes_parent.get(node) if node_parent is not None: node_parent = node_to_ctrl_map.get(node_parent) name = node.rpartition('|')[-1] assert '|' not in name name = name.replace(':', '_') name = name + '_CTRL' name = mmapi.find_valid_maya_node_name(name) tfm = maya.cmds.createNode('transform', name=name, parent=node_parent) tfm = node_utils.get_long_name(tfm) shape_name = name + 'Shape' maya.cmds.createNode('locator', name=shape_name, parent=tfm) rot_order = maya.cmds.xform(node, query=True, rotateOrder=True) maya.cmds.xform(tfm, rotateOrder=rot_order, preserve=True) ctrl_tfm = tfm_utils.TransformNode(node=tfm) ctrl_list.append(tfm) node_to_ctrl_map[node] = tfm node_to_ctrl_tfm_map[node] = ctrl_tfm # Set transform matrix on new node anim_curves = [] for src in tfm_nodes: src_node = src.get_node() src_times = key_times_map.get(src_node, [current_frame]) dst = node_to_ctrl_tfm_map.get(src_node) assert len(src_times) > 0 tfm_utils.set_transform_values(cache, src_times, src, dst, delete_static_anim_curves=False, eval_mode=eval_mode) src_had_keys = key_times_map.get(src_node) is not None if src_had_keys is True: continue # Maintain that destination node will not have keyframes now, the # same as the source node. dst_node = dst.get_node() keyable_attrs = _get_keyable_attrs(dst_node, const.TFM_ATTRS) anim_curves += anim_utils.get_anim_curves_from_nodes( list(keyable_attrs), ) anim_curves = [ n for n in anim_curves if node_utils.node_is_referenced(n) is False ] if len(anim_curves) > 0: maya.cmds.delete(anim_curves) # Delete all keyframes on controlled nodes keyable_attrs = set() for tfm_node in tfm_nodes: node = tfm_node.get_node() keyable_attrs |= _get_keyable_attrs(node, const.TFM_ATTRS) anim_curves = anim_utils.get_anim_curves_from_nodes(list(keyable_attrs), ) anim_curves = [ n for n in anim_curves if node_utils.node_is_referenced(n) is False ] if len(anim_curves) > 0: maya.cmds.delete(anim_curves) # Create constraint(s) to previous nodes. for tfm_node in tfm_nodes: src_node = tfm_node.get_node() ctrl = node_to_ctrl_tfm_map.get(src_node) dst_node = ctrl.get_node() _create_constraint(src_node, dst_node) return ctrl_list
def create(nodes, sparse=True): tfm_nodes = [tfm_utils.TransformNode(node=n) for n in nodes] # Force into long-names. nodes = [n.get_node() for n in tfm_nodes] # Ensure node attributes are editable. keyable_attrs = set() for node in nodes: keyable_attrs |= _get_keyable_attrs(node, const.TFM_ATTRS) # Query keyframe times on each node attribute start_frame, end_frame = time_utils.get_maya_timeline_range_outer() keytime_obj = keytime_utils.KeyframeTimes() for node in nodes: keytime_obj.add_node_attrs(node, const.TFM_ATTRS, start_frame, end_frame) fallback_frame_range = keytime_obj.sum_frame_range_for_nodes(nodes) fallback_times = list(range(fallback_frame_range[0], fallback_frame_range[1]+1)) # Query the transform matrix for the nodes cache = tfm_utils.TransformMatrixCache() for tfm_node in tfm_nodes: node = tfm_node.get_node() times = keytime_obj.get_times(node, sparse) or fallback_times cache.add_node(tfm_node, times) cache.process() # Create new (locator) node for each input node ctrl_list = [] for tfm_node in tfm_nodes: node = tfm_node.get_node() name = node.rpartition('|')[-1] assert '|' not in name name = name.replace(':', '_') name = name + '_CTRL' name = mmapi.find_valid_maya_node_name(name) # TODO: Allow maintaining relative hierarchy of nodes. tfm = maya.cmds.createNode('transform', name=name) maya.cmds.createNode('locator', parent=tfm) rot_order = maya.cmds.xform(node, query=True, rotateOrder=True) maya.cmds.xform(tfm, rotateOrder=rot_order, preserve=True) ctrl_list.append(tfm) ctrl_tfm_nodes = [tfm_utils.TransformNode(node=tfm) for tfm in ctrl_list] # Set transform matrix on new node for src, dst in zip(tfm_nodes, ctrl_tfm_nodes): src_node = src.get_node() times = keytime_obj.get_times(src_node, sparse) or fallback_times tfm_utils.set_transform_values( cache, times, src, dst, delete_static_anim_curves=False ) if sparse is True: # Remove keyframes src_times = keytime_obj.get_times(src_node, sparse) or [] dst_node = dst.get_node() if len(src_times) == 0: time_range = keytime_obj.get_frame_range_for_node(src_node) assert time_range[0] is not None assert time_range[1] is not None maya.cmds.cutKey( dst_node, attribute=const.TFM_ATTRS, time=time_range, clear=True ) # Delete all keyframes on controlled nodes anim_curves = anim_utils.get_anim_curves_from_nodes( list(keyable_attrs), ) anim_curves = [n for n in anim_curves if node_utils.node_is_referenced(n) is False] if len(anim_curves) > 0: maya.cmds.delete(anim_curves) # Create constraint(s) to previous nodes. for tfm_node, ctrl in zip(tfm_nodes, ctrl_tfm_nodes): src_node = tfm_node.get_node() dst_node = ctrl.get_node() _create_constraint(src_node, dst_node) return ctrl_list
def main(): """Ray-casts each bundle connected to the selected markers on to the mesh from the associated camera. Select markers and mesh objects to ray-cast on to, if no mesh objects are selected the tool will ray-cast on to all visible mesh objects. If a bundle translate attribute is locked, it will be unlocked, then projected, and then the lock state will be reverted to the original value. .. note:: The Marker node is the origin point of the ray-cast, *not* the camera's pivot position. This is intentional. If the user has a single dense (LIDAR) model node it can be helpful to project from a distance away from the camera origin. With a single dense mesh it is difficult to split the model up to use different mesh selections. Example:: >>> import mmSolver.tools.raycastmarker.tool as tool >>> tool.main() """ selection = maya.cmds.ls(selection=True) or [] if not selection: LOG.warning('Please select a marker to rayCast.') return node_categories = mmapi.filter_nodes_into_categories(selection) mkr_node_list = node_categories['marker'] bnd_node_list = node_categories['bundle'] cam_node_list = node_categories['camera'] if len(mkr_node_list) == 0 and len(bnd_node_list) == 0: LOG.warn('Please select markers or bundles to ray-cast.') return # The camera used to determine where bundles will be projected from. active_cam_tfm, active_cam_shp = _get_active_or_selected_camera( cam_node_list) # Get Markers mkr_list, use_camera = _get_markers(mkr_node_list, bnd_node_list, active_cam_shp) if use_camera and active_cam_shp is None: LOG.warn('Please activate a viewport to ray-cast Bundles from.') frame_range_mode = configmaya.get_scene_option( const.CONFIG_FRAME_RANGE_MODE_KEY, default=const.DEFAULT_FRAME_RANGE_MODE) frame_start = configmaya.get_scene_option( const.CONFIG_FRAME_START_KEY, default=const.DEFAULT_FRAME_START) frame_end = configmaya.get_scene_option(const.CONFIG_FRAME_END_KEY, default=const.DEFAULT_FRAME_END) if frame_range_mode == const.FRAME_RANGE_MODE_CURRENT_FRAME_VALUE: frame_start = int(maya.cmds.currentTime(query=True)) frame_end = frame_start elif frame_range_mode == const.FRAME_RANGE_MODE_TIMELINE_INNER_VALUE: frame_start, frame_end = time_utils.get_maya_timeline_range_inner() elif frame_range_mode == const.FRAME_RANGE_MODE_TIMELINE_OUTER_VALUE: frame_start, frame_end = time_utils.get_maya_timeline_range_outer() frame_range = time_utils.FrameRange(frame_start, frame_end) use_smooth_mesh = True bundle_unlock_relock = configmaya.get_scene_option( const.CONFIG_BUNDLE_UNLOCK_RELOCK_KEY, default=const.DEFAULT_BUNDLE_UNLOCK_RELOCK) # Do not disable the viewport if we're only baking a single frame. disable_viewport = True if frame_range.start == frame_range.end: disable_viewport = False mesh_nodes = _get_selected_meshes() with tools_utils.tool_context(use_undo_chunk=True, restore_current_frame=True, use_dg_evaluation_mode=True, disable_viewport=disable_viewport): bnd_nodes = lib.raycast_markers_onto_meshes( mkr_list, mesh_nodes, frame_range=frame_range, unlock_bnd_attrs=bundle_unlock_relock, relock_bnd_attrs=bundle_unlock_relock, use_smooth_mesh=use_smooth_mesh) if len(bnd_nodes) > 0: maya.cmds.select(bnd_nodes) else: maya.cmds.select(selection) return
def remove(nodes, sparse=True): """ Remove a controller and push the animation back to the controlled object. .. todo:: What should we do with any transforms parented under the controller? Should these objects be re-parented under the controlled object? Probably yes. """ # Find controlled nodes from controller nodes ctrl_to_ctrlled_map = {} for ctrl_node in nodes: constraints = _get_constraints_from_ctrls(ctrl_node) dests = _get_destination_nodes_from_ctrls(constraints) if len(dests) == 0: continue ctrl_to_ctrlled_map[ctrl_node] = (constraints, dests) # Query keyframe times on controller nodes. start_frame, end_frame = time_utils.get_maya_timeline_range_outer() keytime_obj = keytime_utils.KeyframeTimes() for node in nodes: keytime_obj.add_node_attrs(node, const.TFM_ATTRS, start_frame, end_frame) fallback_frame_range = keytime_obj.sum_frame_range_for_nodes(nodes) fallback_times = list(range(fallback_frame_range[0], fallback_frame_range[1]+1)) # Query transform matrix on controlled nodes. cache = tfm_utils.TransformMatrixCache() for ctrl_node, (constraints, dest_nodes) in ctrl_to_ctrlled_map.items(): times = keytime_obj.get_times(ctrl_node, sparse) or fallback_times ctrl = tfm_utils.TransformNode(node=ctrl_node) cache.add_node(ctrl, times) for dest_node in dest_nodes: dest = tfm_utils.TransformNode(node=dest_node) cache.add_node(dest, times) cache.process() # Get Controlled nodes ctrlled_nodes = set() for ctrl_node, (_, dest_nodes) in ctrl_to_ctrlled_map.items(): for dest_node in dest_nodes: ctrlled_nodes.add(dest_node) # Delete constraints on controlled nodes. const_nodes = set() for ctrl_node, (constraints, _) in ctrl_to_ctrlled_map.items(): const_nodes |= constraints if len(const_nodes) > 0: maya.cmds.delete(list(const_nodes)) # Set keyframes (per-frame) on controlled nodes for ctrl_node, (_, ctrlled_nodes) in ctrl_to_ctrlled_map.items(): times = keytime_obj.get_times(ctrl_node, sparse) or fallback_times ctrl = tfm_utils.TransformNode(node=ctrl_node) for ctrlled_node in ctrlled_nodes: ctrlled = tfm_utils.TransformNode(node=ctrlled_node) tfm_utils.set_transform_values(cache, times, ctrl, ctrlled, delete_static_anim_curves=False) # Re-parent controller child nodes under controlled node. ctrl_children = maya.cmds.listRelatives( ctrl_node, children=True, shapes=False, fullPath=True, type='transform', ) or [] for child_node in ctrl_children: maya.cmds.parent(child_node, ctrlled_node, absolute=True) # Delete controller nodes ctrl_nodes = ctrl_to_ctrlled_map.keys() if len(ctrl_nodes) > 0: maya.cmds.delete(ctrl_nodes) return list(ctrlled_nodes)
def reparent(children, parent, sparse=True, delete_static_anim_curves=False): """ Reparent the children under the given parent. :param children: List of child nodes to be modified. :type children: [TransformNode, ..] :param parent: The new parent node for children, or None means un-parent. :type parent: TransformNode or None :param sparse: Keyframe animation on the children each frame (dense) or sparse (only at keyframes). :type sparse: bool :param delete_static_anim_curves: Delete any animCurves that all have the same values. :type delete_static_anim_curves: bool :returns: List of 'children' TransformNodes modified, will not contain child nodes if the child is already parented under 'parent'. :rtype: [TransformNode, ..] """ assert len(children) > 0 assert isinstance(children[0], tfm_utils.TransformNode) assert parent is None or isinstance(parent, tfm_utils.TransformNode) assert isinstance(sparse, bool) assert isinstance(delete_static_anim_curves, bool) children_nodes = [tn.get_node() for tn in children] parent_parent_nodes = [] if parent is not None: parent_node = parent.get_node() parent_parent_nodes = [parent_node] parent_parent_nodes += node_utils.get_node_parents(parent_node) or [] # Query keyframe times on each node attribute start_frame, end_frame = time_utils.get_maya_timeline_range_outer() keytime_obj = keytime_utils.KeyframeTimes() for child_node in children_nodes: child_parent_nodes = list(parent_parent_nodes) child_parent_nodes += node_utils.get_node_parents(child_node) or [] keytime_obj.add_node_attrs(child_node, TFM_ATTRS, start_frame, end_frame, parents=child_parent_nodes) fallback_frame_range = keytime_obj.sum_frame_range_for_nodes( children_nodes) fallback_times = list( range(fallback_frame_range[0], fallback_frame_range[1] + 1)) # Query current transforms tfm_cache = tfm_utils.TransformMatrixCache() for tfm_node, node in zip(children, children_nodes): times = keytime_obj.get_times(node, sparse) or fallback_times tfm_cache.add_node_attr(tfm_node, 'worldMatrix[0]', times) tfm_cache.process() # Apply parenting logic for the children nodes. changed_list = [False] * len(children) if parent is not None: parent_node = parent.get_node() assert maya.cmds.objExists(parent_node) for i, tfm_node in enumerate(children): node = tfm_node.get_node() current_parent = tfm_node.get_parent() if current_parent == parent: continue maya.cmds.parent(node, parent_node, absolute=True) changed_list[i] = True else: for i, (tfm_node, node) in enumerate(zip(children, children_nodes)): current_parent = tfm_node.get_parent() if current_parent is None: continue maya.cmds.parent(node, world=True, absolute=True) changed_list[i] = True assert len(changed_list) == len(children) # Set transforms again. changed_tfm_nodes = [ tn for tn, c in zip(children, changed_list) if c is True ] for tfm_node in changed_tfm_nodes: node = tfm_node.get_node() times = keytime_obj.get_times(node, sparse) or [] if len(times) > 0: tfm_utils.set_transform_values( tfm_cache, times, tfm_node, tfm_node, delete_static_anim_curves=delete_static_anim_curves, ) return changed_tfm_nodes