コード例 #1
0
def update_deformed_shape(source, target, mismatching_topology=True):
    """ Updates the target shape with the given source shape content

    :param source: maya shape node
    :type source: str

    :param target: maya shape node
    :type target: str

    :param mismatching_topology: ignore or not mismatching topologies
    :type mismatching_topology: bool
    """

    # gets orig shape
    deform_origin = get_shape_orig(target)

    # returns as target is not a deformed shape
    if not deform_origin:
        return

    logger.debug("Deformed shape found: {}".format(target))

    # returns if source and target shapes don't match
    if not is_matching_type(source, target):
        logger.warning(
            "{} and {} don't have same shape type. passing...".format(
                source, target))
        return

    # returns if vertices count isn't equal and mismatching isn't requested
    if not mismatching_topology and not is_matching_count(source, target):
        logger.warning("{} and {} don't have same shape vertices count."
                       "passing...".format(source, target))
        return

    deform_origin = deform_origin[0]

    # updates map1 name
    copy_map1_name(source, deform_origin)

    # updates on mismatching topology
    if mismatching_topology and not is_matching_count(source, target):
        update_deformed_mismatching_shape(source, target, deform_origin)
        return

    # update the shape
    update_shape(source, deform_origin)

    # update uvs set on target
    update_uvs_sets(target)
コード例 #2
0
def update_deformed_mismatching_shape(source, target, shape_orig):
    """ Updates the target shape with the given source shape content

    :param source: maya shape node
    :type source: str

    :param target: maya shape node
    :type target: str

    :param shape_orig: shape orig on the target shape
    :type shape_orig: str
    """

    logger.debug("Running update deformed mismatched shapes")

    # gets all deformers on the target shape (supported by flex)
    deformers = get_deformers(target)

    if len(deformers["skinCluster"]) > 1:
        logger.warning(
            "Dual skinning is yet not supported. {} will be used".format(
                deformers["skinCluster"][0]))

    # Turns all deformers envelope off
    set_deformer_state(deformers, False)

    # creates deformers backups
    bs_nodes, skin_nodes, cluster_nodes = create_deformers_backups(
        source, target, shape_orig, deformers)
    # updates target shape
    update_shape(source, shape_orig)

    # updates skinning nodes
    update_skincluster_node(skin_nodes, deformers["skinCluster"])

    # updates blendshapes nodes
    update_blendshapes_nodes(bs_nodes, deformers["blendShape"])

    # update cluster nodes
    update_clusters_nodes(target, cluster_nodes)

    # updates uv sets on target shape
    update_uvs_sets(target)

    # Turns all deformers envelope ON
    set_deformer_state(deformers, True)

    # deletes backups
    delete_transform_from_nodes(set(bs_nodes).union(skin_nodes))
コード例 #3
0
def analyze_groups(source, target):
    """ Analyze the shapes found inside the source and target groups

    :param source: maya transform node
    :type source: str

    :param target: maya transform node
    :type target: str
    """

    logger.debug(
        "Analysing the following groups - source: {}  - target: {}".format(
            source, target))

    # gets the matching shapes
    matching_shapes = get_matching_shapes_from_group(source, target)

    # gets mismatching shape types
    mismatched_types = [
        x for x in matching_shapes
        if not is_matching_type(x, matching_shapes[x])
    ]

    # gets mismatching shape vertices count
    mismatched_count = [
        x for x in matching_shapes
        if not is_matching_count(x, matching_shapes[x])
    ]

    # gets mismatching shape bounding box
    mismatched_bbox = [
        x for x in matching_shapes
        if not is_matching_bouding_box(x, matching_shapes[x])
    ]

    logger.info("-" * 90)
    logger.info("Mismatch shapes types: {}".format(mismatched_types))
    logger.info("Mismatch vertices shapes: {}".format(mismatched_count))
    logger.info("Mismatch volume shapes: {}".format(mismatched_bbox))
    logger.warning("-" * 90)
    logger.warning("Source missing shapes: {}".format(
        get_missing_shapes_from_group(source, target)))
    logger.warning("Target missing shapes: {}".format(
        get_missing_shapes_from_group(target, source)))
    logger.warning("-" * 90)

    return matching_shapes, mismatched_types, mismatched_count, mismatched_bbox
コード例 #4
0
def update_attribute(source, target, attribute_name):
    """ Updates the given attribute value

    ..note:: This in a generic method to **setAttr** all type of attributes
             inside Maya. Using the getSetAttrCmds from the MPLug class allows
             avoiding to create one method for each type of attribute inside
             Maya as the setAttr command will differ depending on the
             attribute type and data.

    This method is faster than using PyMel attribute set property.

    :param source: the maya source node
    :type source: str

    :param target: the maya target node
    :type target: str

    :param attribute_name: the attribute name to set in the given target
    :type attribute_name: str
    """

    if not cmds.objExists("{}.{}".format(target, attribute_name)):
        logger.warning(
            "The current target {} does not have attribute: {}".format(
                target, attribute_name))
        return

    # checks for locking
    lock = is_lock_attribute(target, attribute_name)

    if not lock_unlock_attribute(target, attribute_name, False):
        logger.warning("The given attribute {} can't be updated on {}".format(
            attribute_name, target))
        return

    # creates pymel nodes to get and apply attributes from
    # I am using pymel as they managed to handle default attributes on
    # referenced nodes correctly. When using MPlug.getSetAttrCmd with kAll
    # this doesn't return the command correctly when nodes in reference have
    # the attribute left as default
    py_source = pm.PyNode(source)
    py_target = pm.PyNode(target)

    # sets the attribute value
    try:
        attr_value = py_source.attr(attribute_name).get()
        py_target.attr(attribute_name).set(attr_value)

    except Exception as e:
        logger.warning(
            "The given attribute ({}) can't be updated on {}".format(
                attribute_name, target))
        return e

    if lock:
        lock_unlock_attribute(target, attribute_name, True)
コード例 #5
0
def copy_blendshape_node(node, target):
    """ Copies the given blendshape node into the given target shape

    :param node: blendshape node
    :type node: str

    :param target: target shape node
    :type target: str

    :return: copied blenshape node
    :rtype: str
    """

    logger.debug("Copying blendshape node {} to {}".format(node, target))

    # get blendshape targets indices
    targets_idx = cmds.getAttr("{}.weight".format(node), multiIndices=True)

    # skip node if no targets where found
    if not targets_idx:
        return

    # list for ignored targets (when they are live connected)
    ignore = []

    # creates blendshape deformer node on target
    node_copy = cmds.deformer(target, type="blendShape", name="flex_copy_{}"
                              .format(node))[0]

    # loop on blendshape targets indices
    for idx in targets_idx:
        # input target group attribute
        attr_name = (BLENDSHAPE_TARGET.format(node, idx))

        # blendshape target name
        target_name = cmds.aliasAttr("{}.weight[{}]".format(node, idx),
                                     query=True)

        # checks for empty target
        if not cmds.getAttr(attr_name, multiIndices=True):
            continue

        # loop on actual targets and in-between targets
        for target in cmds.getAttr(attr_name, multiIndices=True):
            # target attribute name
            target_attr = "{}[{}]".format(attr_name, target)

            # checks for incoming connections on the geometry target
            if cmds.listConnections("{}.inputGeomTarget".format(target_attr),
                                    destination=False):

                logger.warning("{} can't be updated because it is a live "
                               "target".format(target_name))
                ignore.append(idx)
                continue

            # updates node copy target
            destination = target_attr.replace(target_attr.split(".")[0],
                                              node_copy)
            cmds.connectAttr(target_attr, destination, force=True)
            cmds.disconnectAttr(target_attr, destination)

        # skips updating target name if this was a life target
        if idx in ignore:
            continue

        # forces the weight attribute to be shown on the blendshape node
        cmds.setAttr("{}.weight[{}]".format(node_copy, idx), 0)

        # updates blendshape node attribute name
        if target_name:
            cmds.aliasAttr(target_name, "{}.weight[{}]"
                           .format(node_copy, idx))

    # gets targets on copied node to see if there is any node with zero target
    idx = cmds.getAttr("{}.weight".format(node_copy), multiIndices=True)
    if not idx:
        cmds.delete(node_copy)
        return

    return node_copy