def apply(self): form = self.getSubForm() children_nodes = form.getChildrenNodes() parent_node = form.getParentNode() LOG.debug('children_nodes: %r', children_nodes) LOG.debug('parent_node: %r', parent_node) # Store transform nodes (to be restored after tool is run). children_tfm_nodes = [ tfm_utils.TransformNode(node=n) for n in children_nodes ] if parent_node is not None: parent_tfm_node = tfm_utils.TransformNode(node=parent_node) # Ensure we have enough nodes. msg = '' if parent_node is None: msg = 'Not enough nodes, choose at least 1 node.' else: msg = ('Not enough children nodes, ' 'choose at least 1 child node.') if len(children_nodes) == 0: LOG.error(msg) return tool.reparent(children_nodes, parent_node) # Update children and parent nodes after reparent # process. Updates the UI. children_nodes = [tn.get_node() for tn in children_tfm_nodes] form.setChildrenNodes(children_nodes) if parent_node is None: form.setParentNode([]) else: form.setParentNode([parent_tfm_node.get_node()]) return
def create_scene_b(self): """ Three transforms, 2 children under 1 parent. No keyframes. - A - B - C """ tfm_a = maya.cmds.createNode('transform') maya.cmds.setAttr(tfm_a + '.translateX', 10.0) maya.cmds.setAttr(tfm_a + '.translateY', 20.0) maya.cmds.setAttr(tfm_a + '.translateZ', 30.0) tfm_node_a = tfm_utils.TransformNode(node=tfm_a) tfm_b = maya.cmds.createNode('transform', parent=tfm_a) maya.cmds.setAttr(tfm_b + '.translateX', -10.0) maya.cmds.setAttr(tfm_b + '.translateY', -20.0) maya.cmds.setAttr(tfm_b + '.translateZ', -30.0) tfm_node_b = tfm_utils.TransformNode(node=tfm_b) tfm_c = maya.cmds.createNode('transform', parent=tfm_a) maya.cmds.setAttr(tfm_b + '.translateX', -12.0) maya.cmds.setAttr(tfm_b + '.translateY', -22.0) maya.cmds.setAttr(tfm_b + '.translateZ', -32.0) tfm_node_c = tfm_utils.TransformNode(node=tfm_c) return tfm_node_a, tfm_node_b, tfm_node_c
def reparent_under_node(): """ Re-parent the selection under the last selected node. """ frame = maya.cmds.currentTime(query=True) nodes = maya.cmds.ls(selection=True, long=True, type='transform') or [] if len(nodes) < 2: msg = ('Not enough objects selected, ' 'select at least 1 child and 1 parent node.') LOG.warn(msg) return with tools_utils.tool_context(disable_viewport=True, use_undo_chunk=False, use_dg_evaluation_mode=False, restore_current_frame=False, pre_update_frame=False): children = nodes[:-1] parent = nodes[-1] children_tfm_nodes = [ tfm_utils.TransformNode(node=n) for n in children ] parent_tfm_node = tfm_utils.TransformNode(node=parent) lib.reparent(children_tfm_nodes, parent_tfm_node, sparse=True) children = [tn.get_node() for tn in children_tfm_nodes] maya.cmds.select(children, replace=True) # Trigger Maya to refresh. maya.cmds.currentTime(frame, update=True) maya.cmds.refresh(currentView=True, force=False) return
def parent(src_nodes, dst_node, current_frame=None, eval_mode=None): """ Parent nodes under a new parent node. :param src_nodes: List of nodes to reparent. :type src_nodes: [str, ..] :param dst_node: The new parent node for the given source nodes. :type dst_node: 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_* """ assert len(src_nodes) > 0 assert len(dst_node) > 0 if current_frame is None: current_frame = maya.cmds.currentTime(query=True) assert current_frame is not None src_tfm_nodes = [tfm_utils.TransformNode(node=n) for n in src_nodes] tfm_dst_node = tfm_utils.TransformNode(node=dst_node) # Query keyframe times on each node attribute key_times_map = time_utils.get_keyframe_times_for_node_attrs( src_nodes, const.TFM_ATTRS) # Create Transform Cache, add and process cache. times = [] cache = tfm_utils.TransformMatrixCache() for src_tfm_node in src_tfm_nodes: src_node = src_tfm_node.get_node() times = key_times_map.get(src_node, [current_frame]) cache.add_node(src_tfm_node, times) cache.process(eval_mode=eval_mode) # Re-parent the nodes. dst_node = tfm_dst_node.get_node() src_nodes = [tfm_node.get_node() for tfm_node in src_tfm_nodes] maya.cmds.parent(src_nodes, dst_node, relative=True) # Set transforms for all source nodes. # anim_curves = [] for src_tfm_node in src_tfm_nodes: src_node = src_tfm_node.get_node() src_times = key_times_map.get(src_node, [current_frame]) assert len(src_times) > 0 tfm_utils.set_transform_values(cache, src_times, src_tfm_node, src_tfm_node, delete_static_anim_curves=False) src_nodes = [tfm_node.get_node() for tfm_node in src_tfm_nodes] return src_nodes
def reparent_under_node(): """ Re-parent the selection under the last selected node. """ frame = maya.cmds.currentTime(query=True) nodes = maya.cmds.ls(selection=True, long=True, type='transform') or [] if len(nodes) < 2: msg = ('Not enough objects selected, ' 'select at least 1 child and 1 parent node.') LOG.warn(msg) return try: viewport.viewport_turn_off() children = nodes[:-1] parent = nodes[-1] children_tfm_nodes = [tfm_utils.TransformNode(node=n) for n in children] parent_tfm_node = tfm_utils.TransformNode(node=parent) lib.reparent(children_tfm_nodes, parent_tfm_node, sparse=True) children = [tn.get_node() for tn in children_tfm_nodes] maya.cmds.select(children, replace=True) finally: viewport.viewport_turn_on() # Trigger Maya to refresh. maya.cmds.currentTime(frame, update=True) maya.cmds.refresh(currentView=True, force=False) return
def test_set_transform_values(self): """ """ start_frame = 1001 end_frame = 1101 node = maya.cmds.createNode('transform') maya.cmds.setKeyframe(node, attribute='translateX', time=start_frame, value=-100.0) maya.cmds.setKeyframe(node, attribute='translateX', time=end_frame, value=100.0) maya.cmds.setKeyframe(node, attribute='translateY', time=start_frame, value=-10.0) maya.cmds.setKeyframe(node, attribute='translateY', time=end_frame, value=10.0) maya.cmds.setKeyframe(node, attribute='rotateY', time=start_frame, value=90.0) maya.cmds.setKeyframe(node, attribute='rotateY', time=end_frame, value=-90.0) frame_range = list(range(start_frame, end_frame + 1)) tfm_node = mod.TransformNode(node=node) tfm_cache = mod.TransformMatrixCache() tfm_cache.add_node_attr(tfm_node, 'worldMatrix[0]', frame_range) tfm_cache.process() dst_node = maya.cmds.createNode('transform') dst_tfm_node = mod.TransformNode(node=dst_node) mod.set_transform_values(tfm_cache, frame_range, tfm_node, dst_tfm_node, delete_static_anim_curves=True, ) # save the output scene file path = 'test_transform.ma' path = self.get_data_path(path) maya.cmds.file(rename=path) maya.cmds.file(save=True, type='mayaAscii', force=True) return
def test_TransformNode_usage(self): start_frame = 1001 end_frame = 1101 times = list(range(start_frame, end_frame)) maya_node = maya.cmds.createNode('transform', name='myNode') tfm_node = mod.TransformNode(node=maya_node) node = tfm_node.get_node() node_uuid = tfm_node.get_node_uuid() tfm_node_parents = tfm_node.get_parents() tfm_node_b = mod.TransformNode() tfm_node_b.set_node('myNode') return
def unparent_to_world(): """ Un-parent the selected nodes into world space. """ frame = maya.cmds.currentTime(query=True) nodes = maya.cmds.ls(selection=True, long=True, type='transform') or [] if len(nodes) == 0: msg = ('Not enough objects selected, ' 'select at least 1 transform node.') LOG.warn(msg) return with tools_utils.tool_context(disable_viewport=True, use_undo_chunk=True, use_dg_evaluation_mode=False, restore_current_frame=False, pre_update_frame=False): tfm_nodes = [tfm_utils.TransformNode(node=n) for n in nodes] lib.reparent(tfm_nodes, None, sparse=True) nodes = [tn.get_node() for tn in tfm_nodes] maya.cmds.select(nodes, replace=True) # Trigger Maya to refresh. maya.cmds.currentTime(frame, update=True) maya.cmds.refresh(currentView=True, force=False) return
def test_reparent_unparent_with_sparse_keyframes(self): name = 'reparent_sparse_keyframes.ma' path = self.get_data_path('scenes', name) maya.cmds.file(path, open=True, force=True) tfm_a = 'pSphere1' tfm_b = 'pCube1' tfm_node_a = tfm_utils.TransformNode(node=tfm_a) tfm_node_b = tfm_utils.TransformNode(node=tfm_b) # Parent sphere under cube. tfm_nodes = lib.reparent([tfm_node_a], tfm_node_b, sparse=True, delete_static_anim_curves=True) tfm_node_c = tfm_nodes[0] node = tfm_node_c.get_node() plug = node + '.translateX' times = maya.cmds.keyframe(plug, query=True, timeChange=True) self.assertEqual(len(times), 5) self.assertEqual(sorted(times), sorted([1, 16, 61, 98, 120])) self.assertEqual(len(tfm_nodes), 1) new_parent = tfm_node_a.get_parent() self.assertEqual(new_parent, tfm_node_b) # Unparent sphere to world tfm_nodes = lib.reparent([tfm_node_c], None, sparse=True, delete_static_anim_curves=True) tfm_node_d = tfm_nodes[0] # save the output name = 'reparent_unparent_sparse_with_keyframes_after.ma' path = self.get_data_path(name) maya.cmds.file(rename=path) maya.cmds.file(save=True, type='mayaAscii', force=True) node = tfm_node_d.get_node() plug = node + '.translateX' times = maya.cmds.keyframe(plug, query=True, timeChange=True) self.assertEqual(len(times), 5) self.assertEqual(sorted(times), sorted([1, 16, 61, 98, 120])) self.assertEqual(len(tfm_nodes), 1) new_parent = tfm_node_a.get_parent() self.assertIs(new_parent, None)
def test_TransformMatrixCache_init(self): start_frame = 1001 end_frame = 1101 times = list(range(start_frame, end_frame)) node = maya.cmds.createNode('transform') tfm_node = mod.TransformNode(node=node) tfm_matrix_cache = mod.TransformMatrixCache() return
def create_scene_a(self): """ Simple scene, two transforms, both without any keyframes. - A - B """ tfm_a = maya.cmds.createNode('transform') maya.cmds.setAttr(tfm_a + '.translateX', 10.0) maya.cmds.setAttr(tfm_a + '.translateY', 20.0) maya.cmds.setAttr(tfm_a + '.translateZ', 30.0) tfm_node_a = tfm_utils.TransformNode(node=tfm_a) tfm_b = maya.cmds.createNode('transform') maya.cmds.setAttr(tfm_b + '.translateX', -10.0) maya.cmds.setAttr(tfm_b + '.translateY', -20.0) maya.cmds.setAttr(tfm_b + '.translateZ', -30.0) tfm_node_b = tfm_utils.TransformNode(node=tfm_b) return tfm_node_a, tfm_node_b
def reparent_under_node(): """ Re-parent the selection under the last selected node. """ nodes = maya.cmds.ls(selection=True, long=True, type='transform') or [] if len(nodes) < 2: msg = ('Not enough objects selected, ' 'select at least 1 child and 1 parent node.') LOG.warn(msg) return children = nodes[:-1] parent = nodes[-1] children_tfm_nodes = [tfm_utils.TransformNode(node=n) for n in children] parent_tfm_node = tfm_utils.TransformNode(node=parent) lib.reparent(children_tfm_nodes, parent_tfm_node, sparse=True) children = [tn.get_node() for tn in children_tfm_nodes] maya.cmds.select(children, replace=True) __refresh_maya() return
def test_TransformMatrixCache_usage(self): start_frame = 1001 end_frame = 1101 times = list(range(start_frame, end_frame)) node = maya.cmds.createNode('transform') tfm_node = mod.TransformNode(node=node) tfm_matrix_cache = mod.TransformMatrixCache() tfm_matrix_cache.add_node(tfm_node, times) tfm_matrix_cache.process() attr_name = 'translateX' tfm_matrix_cache.get_node_attr_matrix(tfm_node, attr_name, times) return
def test_detect_rotate_pivot_non_zero(self): start_frame = 1001 end_frame = 1101 tfm_node = maya.cmds.createNode('transform') tfm = mod.TransformNode(tfm_node) self.assertFalse(mod.detect_rotate_pivot_non_zero(tfm)) path = self.get_data_path('scenes', 'bookHierarchy.ma') maya.cmds.file(path, open=True, force=True) book_node = 'book_GRP' spine_node = 'spine_GRP' cover_node = 'front_cover_GRP' book_tfm = mod.TransformNode(book_node) spine_tfm = mod.TransformNode(spine_node) cover_tfm = mod.TransformNode(cover_node) self.assertFalse(mod.detect_rotate_pivot_non_zero(book_tfm)) self.assertTrue(mod.detect_rotate_pivot_non_zero(spine_tfm)) self.assertTrue(mod.detect_rotate_pivot_non_zero(cover_tfm)) return
def unparent_to_world(): """ Un-parent the selected nodes into world space. """ nodes = maya.cmds.ls(selection=True, long=True, type='transform') or [] if len(nodes) == 0: msg = ('Not enough objects selected, ' 'select at least 1 transform node.') LOG.warn(msg) return tfm_nodes = [tfm_utils.TransformNode(node=n) for n in nodes] lib.reparent(tfm_nodes, None, sparse=True) nodes = [tn.get_node() for tn in tfm_nodes] maya.cmds.select(nodes, replace=True) __refresh_maya() return
def unparent_to_world(): """ Un-parent the selected nodes into world space. """ frame = maya.cmds.currentTime(query=True) nodes = maya.cmds.ls(selection=True, long=True, type='transform') or [] if len(nodes) == 0: msg = ('Not enough objects selected, ' 'select at least 1 transform node.') LOG.warn(msg) return try: viewport.viewport_turn_off() tfm_nodes = [tfm_utils.TransformNode(node=n) for n in nodes] lib.reparent(tfm_nodes, None, sparse=True) nodes = [tn.get_node() for tn in tfm_nodes] maya.cmds.select(nodes, replace=True) finally: viewport.viewport_turn_on() # Trigger Maya to refresh. maya.cmds.currentTime(frame, update=True) maya.cmds.refresh(currentView=True, force=False) return
def create_scene_d(self, start, end): """ Three transforms, 2 transforms parented 1 parent. With keyframes. - A - B - C """ tfm_a = maya.cmds.createNode('transform') maya.cmds.setKeyframe(tfm_a, attribute='translateX', value=10.0, time=start) maya.cmds.setKeyframe(tfm_a, attribute='translateY', value=20.0, time=start) maya.cmds.setKeyframe(tfm_a, attribute='translateZ', value=30.0, time=start) maya.cmds.setKeyframe(tfm_a, attribute='translateX', value=-10.0, time=end) maya.cmds.setKeyframe(tfm_a, attribute='translateY', value=-20.0, time=end) maya.cmds.setKeyframe(tfm_a, attribute='translateZ', value=-30.0, time=end) tfm_node_a = tfm_utils.TransformNode(node=tfm_a) tfm_b = maya.cmds.createNode('transform', parent=tfm_a) maya.cmds.setKeyframe(tfm_b, attribute='translateX', value=30.0, time=start) maya.cmds.setKeyframe(tfm_b, attribute='translateY', value=20.0, time=start) maya.cmds.setKeyframe(tfm_b, attribute='translateZ', value=10.0, time=start) maya.cmds.setKeyframe(tfm_b, attribute='translateX', value=-30.0, time=end) maya.cmds.setKeyframe(tfm_b, attribute='translateY', value=-20.0, time=end) maya.cmds.setKeyframe(tfm_b, attribute='translateZ', value=-10.0, time=end) tfm_node_b = tfm_utils.TransformNode(node=tfm_b) tfm_c = maya.cmds.createNode('transform', parent=tfm_a) maya.cmds.setKeyframe(tfm_c, attribute='translateX', value=-32.0, time=start) maya.cmds.setKeyframe(tfm_c, attribute='translateY', value=-22.0, time=start) maya.cmds.setKeyframe(tfm_c, attribute='translateZ', value=-12.0, time=start) maya.cmds.setKeyframe(tfm_c, attribute='translateX', value=32.0, time=end) maya.cmds.setKeyframe(tfm_c, attribute='translateY', value=22.0, time=end) maya.cmds.setKeyframe(tfm_c, attribute='translateZ', value=12.0, time=end) tfm_node_c = tfm_utils.TransformNode(node=tfm_c) return tfm_node_a, tfm_node_b, tfm_node_c
def create_camera_body_track_scale_rig(name, camera, scene, body_track_controls, scale_rig_type): """ Create a camera track scale rig. :param name: Scale rig name. :type name: str :param camera: Camera node. :type camera: Transform node :param scene: Scene node. :type scene: Transform node or None :param body_track_controls: Body track controls transforms. :type body_track_controls: Transforms list or [] :param scale_rig_type: Which type of scale rig to be created? mmSolver.tools.camerabodytrackscalerigbake.constant.SCALE_RIG_LIST. :type: str :rtype: [str] """ # Create camera witness attrs = ['tx', 'ty', 'tz', 'rx', 'ry', 'rz'] controller_type = createcontroller2_const.CONTROLLER_TYPE_WORLD_SPACE if scale_rig_type == const.SCALE_RIG_TYPE_BODY_TRACK: camera_witness = _create_scale_rig_main_grp(name+suffix+main_grp_suffix, str(scene), body_track_controls, const.SCALE_RIG_TYPE_BODY_TRACK) if scale_rig_type == const.SCALE_RIG_TYPE_CAMERA_TRACK: camera_witness = cmds.group(name=name+suffix, empty=True) parent_con = cmds.parentConstraint(camera, camera_witness, maintainOffset=False) camera_witness = cmds.ls(camera_witness) fastbake_lib.bake_attributes(camera_witness, attrs, frame_start, frame_end, smart_bake=False) cmds.delete(parent_con) # Create rig controls witness body_track_controls_witness = [] for control in body_track_controls: control_witness = createcontroller2_lib.create_controller(name, control, control, cmds.spaceLocator(), frame_start, frame_end, controller_type, smart_bake=False, camera=None) body_track_controls_witness.append(control_witness[0]) # Reparent children_nodes = [tfm_utils.TransformNode(node=n) for n in body_track_controls_witness] parent_node = tfm_utils.TransformNode(node=camera_witness[0]) reparent2_lib.reparent(children_nodes, parent_node, frame_range_mode='timeline_inner', start_frame=frame_start, end_frame=frame_end, bake_mode='full_bake', rotate_order_mode='use_existing', delete_static_anim_curves=False) _break_scale_attributes(children_nodes) # Body track scale rig if scale_rig_type == const.SCALE_RIG_TYPE_BODY_TRACK: # Break body track controls witness scale attributes body_track_control_nodes = [tfm_utils.TransformNode(node=n) for n in body_track_controls] _break_scale_attributes(body_track_control_nodes) # Scale constraint to body track controls for node in body_track_control_nodes: cmds.scaleConstraint(parent_node.get_node(), node.get_node(), maintainOffset=True) cmds.select(parent_node.get_node(), replace=True) # Camera track scale rig if scale_rig_type == const.SCALE_RIG_TYPE_CAMERA_TRACK: grand_parent = _create_scale_rig_main_grp(name+suffix+main_grp_suffix, str(scene), body_track_controls, const.SCALE_RIG_TYPE_CAMERA_TRACK) con = cmds.parentConstraint(parent_node.get_node(), grand_parent, maintainOffset=False) cmds.delete(con) grand_parent_node = tfm_utils.TransformNode(node=grand_parent) reparent2_lib.reparent([parent_node], grand_parent_node, frame_range_mode='timeline_inner', start_frame=frame_start, end_frame=frame_end, bake_mode='full_bake', rotate_order_mode='use_existing', delete_static_anim_curves=False) _break_scale_attributes([parent_node]) # Break scene scale attributes node = cmds.ls(scene, long=True, type='transform') scene_node = tfm_utils.TransformNode(node=node[0]) _break_scale_attributes([scene_node]) cmds.parentConstraint(grand_parent, scene, maintainOffset=True) cmds.scaleConstraint(grand_parent, scene, maintainOffset=True) # Create scale expression attrs = ['sx', 'sy', 'sz'] parent = parent_node.get_node() for attr in attrs: exp = str(str(parent)+'.'+attr)+'='+'1'+'/'+str(grand_parent)+'.'+attr cmds.expression(string=exp, object=str(parent), alwaysEvaluate=True, unitConversion='all') cmds.select(grand_parent, replace=True)
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 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_nodes, parent_node, frame_range_mode=None, start_frame=None, end_frame=None, bake_mode=None, rotate_order_mode=None, delete_static_anim_curves=None): """ Reparent the children under the given parent. :param children_nodes: List of child nodes to be modified. :type children_nodes: [TransformNode, ..] :param parent_node: The new parent node for children, or None means un-parent. :type parent_node: TransformNode or None :param frame_range_mode: What frame range to use for baking. :type frame_range_mode: FRAME_RANGE_MODE_VALUES :param start_frame: First frame of custom frame range. :type start_frame: int or None :param end_frame: Last frame of custom frame range. :type end_frame: int or None :param bake_mode: How to bake the object? Where to place keyframes. :type bake_mode: BAKE_MODE_VALUES :param rotate_order_mode: :type rotate_order_mode: ROTATE_ORDER_MODE_VALUES :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_nodes) > 0 assert isinstance(children_nodes[0], tfm_utils.TransformNode) assert parent_node is None or isinstance(parent_node, tfm_utils.TransformNode) if isinstance(parent_node, tfm_utils.TransformNode): assert maya.cmds.objExists(parent_node.get_node()) if frame_range_mode is None: frame_range_mode = const.FRAME_RANGE_MODE_TIMELINE_INNER_VALUE if bake_mode is None: bake_mode = const.BAKE_MODE_FULL_BAKE_VALUE if rotate_order_mode is None: rotate_order_mode = const.ROTATE_ORDER_MODE_USE_EXISTING_VALUE assert frame_range_mode in const.FRAME_RANGE_MODE_VALUES assert bake_mode in const.BAKE_MODE_VALUES assert rotate_order_mode in const.ROTATE_ORDER_MODE_VALUES assert isinstance(delete_static_anim_curves, bool) # Get frame range frame_range = time_utils.get_frame_range(frame_range_mode) # Get bake mode. sparse = None if bake_mode == const.BAKE_MODE_FULL_BAKE_VALUE: sparse = False elif bake_mode == const.BAKE_MODE_SMART_BAKE_VALUE: sparse = True else: assert False smart_bake = sparse is True # Get rotate order mode. rotate_order = None if rotate_order_mode == const.ROTATE_ORDER_MODE_USE_EXISTING_VALUE: rotate_order = None else: order_str = str(rotate_order_mode) rotate_order = const_utils.ROTATE_ORDER_STR_TO_INDEX[order_str] # Filter out invalid nodes. # # There is no need to un-parent to the world, if the node is # already parented to the world. msg = 'Skipping Re-Parent! Node is already parented to world: node=%r' if parent_node is None: tmp_children_nodes = children_nodes children_nodes = [] for child_node in tmp_children_nodes: node = child_node.get_node() current_parent = maya.cmds.listRelatives(node, parent=True) if not current_parent: LOG.warn(msg, node) else: children_nodes.append(child_node) if len(children_nodes) == 0: return # Sort nodes by depth, deeper nodes first, so we do do not remove # parents before children. children = [tn.get_node() for tn in children_nodes] children = node_utils.sort_nodes_by_depth(children, reverse=True) children_nodes = [tfm_utils.TransformNode(node=n) for n in children] loc_tfms = [] for i, child in enumerate(children): tfm_name = 'dummy' + str(i + 1) shp_name = 'dummy' + str(i + 1) + 'Shape' loc_tfm = maya.cmds.createNode('transform', name=tfm_name) maya.cmds.createNode('locator', name=shp_name, parent=loc_tfm) # Constrain the locator to the child, in translate, rotate and # scale. maya.cmds.pointConstraint(child, loc_tfm) maya.cmds.orientConstraint(child, loc_tfm) maya.cmds.scaleConstraint(child, loc_tfm) loc_tfms.append(loc_tfm) # Bake the locator results _bake_nodes(loc_tfms, frame_range, smart_bake=True) maya.cmds.delete(loc_tfms, constraints=True) for child, child_node, loc_tfm in zip(children, children_nodes, loc_tfms): # Find which attributes are partially locked, so we can avoid # modifying the attributes. translate_skip = _get_node_attr_skip(child, 'translate') rotate_skip = _get_node_attr_skip(child, 'rotate') scale_skip = _get_node_attr_skip(child, 'scale') # Warn if the child transform is completely locked. if (translate_skip == SKIP_ALL and rotate_skip == SKIP_ALL and scale_skip == SKIP_ALL): msg = 'Skipping Re-Parent! Cannot modify any attributes: node=%r' LOG.warn(msg, child) continue # Warn the user if some values cannot be modified. msg_base = 'Cannot modify attributes: node=%r attrs={} skip=%r' if translate_skip != 'none': msg = msg_base.format('translate') LOG.warn(msg, child, translate_skip) if rotate_skip != 'none': msg = msg_base.format('rotate') LOG.warn(msg, child, rotate_skip) if scale_skip != 'none': msg = msg_base.format('scale') LOG.warn(msg, child, scale_skip) # Remove keyframes from child transform. maya.cmds.cutKey(child, time=frame_range, attribute='translateX') maya.cmds.cutKey(child, time=frame_range, attribute='translateY') maya.cmds.cutKey(child, time=frame_range, attribute='translateZ') maya.cmds.cutKey(child, time=frame_range, attribute='rotateX') maya.cmds.cutKey(child, time=frame_range, attribute='rotateY') maya.cmds.cutKey(child, time=frame_range, attribute='rotateZ') maya.cmds.cutKey(child, time=frame_range, attribute='scaleX') maya.cmds.cutKey(child, time=frame_range, attribute='scaleY') maya.cmds.cutKey(child, time=frame_range, attribute='scaleZ') maya.cmds.cutKey(child, time=frame_range, attribute='rotateOrder') # If the parent is empty, parent to the world... if parent_node is None: maya.cmds.parent(child, world=True) else: # Else, constrain the child to the parent, # delete the history, and parent the child under # the parent. parent = parent_node.get_node() if translate_skip != SKIP_ALL: maya.cmds.pointConstraint(parent, child, skip=translate_skip) if rotate_skip != SKIP_ALL: maya.cmds.orientConstraint(parent, child, skip=rotate_skip) if scale_skip != SKIP_ALL: maya.cmds.scaleConstraint(parent, child, skip=scale_skip) maya.cmds.delete(child, constraints=True) maya.cmds.parent(child, parent) child = child_node.get_node() # Change Rotate order. if rotate_order is not None: node_attr = child + '.rotateOrder' settable = maya.cmds.getAttr(node_attr, settable=True) if settable: maya.cmds.setAttr(node_attr, rotate_order) else: LOG.warn('Cannot change rotate order: %r', child) # Constrain the child to match the locator. if translate_skip != SKIP_ALL: maya.cmds.pointConstraint(loc_tfm, child, skip=translate_skip) if rotate_skip != SKIP_ALL: maya.cmds.orientConstraint(loc_tfm, child, skip=rotate_skip) if scale_skip != SKIP_ALL: maya.cmds.scaleConstraint(loc_tfm, child, skip=scale_skip) # Bake the children's results. children = [tn.get_node() for tn in children_nodes] _bake_nodes(children, frame_range, smart_bake=smart_bake) maya.cmds.delete(children, constraints=True) maya.cmds.filterCurve(children) if delete_static_anim_curves is True: maya.cmds.delete(children, staticChannels=True) # Clean up redundant nodes. maya.cmds.delete(loc_tfms) return
def test_get_transform_matrix_list_90degrees(self): path = self.get_data_path('scenes', 'bookHierarchy.ma') maya.cmds.file(path, open=True, force=True) book_node = 'book_GRP' spine_node = 'spine_GRP' cover_node = 'front_cover_GRP' latch_node = 'latch_GRP' maya.cmds.setAttr(book_node + '.ty', 10.0) maya.cmds.setAttr(book_node + '.rz', 90.0) # <<< 90 degrees maya.cmds.setAttr(spine_node + '.rz', 90.0) maya.cmds.setAttr(cover_node + '.rz', 90.0) book_tfm = mod.TransformNode(book_node) spine_tfm = mod.TransformNode(spine_node) cover_tfm = mod.TransformNode(cover_node) latch_tfm = mod.TransformNode(latch_node) tfm_nodes = [book_tfm, spine_tfm, cover_tfm, latch_tfm] current_frame = maya.cmds.currentTime(query=True) frame_range = [current_frame] # Query the transform matrix for the nodes cache = mod.TransformMatrixCache() for tfm_node in tfm_nodes: cache.add_node(tfm_node, frame_range) cache.process() book_world_matrix_list = mod.get_transform_matrix_list( cache, frame_range, book_tfm) self.assertEqual(len(book_world_matrix_list), 1) book_world_matrix = list(book_world_matrix_list[0].asMatrix()) spine_world_matrix_list = mod.get_transform_matrix_list( cache, frame_range, spine_tfm) self.assertEqual(len(spine_world_matrix_list), 1) spine_world_matrix = list(spine_world_matrix_list[0].asMatrix()) cover_world_matrix_list = mod.get_transform_matrix_list( cache, frame_range, cover_tfm) self.assertEqual(len(cover_world_matrix_list), 1) cover_world_matrix = list(cover_world_matrix_list[0].asMatrix()) latch_world_matrix_list = mod.get_transform_matrix_list( cache, frame_range, latch_tfm) self.assertEqual(len(latch_world_matrix_list), 1) latch_world_matrix = list(latch_world_matrix_list[0].asMatrix()) # Expected Matrices expected_book_matrix = [ 0.0, 1.0, 0.0, 0.0, -1.0, 0.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 10.0, 0.0, 1.0 ] expected_spine_matrix = [ -1.0, 0.0, 0.0, 0.0, 0.0, -1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.3518918752670288, 8.476484298706055, 0.0029969215393066406, 1.0 ] expected_cover_matrix = [ 0.0, -1.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.3488234877586365, 7.9185943603515625, 0.0029969215393066406, 1.0 ] expected_latch_matrix = [ 0.0, 1.0, 0.0, 0.0, -1.0, 0.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.3430972993373871, 11.661497116088867, 0.0001980811357498169, 1.0 ] # Confirm matrix values in the cache are correct self.assertGreater( closeness.compare_floats(book_world_matrix, expected_book_matrix), closeness.DEFAULT_SIGNIFICANT_DIGITS) self.assertGreater( closeness.compare_floats(spine_world_matrix, expected_spine_matrix), closeness.DEFAULT_SIGNIFICANT_DIGITS) self.assertGreater( closeness.compare_floats(cover_world_matrix, expected_cover_matrix), closeness.DEFAULT_SIGNIFICANT_DIGITS) self.assertGreater( closeness.compare_floats(latch_world_matrix, expected_latch_matrix), closeness.DEFAULT_SIGNIFICANT_DIGITS) 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 query_camera_data(cam_tfm, cam_shp, frames, rotate_order, test_disk): """ Get the camera information from the given cameras """ assert isinstance(cam_tfm, (str, unicode, basestring)) assert isinstance(cam_shp, (str, unicode, basestring)) assert len(cam_tfm) > 0 assert len(cam_shp) > 0 assert maya.cmds.objExists(cam_tfm) assert maya.cmds.objExists(cam_shp) assert isinstance(frames, (list, tuple)) cam_data = {} attr_data = {} # Get the camera name, by parsing node name. name = cam_tfm.rpartition('|')[-1] cam_data['name'] = name # Add 'translate' and 'rotate' attributes to list to evaluate. tfm_node = tfm_utils.TransformNode(cam_tfm) tfm_cache = tfm_utils.TransformMatrixCache() tfm_cache.add_node(tfm_node, frames) tfm_cache.process() tfm_mat_list = tfm_utils.get_transform_matrix_list( tfm_cache, frames, tfm_node, rotate_order=rotate_order) assert len(tfm_mat_list) == len(frames) tx_values = [] ty_values = [] tz_values = [] rx_values = [] ry_values = [] rz_values = [] prv_rot = None for f, mat in zip(frames, tfm_mat_list): tx, ty, tz, rx, ry, rz, _, _, _ = tfm_utils.decompose_matrix( mat, prv_rot) tx_values.append((f, tx)) ty_values.append((f, ty)) tz_values.append((f, tz)) rx_values.append((f, rx)) ry_values.append((f, ry)) rz_values.append((f, rz)) attr_data['translateX'] = tx_values attr_data['translateY'] = ty_values attr_data['translateZ'] = tz_values attr_data['rotateX'] = rx_values attr_data['rotateY'] = ry_values attr_data['rotateZ'] = rz_values # Get the camera shape node attributes: # - focal length # - film back # - film back offset # # The values are stored in millimetres (mm). attrs = [ ('focalLength', 'focalLength', lambda x: x), ('horizontalFilmAperture', 'filmBackWidth', lambda x: x * 25.4), ('verticalFilmAperture', 'filmBackHeight', lambda x: x * 25.4), ('horizontalFilmOffset', 'filmBackOffsetX', lambda x: x * 25.4), ('verticalFilmOffset', 'filmBackOffsetY', lambda x: x * 25.4), ] for attr, attr_name, convert_func in attrs: plug = '{0}.{1}'.format(cam_tfm, attr) attr_values = [] for f in frames: v = maya.cmds.getAttr(plug, time=f) v = convert_func(v) attr_values.append((f, v)) attr_data[attr_name] = attr_values cam_data['attr'] = attr_data return cam_data
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 reparent(children, parent): """ Reparent 'children' nodes under 'parent' node. If 'parent' is None, the children are unparented to world. All settings are taken from the UI's defaults. To change these, please use the UI (or 'configmaya' module) """ children_nodes = [tfm_utils.TransformNode(node=n) for n in children] parent_node = None if parent is not None: parent_node = tfm_utils.TransformNode(node=parent) # Get all saved re-parent options. frame_range_mode = configmaya.get_scene_option( const.CONFIG_FRAME_RANGE_MODE_KEY, default=const.DEFAULT_FRAME_RANGE_MODE) start_frame = configmaya.get_scene_option( const.CONFIG_FRAME_START_KEY, default=const.DEFAULT_FRAME_START) end_frame = configmaya.get_scene_option( const.CONFIG_FRAME_END_KEY, default=const.DEFAULT_FRAME_END) bake_mode = configmaya.get_scene_option( const.CONFIG_BAKE_MODE_KEY, default=const.DEFAULT_BAKE_MODE) rotate_order = configmaya.get_scene_option( const.CONFIG_ROTATE_ORDER_MODE_KEY, default=const.DEFAULT_ROTATE_ORDER_MODE) delete_static_anim_curves = configmaya.get_scene_option( const.CONFIG_DELETE_STATIC_ANIM_CURVES_KEY, default=const.DEFAULT_DELETE_STATIC_ANIM_CURVES) viewport_mode = const_utils.DISABLE_VIEWPORT_MODE_VP1_VALUE # Check the children nodes and prompt the user what to do prompt_user, settable_map, full_msg, confirm_msg = \ __check_modify_nodes(children) if prompt_user is True: LOG.warn(full_msg) cancel_button = 'Cancel' continue_button = 'Continue' button = maya.cmds.confirmDialog( title='Warning: Cannot Modify Nodes.', message=confirm_msg, button=[continue_button, cancel_button], defaultButton=continue_button, cancelButton=cancel_button, dismissString=cancel_button) if button == cancel_button: LOG.warn('User canceled Re-parent.') return with tools_utils.tool_context(disable_viewport=True, use_undo_chunk=True, use_dg_evaluation_mode=False, restore_current_frame=True, pre_update_frame=False, disable_viewport_mode=viewport_mode): lib.reparent( children_nodes, parent_node, frame_range_mode=frame_range_mode, start_frame=start_frame, end_frame=end_frame, bake_mode=bake_mode, rotate_order_mode=rotate_order, delete_static_anim_curves=bool(delete_static_anim_curves), ) nodes = [tn.get_node() for tn in children_nodes] maya.cmds.select(nodes, replace=True) # Trigger Maya to refresh. maya.cmds.refresh(currentView=True, force=False) return
def create_scene_c(self, start, end): """ Simple scene, two transforms, both with keyframes. - A - B """ maya.cmds.playbackOptions(edit=True, minTime=start) maya.cmds.playbackOptions(edit=True, animationStartTime=start) maya.cmds.playbackOptions(edit=True, animationEndTime=end) maya.cmds.playbackOptions(edit=True, maxTime=end) tfm_a = maya.cmds.createNode('transform') maya.cmds.setKeyframe(tfm_a, attribute='translateX', value=10.0, time=start) maya.cmds.setKeyframe(tfm_a, attribute='translateY', value=20.0, time=start) maya.cmds.setKeyframe(tfm_a, attribute='translateZ', value=30.0, time=start) maya.cmds.setKeyframe(tfm_a, attribute='translateX', value=-10.0, time=end) maya.cmds.setKeyframe(tfm_a, attribute='translateY', value=-20.0, time=end) maya.cmds.setKeyframe(tfm_a, attribute='translateZ', value=-30.0, time=end) tfm_node_a = tfm_utils.TransformNode(node=tfm_a) tfm_b = maya.cmds.createNode('transform') maya.cmds.setKeyframe(tfm_b, attribute='translateX', value=-10.0, time=start) maya.cmds.setKeyframe(tfm_b, attribute='translateY', value=-20.0, time=start) maya.cmds.setKeyframe(tfm_b, attribute='translateZ', value=-30.0, time=start) maya.cmds.setKeyframe(tfm_b, attribute='translateX', value=10.0, time=end) maya.cmds.setKeyframe(tfm_b, attribute='translateY', value=20.0, time=end) maya.cmds.setKeyframe(tfm_b, attribute='translateZ', value=30.0, time=end) tfm_node_b = tfm_utils.TransformNode(node=tfm_b) return tfm_node_a, tfm_node_b
def test_set_transform_values_with_rotate_pivot(self): path = self.get_data_path('scenes', 'bookHierarchy.ma') maya.cmds.file(path, open=True, force=True) book_node = 'book_GRP' spine_node = 'spine_GRP' cover_node = 'front_cover_GRP' maya.cmds.setAttr(book_node + '.ty', 10.0) maya.cmds.setAttr(book_node + '.rz', 90.0) maya.cmds.setAttr(spine_node + '.rz', 90.0) maya.cmds.setAttr(cover_node + '.rz', 90.0) book_tfm = mod.TransformNode(book_node) spine_tfm = mod.TransformNode(spine_node) cover_tfm = mod.TransformNode(cover_node) tfm_nodes = [book_tfm, spine_tfm, cover_tfm] current_frame = maya.cmds.currentTime(query=True) frame_range = [current_frame] # Query the transform matrix for the nodes cache = mod.TransformMatrixCache() for tfm_node in tfm_nodes: cache.add_node(tfm_node, frame_range) cache.process() book_dst_node = maya.cmds.createNode('transform', name='book_CTRL') book_dst_tfm_node = mod.TransformNode(node=book_dst_node) mod.set_transform_values(cache, frame_range, book_tfm, book_dst_tfm_node, delete_static_anim_curves=False) spine_dst_node = maya.cmds.createNode('transform', name='spine_CTRL') spine_dst_tfm_node = mod.TransformNode(node=spine_dst_node) mod.set_transform_values(cache, frame_range, spine_tfm, spine_dst_tfm_node, delete_static_anim_curves=False) cover_dst_node = maya.cmds.createNode('transform', name='cover_CTRL') cover_dst_tfm_node = mod.TransformNode(node=cover_dst_node) mod.set_transform_values(cache, frame_range, cover_tfm, cover_dst_tfm_node, delete_static_anim_curves=False) # save the output scene file path = 'test_transform_set_transforms_with_rotate_pivot.ma' path = self.get_data_path(path) maya.cmds.file(rename=path) maya.cmds.file(save=True, type='mayaAscii', force=True) # Expected Matrices expected_book_matrix = [ 0.0, 1.0, 0.0, 0.0, -1.0, 0.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 10.0, 0.0, 1.0 ] expected_spine_matrix = [ -1.0, 0.0, 0.0, 0.0, 0.0, -1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.3518918752670288, 8.476484298706055, 0.0029969215393066406, 1.0 ] expected_cover_matrix = [ 0.0, -1.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.3488234877586365, 7.9185943603515625, 0.0029969215393066406, 1.0 ] expected_spine_par_inv_matrix = [ 0.0, -1.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, -10.0, 0.0, 0.0, 1.0 ] expected_front_cover_par_inv_matrix = [ -1.0, 0.0, 0.0, 0.0, 0.0, -1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, -1.1716232898755894, 8.124592860140336, 0.0, 1.0 ] # Confirm attributes in the cache are correct book_attrs = cache.get_attrs_for_node(book_tfm) self.assertItemsEqual(book_attrs, ["worldMatrix[0]"]) attr_names_with_pivot = [ "worldMatrix[0]", "matrix", "parentInverseMatrix[0]", "rotatePivotX", "rotatePivotY", "rotatePivotZ", ] spine_attrs = cache.get_attrs_for_node(spine_tfm) self.assertItemsEqual(spine_attrs, attr_names_with_pivot) cover_attrs = cache.get_attrs_for_node(cover_tfm) self.assertItemsEqual(cover_attrs, attr_names_with_pivot) # Confirm matrix values in the cache are correct book_world_matrix = list( cache.get_node_attr(book_tfm, "worldMatrix[0]", frame_range)[0]) self.assertGreater( closeness.compare_floats(book_world_matrix, expected_book_matrix), closeness.DEFAULT_SIGNIFICANT_DIGITS) spine_par_inv_matrix = list( cache.get_node_attr(spine_tfm, "parentInverseMatrix[0]", frame_range)[0]) self.assertGreater( closeness.compare_floats(spine_par_inv_matrix, expected_spine_par_inv_matrix), closeness.DEFAULT_SIGNIFICANT_DIGITS) cover_par_inv_matrix = list( cache.get_node_attr(cover_tfm, "parentInverseMatrix[0]", frame_range)[0]) self.assertGreater( closeness.compare_floats(cover_par_inv_matrix, expected_front_cover_par_inv_matrix), closeness.DEFAULT_SIGNIFICANT_DIGITS) # Compare destination node matrices with the original book_matrix = maya.cmds.xform(book_dst_node, query=True, matrix=True, worldSpace=True) self.assertGreater( closeness.compare_floats(book_matrix, expected_book_matrix), closeness.DEFAULT_SIGNIFICANT_DIGITS) spine_matrix = maya.cmds.xform(spine_dst_node, query=True, matrix=True, worldSpace=True) self.assertGreater( closeness.compare_floats(spine_matrix, expected_spine_matrix), closeness.DEFAULT_SIGNIFICANT_DIGITS) cover_matrix = maya.cmds.xform(cover_dst_node, query=True, matrix=True, worldSpace=True) self.assertGreater( closeness.compare_floats(cover_matrix, expected_cover_matrix), closeness.DEFAULT_SIGNIFICANT_DIGITS) return
def test_get_transform_matrix_list_45degrees(self): path = self.get_data_path('scenes', 'bookHierarchy.ma') maya.cmds.file(path, open=True, force=True) book_node = 'book_GRP' spine_node = 'spine_GRP' cover_node = 'front_cover_GRP' latch_node = 'latch_GRP' maya.cmds.setAttr(book_node + '.ty', 10.0) maya.cmds.setAttr(book_node + '.rz', 45.0) # <<< 45 degrees maya.cmds.setAttr(spine_node + '.rz', 90.0) maya.cmds.setAttr(cover_node + '.rz', 90.0) book_tfm = mod.TransformNode(book_node) spine_tfm = mod.TransformNode(spine_node) cover_tfm = mod.TransformNode(cover_node) latch_tfm = mod.TransformNode(latch_node) tfm_nodes = [book_tfm, spine_tfm, cover_tfm, latch_tfm] current_frame = maya.cmds.currentTime(query=True) frame_range = [current_frame] # Query the transform matrix for the nodes cache = mod.TransformMatrixCache() for tfm_node in tfm_nodes: cache.add_node(tfm_node, frame_range) cache.process() book_world_matrix_list = mod.get_transform_matrix_list( cache, frame_range, book_tfm) self.assertEqual(len(book_world_matrix_list), 1) book_world_matrix = list(book_world_matrix_list[0].asMatrix()) spine_world_matrix_list = mod.get_transform_matrix_list( cache, frame_range, spine_tfm) self.assertEqual(len(spine_world_matrix_list), 1) spine_world_matrix = list(spine_world_matrix_list[0].asMatrix()) cover_world_matrix_list = mod.get_transform_matrix_list( cache, frame_range, cover_tfm) self.assertEqual(len(cover_world_matrix_list), 1) cover_world_matrix = list(cover_world_matrix_list[0].asMatrix()) latch_world_matrix_list = mod.get_transform_matrix_list( cache, frame_range, latch_tfm) self.assertEqual(len(latch_world_matrix_list), 1) latch_world_matrix = list(latch_world_matrix_list[0].asMatrix()) # Expected Matrices expected_book_matrix = [ 0.7071067811865475, 0.7071067811865476, 0.0, 0.0, -0.7071067811865476, 0.7071067811865475, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 10.0, 0.0, 1.0 ] expected_spine_matrix = [ -0.7071067811865475, 0.7071067811865477, 0.0, 0.0, -0.7071067811865477, -0.7071067811865475, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, -0.8284631523833599, 8.673886585125107, 0.0029969215393066406, 1.0 ] expected_cover_matrix = [ -0.7071067811865479, -0.7071067811865474, 0.0, 0.0, 0.7071067811865474, -0.7071067811865479, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, -1.2251205885640575, 8.281568504173393, 0.0029969215393066406, 1.0 ] expected_latch_matrix = [ 0.7071067811865475, 0.7071067811865476, 0.0, 0.0, -0.7071067811865476, 0.7071067811865475, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 1.417462229728698, 10.932249069213867, 0.0001980811357498169, 1.0 ] # Confirm matrix values in the cache are correct self.assertGreater( closeness.compare_floats(book_world_matrix, expected_book_matrix), closeness.DEFAULT_SIGNIFICANT_DIGITS) tol = 0.000001 mat_a = OpenMaya2.MMatrix(book_world_matrix) mat_b = OpenMaya2.MMatrix(expected_book_matrix) self.assertTrue(mat_a.isEquivalent(mat_b, tol)) self.assertGreater( closeness.compare_floats(spine_world_matrix, expected_spine_matrix), closeness.DEFAULT_SIGNIFICANT_DIGITS) mat_a = OpenMaya2.MMatrix(spine_world_matrix) mat_b = OpenMaya2.MMatrix(expected_spine_matrix) self.assertTrue(mat_a.isEquivalent(mat_b, tol)) self.assertGreater( closeness.compare_floats(cover_world_matrix, expected_cover_matrix), closeness.DEFAULT_SIGNIFICANT_DIGITS) mat_a = OpenMaya2.MMatrix(cover_world_matrix) mat_b = OpenMaya2.MMatrix(expected_cover_matrix) self.assertTrue(mat_a.isEquivalent(mat_b, tol)) self.assertGreater( closeness.compare_floats(latch_world_matrix, expected_latch_matrix), closeness.DEFAULT_SIGNIFICANT_DIGITS) mat_a = OpenMaya2.MMatrix(latch_world_matrix) mat_b = OpenMaya2.MMatrix(expected_latch_matrix) self.assertTrue(mat_a.isEquivalent(mat_b, tol)) return