def create_node(source_node, node_type="empty"): """Creates a zero transform node to be the parent of the given one and returns it. Args: source_node (PyNode): Node to create a zero transform one to be its parent. node_type (str, optional): Type of the zero transform node. By default "empty". Returns: PyNode: Returns the created zero node. """ if source_node: # Creates the node zero_node = utils.create_node_by_type(node_type) if zero_node: # Renames it as ZT node zero_node.rename(source_node.longName() + "ZT") # Aligns it to the current one. utils.align(zero_node, source_node) # If source node has a parent, this will be the ZT node parent source_node_parent = source_node.listRelatives(parent=True) source_node_parent = source_node_parent[0] if source_node_parent else None if source_node_parent: pm.parent(zero_node, source_node_parent, absolute=True) # Source node parent now will be the ZT node pm.parent(source_node, zero_node, absolute=True) return zero_node return None
def set_current(source_node): """Stores the current transform to the zero transform values. Args: source_node (PyNode): Node to store the zero transform. """ if source_node: source_node = pm.PyNode(source_node) zero_node = get_node(source_node) # If it has a ZT parent node, stores the source node transform if zero_node: utils.align(zero_node, source_node) apply(source_node)
def build_core(self, goal): """Creates the core solution attending to the goal type. Args: goal (str): Goal of the core to build. """ # ------------------------------------ # FIT GOAL # Creation of fit goal if goal == "fit": # ------------------------------------ # Default attributes values. segments = 3 if hasattr(self, "sp_segments"): segments = self.sp_segments.value() distance = 10.0 if hasattr(self, "dsp_len"): distance = self.dsp_len.value() segment_distance = distance/segments # ------------------------------------ # ------------------------------------ master_node = self.get_node(goal, "master") master_node_shape = master_node.listRelatives(shapes=True)[0] master_node_shape_circle = master_node_shape.listConnections(source=True)[0] # Locks and hides non necessary attributes. self.setup_channelBox_attributes(master_node_shape_circle, ["radius", "sections", "degree", "sweep"]) # ------------------------------------ # ------------------------------------ # Creates a node to be the parent of all core part first_core_node = self.create_node_by_type("empty") first_core_node_tag = "first" self.rename_node(first_core_node, goal, "core", first_core_node_tag) self.set_color(first_core_node, goal) self.add_attributes(first_core_node, goal, "core", first_core_node_tag) self.nodes[goal]["core"].append(first_core_node) # ------------------------------------ # ------------------------------------ # Creates a node to drive the length of the core part last_core_node = self.create_node_by_type("circle", radius=1.5) last_core_node_tag = "last" self.rename_node(last_core_node, goal, "core", last_core_node_tag) self.set_color(last_core_node, goal) self.add_attributes(last_core_node, goal, "core", last_core_node_tag) # Locks and hides non necessary attributes. self.setup_channelBox_attributes(last_core_node, ["translateX", "translateY", "translateZ", "rotateX", "rotateY", "rotateZ"]) # Position it in the distance required and parent to first core node utils.align(last_core_node, first_core_node, offset_translation=[0.0, distance, 0.0]) pm.parent(last_core_node, first_core_node, absolute=True) # NOTE: In this case we dont add the node for now to the solution core nodes because we need to do it at the end, # since the branch node must be the child of this last core node. # Creates the zero transform node for this one. last_core_zero_node = self.create_zero_transform_node(last_core_node) self.nodes[goal]["core"].append(last_core_zero_node) # ------------------------------------ # ------------------------------------ # Creates the radius and sections, etc. connection from the main control to the last core node. last_core_node_shape = last_core_node.listRelatives(shapes=True)[0] last_core_node_shape_circle = last_core_node_shape.listConnections(source=True)[0] pm.connectAttr(master_node_shape_circle.attr("radius"), last_core_node_shape_circle.attr("radius")) pm.connectAttr(master_node_shape_circle.attr("sections"), last_core_node_shape_circle.attr("sections")) pm.connectAttr(master_node_shape_circle.attr("degree"), last_core_node_shape_circle.attr("degree")) pm.connectAttr(master_node_shape_circle.attr("sweep"), last_core_node_shape_circle.attr("sweep")) # Locks and hides non necessary attributes. self.setup_channelBox_attributes(last_core_node_shape_circle, ["radius", "sections", "degree", "sweep"]) # ------------------------------------ # ------------------------------------ # Creates the node to aim the deform joints to it. last_core_aim_node = self.create_node_by_type("empty") last_core_aim_node_tag = "lastAim" self.rename_node(last_core_aim_node, goal, "core", last_core_aim_node_tag) self.set_color(last_core_aim_node, goal) self.add_attributes(last_core_aim_node, goal, "core", last_core_aim_node_tag) # Align the joint align node to the core node. Also inverts x and y. utils.align(last_core_aim_node, last_core_node, offset_translation=[0, 0, distance]) pm.parent(last_core_aim_node, last_core_node, absolute=True) self.nodes[goal]["core"].append(last_core_aim_node) # ------------------------------------ # ------------------------------------ # Creates the connection from the distance to the aim node separation. last_core_aim_distance_node = self.create_node_by_type("plusMinusAverage") last_core_aim_distance_node_tag = "lastAimDistance" self.rename_node(last_core_aim_distance_node, goal, "core", last_core_aim_distance_node_tag) self.add_attributes(last_core_aim_distance_node, goal, "core", last_core_aim_distance_node_tag) pm.connectAttr(last_core_node.attr("translateY"), last_core_aim_distance_node.attr("input1D[0]")) pm.connectAttr(last_core_zero_node.attr("translateY"), last_core_aim_distance_node.attr("input1D[1]")) pm.connectAttr(last_core_aim_distance_node.attr("output1D"), last_core_aim_node.attr("translateZ")) # NOTE: Don't add non dag nodes to the solution node lists, beccause since they don't have parent, # can be confused with first core node and used wrong to get the master node. Gives listRelatives errors. # self.nodes[goal]["core"].append(last_core_aim_distance_node) # ------------------------------------ # If the main core node is created successfully, continues with all the others. if first_core_node and last_core_node: # ------------------------------------ # Variables to store prev iteration nodes. prev_joint_node = None prev_segment_node = None # ------------------------------------ # Loops the number of segments. for i in range(segments + 1): # ------------------------------------ # Create a segment parent node for each segment and an extra one for the end. segment_parent_node = self.create_node_by_type("empty") # Set the properties. segment_parent_node_tag = ("segmentParent%03d" % i) self.rename_node(segment_parent_node, goal, "core", segment_parent_node_tag) self.set_color(segment_parent_node, goal) self.add_attributes(segment_parent_node, goal, "core", segment_parent_node_tag) # Position the segment node in the right position. utils.align(segment_parent_node, first_core_node, offset_translation=[0.0, segment_distance*i, 0.0]) pm.parent(segment_parent_node, first_core_node, absolute=True) # Creates the point constraint to maintain segment distances. segment_parent_node_point_constraint = pm.PyNode(pm.pointConstraint(first_core_node, last_core_node, segment_parent_node)) pm.pointConstraint(first_core_node, segment_parent_node, e=True, w=(100.0/segments)*(segments - i)) pm.pointConstraint(last_core_node, segment_parent_node, e=True, w=(100.0/segments)*i) segment_parent_node_point_constraint_tag = ("segmentParentPointConstraint%03d" % i) self.rename_node(segment_parent_node_point_constraint, goal, "core", segment_parent_node_point_constraint_tag) self.set_color(segment_parent_node_point_constraint, goal) self.add_attributes(segment_parent_node_point_constraint, goal, "core", segment_parent_node_point_constraint_tag) # Creates the aim constraint to point the last node. target = last_core_node if i < segments else first_core_node segment_parent_node_aim_constraint = pm.PyNode(pm.aimConstraint(target, segment_parent_node, aim=[0, 1, 0], u=[0, 0, 1], mo=True, wut="object", wuo=last_core_aim_node)) segment_parent_node_aim_constraint_tag = ("segmentParentAimConstraint%03d" % i) self.rename_node(segment_parent_node_aim_constraint, goal, "core", segment_parent_node_aim_constraint_tag) self.set_color(segment_parent_node_aim_constraint, goal) self.add_attributes(segment_parent_node_aim_constraint, goal, "core", segment_parent_node_aim_constraint_tag) # ------------------------------------ # ------------------------------------ # Create a segment node for each segment and an extra one for the end. segment_node = self.create_node_by_type("circle", radius=1) # Set the properties. segment_node_tag = ("segment%03d" % i) self.rename_node(segment_node, goal, "core", segment_node_tag) self.set_color(segment_node, goal) self.add_attributes(segment_node, goal, "core", segment_node_tag) self.setup_channelBox_attributes(segment_node, ["translateY", "translateZ"]) # Position the segment node in the right position. utils.align(segment_node, segment_parent_node) pm.parent(segment_node, segment_parent_node, absolute=True) # Creates the zero transform node for this one. segment_zero_node = self.create_zero_transform_node(segment_node) # ------------------------------------ # ------------------------------------ # Creates the radius connection from the main control to the segments nodes. segment_radius_node = self.create_node_by_type("multiplyDivide") segment_radius_node.attr("input2.input2X").set(0.5) segment_radius_node_tag = ("segmentRadius%03d" % i) self.rename_node(segment_radius_node, goal, "core", segment_radius_node_tag) self.add_attributes(segment_radius_node, goal, "core", segment_radius_node_tag) # Connects the radius. segment_node_shape = segment_node.listRelatives(shapes=True)[0] segment_node_shape_circle = segment_node_shape.listConnections(source=True)[0] pm.connectAttr(master_node_shape_circle.attr("radius"), segment_radius_node.attr("input1.input1X")) pm.connectAttr(segment_radius_node.attr("output.outputX"), segment_node_shape_circle.attr("radius")) pm.connectAttr(master_node_shape_circle.attr("sections"), segment_node_shape_circle.attr("sections")) pm.connectAttr(master_node_shape_circle.attr("degree"), segment_node_shape_circle.attr("degree")) pm.connectAttr(master_node_shape_circle.attr("sweep"), segment_node_shape_circle.attr("sweep")) # Locks and hides non necessary attributes. self.setup_channelBox_attributes(segment_node_shape_circle, ["radius", "sections", "degree", "sweep"]) # ------------------------------------ # ------------------------------------ # Creates the node to aim the deform joints to it. segment_joint_aim_node = self.create_node_by_type("empty") segment_joint_aim_node_tag = ("segmentJointAim%03d" % i) self.rename_node(segment_joint_aim_node, goal, "core", segment_joint_aim_node_tag) self.set_color(segment_joint_aim_node, goal) self.add_attributes(segment_joint_aim_node, goal, "core", segment_joint_aim_node_tag) # Position the segment aim node in the right position. utils.align(segment_joint_aim_node, segment_node) pm.parent(segment_joint_aim_node, segment_node, absolute=True) # ------------------------------------ # ------------------------------------ # Creates the connection from the distance to the aim node separation. segment_joint_aim_distance_node = self.create_node_by_type("plusMinusAverage") segment_joint_aim_distance_node_tag = ("segmentJointAimDistance%03d" % i) self.rename_node(segment_joint_aim_distance_node, goal, "core", segment_joint_aim_distance_node_tag) self.add_attributes(segment_joint_aim_distance_node, goal, "core", segment_joint_aim_distance_node_tag) # pm.connectAttr(segment_parent_node.attr("translateY"), segment_joint_aim_distance_node.attr("input1D[0]")) pm.connectAttr(last_core_zero_node.attr("translateY"), segment_joint_aim_distance_node.attr("input1D[0]")) pm.connectAttr(last_core_node.attr("translateY"), segment_joint_aim_distance_node.attr("input1D[1]")) pm.connectAttr(segment_node.attr("translateY"), segment_joint_aim_distance_node.attr("input1D[2]")) pm.connectAttr(segment_joint_aim_distance_node.attr("output1D"), segment_joint_aim_node.attr("translateZ")) # NOTE: Don't add non dag nodes to the solution node lists, beccause since they don't have parent, # can be confused with first core node and used wrong to get the master node. Gives listRelatives errors. # self.nodes[goal]["core"].append(segment_joint_aim_distance_node) # ------------------------------------ # ------------------------------------ # Creates the node to align the deform joints to it. joint_node = self.create_node_by_type("empty") # Creates the align node. joint_node_tag = ("segmentJoint%03d" % i) self.rename_node(joint_node, goal, "core", joint_node_tag) self.set_color(joint_node, goal) self.add_attributes(joint_node, goal, "core", joint_node_tag) # Align the joint align node to the core node. Also inverts x and y. utils.align(joint_node, segment_node, invert="xy") pm.parent(joint_node, segment_node, absolute=True) joint_node_aim_constraint = None last_joint_node_aim_constraint = None if prev_joint_node: # Creates the aim constraint to point the next segment. joint_node_aim_constraint = pm.PyNode(pm.aimConstraint(segment_node, prev_joint_node, aim=[0, 1, 0], u=[0, 0, 1], mo=True, wut="object", wuo=last_core_aim_node)) joint_node_aim_constraint_tag = ("jointNodeAimConstraint%03d" % i) self.rename_node(joint_node_aim_constraint, goal, "core", joint_node_aim_constraint_tag) self.set_color(joint_node_aim_constraint, goal) self.add_attributes(joint_node_aim_constraint, goal, "core", joint_node_aim_constraint_tag) # Creates the aim constraint to point to the previous segment in the case of last part. if i == segments: last_joint_node_aim_constraint = pm.PyNode(pm.aimConstraint(prev_segment_node, joint_node, aim=[0, 1, 0], u=[0, 0, 1], mo=True, wut="object", wuo=last_core_aim_node)) last_joint_node_aim_constraint_tag = ("jointNodeAimConstraint%03d" % i) self.rename_node(last_joint_node_aim_constraint, goal, "core", last_joint_node_aim_constraint_tag) self.set_color(last_joint_node_aim_constraint, goal) self.add_attributes(last_joint_node_aim_constraint, goal, "core", last_joint_node_aim_constraint_tag) # ------------------------------------ # ------------------------------------ # Creates the node to align the animation controls for the anim goal. joint_anim_node = self.create_node_by_type("empty") # Creates the anim node. joint_anim_node_tag = ("segmentControl%03d" % i) self.rename_node(joint_anim_node, goal, "core", joint_anim_node_tag) self.set_color(joint_anim_node, goal) self.add_attributes(joint_anim_node, goal, "core", joint_anim_node_tag) # Align the joint anim node to the joint node. utils.align(joint_anim_node, joint_node) pm.parent(joint_anim_node, joint_node, absolute=True) # ------------------------------------ # ------------------------------------ # Creates the node to visualize the joint direction. # Creates the node to calculate the length to next joint. joint_len_node = None joint_len_node_point_constraint = None segment_body_node = None segment_body_node_point_constraint = None if prev_joint_node: # ------------------------------------ # Creates the length reference node. joint_len_node = self.create_node_by_type("empty") joint_len_node_tag = ("segmentJointLen%03d" % i) self.rename_node(joint_len_node, goal, "core", joint_len_node_tag) self.set_color(joint_len_node, goal) self.add_attributes(joint_len_node, goal, "core", joint_len_node_tag) # Align the body node to the joint. utils.align(joint_len_node, prev_joint_node) pm.parent(joint_len_node, prev_joint_node, absolute=True) # Creates the point constraint to calculate the ditance to the next joint. joint_len_node_point_constraint = pm.PyNode(pm.pointConstraint(joint_node, joint_len_node)) joint_len_node_point_constraint_tag = ("segmentJointLenPointConstraint%03d" % i) self.rename_node(joint_len_node_point_constraint, goal, "core", joint_len_node_point_constraint_tag) self.set_color(joint_len_node_point_constraint, goal) self.add_attributes(joint_len_node_point_constraint, goal, "core", joint_len_node_point_constraint_tag) # ------------------------------------ # ------------------------------------ # Creates the body node. segment_body_node = self.create_node_by_type("renderBox") segment_body_node_tag = ("segmentBody%03d" % i) self.rename_node(segment_body_node, goal, "core", segment_body_node_tag) self.set_color(segment_body_node, goal) self.add_attributes(segment_body_node, goal, "core", segment_body_node_tag) # Align the body node to the joint. utils.align(segment_body_node, prev_joint_node) pm.parent(segment_body_node, prev_joint_node, absolute=True) # Creates the point constraint to maintain the ditance to the next joint. segment_body_node_point_constraint = pm.PyNode(pm.pointConstraint(prev_joint_node, joint_node, segment_body_node)) # pm.pointConstraint(first_core_node, segment_parent_node, e=True, w=(100.0/segments)*(segments - i)) # pm.pointConstraint(last_core_node, segment_parent_node, e=True, w=(100.0/segments)*i) segment_body_node_point_constraint_tag = ("segmentBodyPointConstraint%03d" % i) self.rename_node(segment_body_node_point_constraint, goal, "core", segment_body_node_point_constraint_tag) self.set_color(segment_body_node_point_constraint, goal) self.add_attributes(segment_body_node_point_constraint, goal, "core", segment_body_node_point_constraint_tag) # Connects the joint length to the box lenght. pm.connectAttr(joint_len_node.attr("translateY"), segment_body_node.attr("sizeY")) # Connects the segment radius to the box width. box_radius_node = self.create_node_by_type("multiplyDivide") box_radius_node.attr("input2.input2X").set(0.5) box_radius_node_tag = ("segmentBoxRadius%03d" % i) self.rename_node(box_radius_node, goal, "core", box_radius_node_tag) self.add_attributes(box_radius_node, goal, "core", box_radius_node_tag) prev_segment_node_shape = prev_segment_node.listRelatives(shapes=True)[0] prev_segment_node_shape_circle = prev_segment_node_shape.listConnections(source=True)[0] pm.connectAttr(prev_segment_node_shape_circle.attr("radius"), box_radius_node.attr("input1.input1X")) pm.connectAttr(box_radius_node.attr("output.outputX"), segment_body_node.attr("sizeX")) pm.connectAttr(box_radius_node.attr("output.outputX"), segment_body_node.attr("sizeZ")) # Locks and hides non necessary attributes. self.setup_channelBox_attributes(segment_body_node, ["no_attributes"]) # ------------------------------------ # ------------------------------------ # ------------------------------------ # Stores the current nodes to use in the next interation. prev_segment_node = segment_node prev_joint_node = joint_node # ------------------------------------ # ------------------------------------ # Add the nodes to the core solution self.nodes[goal]["core"].append(segment_parent_node) self.nodes[goal]["core"].append(segment_parent_node_point_constraint) self.nodes[goal]["core"].append(segment_parent_node_aim_constraint) self.nodes[goal]["core"].append(segment_node) self.nodes[goal]["core"].append(segment_zero_node) self.nodes[goal]["core"].append(segment_joint_aim_node) self.nodes[goal]["core"].append(joint_node) self.nodes[goal]["core"].append(joint_anim_node) if joint_node_aim_constraint: self.nodes[goal]["core"].append(joint_node_aim_constraint) if last_joint_node_aim_constraint: self.nodes[goal]["core"].append(last_joint_node_aim_constraint) if joint_len_node: self.nodes[goal]["core"].append(joint_len_node) if joint_len_node_point_constraint: self.nodes[goal]["core"].append(joint_len_node_point_constraint) if segment_body_node: self.nodes[goal]["core"].append(segment_body_node) if segment_body_node_point_constraint: self.nodes[goal]["core"].append(segment_body_node_point_constraint) # ------------------------------------ # ------------------------------------ # NOTE: In this case we add the last node to the core solutiond at the end because the branch node must be the child of this last core node. self.nodes[goal]["core"].append(last_core_node) # FIT GOAL END # ------------------------------------ # ------------------------------------ # DEFORM GOAL # Creation of deform goal if goal == "deform": if self.is_goal_built("fit"): fit_joints = self.get_nodes("fit", "core", "segmentJoint[0-9]{3,3}$") prev_joint_node = None for i in range(len(fit_joints)): # ------------------------------------ # Creates the deform joints. joint_node = self.create_node_by_type("joint") joint_node_tag = ("segmentJoint%03d" % i) self.rename_node(joint_node, goal, "core", joint_node_tag) self.set_color(joint_node, goal) self.add_attributes(joint_node, goal, "core", joint_node_tag) # Align to the fit node. utils.align(joint_node, fit_joints[i]) # Parents it to the previous joint. if prev_joint_node: pm.parent(joint_node, prev_joint_node, absolute=True) # Stores the current node as previous for next iteration. prev_joint_node = joint_node # Stores the node in tbe correspondent list. self.nodes[goal]["core"].append(joint_node) # ------------------------------------ # DEFORM GOAL END # ------------------------------------ # ------------------------------------ # ANIM GOAL # Creation of anim goal if goal == "anim": if self.is_goal_built("fit"): fit_joint_anim_controls = self.get_nodes("fit", "core", "segmentControl[0-9]{3,3}$") fit_joints = self.get_nodes("fit", "core", "segmentJoint[0-9]{3,3}$") prev_joint_anim_node = None for i in range(len(fit_joint_anim_controls)): # ------------------------------------ # Creates the deform joints. joint_anim_node = self.create_node_by_type("circle") joint_anim_node_tag = ("segmentControl%03d" % i) self.rename_node(joint_anim_node, goal, "core", joint_anim_node_tag) self.set_color(joint_anim_node, goal) self.add_attributes(joint_anim_node, goal, "core", joint_anim_node_tag) # Align to the fit node. utils.align(joint_anim_node, fit_joint_anim_controls[i]) # Parents it to the previous joint. if prev_joint_anim_node: pm.parent(joint_anim_node, prev_joint_anim_node, absolute=True) joint_anim_zero_node = self.create_zero_transform_node(joint_anim_node) # Stores the current node as previous for next iteration. prev_joint_anim_node = joint_anim_node # ------------------------------------ # ------------------------------------ # Creates the deform joints. joint_node = self.create_node_by_type("joint") joint_node_tag = ("segmentJoint%03d" % i) self.rename_node(joint_node, goal, "core", joint_node_tag) self.set_color(joint_node, goal) self.add_attributes(joint_node, goal, "core", joint_node_tag) # Align to the fit node. utils.align(joint_node, fit_joints[i]) # Parents it to the anim control. pm.parent(joint_node, joint_anim_node, absolute=True) # ------------------------------------ # ------------------------------------ # Stores the node in tbe correspondent list. self.nodes[goal]["core"].append(joint_anim_zero_node) self.nodes[goal]["core"].append(joint_anim_node) self.nodes[goal]["core"].append(joint_node)