def create_skincluster_backup(shape, skin_node):
    """ Creates a skinning backup object

    :param shape: the shape node you want to duplicate (should use orig shape)
    :type shape: str

    :param skin_node: the given shape skin cluster node
    :type skin_node: str

    :return: the skin cluster node backup
    :rtype: str
    """

    logger.info("Creating skin backup for {}".format(skin_node))

    # gets the skin cluster influences
    influences = cmds.listConnections("{}.matrix".format(skin_node))

    # creates a duplicate shape of the given shape
    holder_name = "{}_flex_skin_shape_holder".format(
        get_prefix_less_name(shape))
    shape_duplicate = create_duplicate(shape, holder_name)

    # creates new skin cluster node on duplicate
    skin_holder = cmds.skinCluster(influences, shape_duplicate, bindMethod=0,
                                   obeyMaxInfluences=False, skinMethod=0,
                                   weightDistribution=0, normalizeWeights=1,
                                   removeUnusedInfluence=False, name="{}_SKN"
                                   .format(holder_name))

    # copy the given skin node weights to back up shape
    copy_skin_weights(skin_node, skin_holder[0])

    return ["{}".format(skin_holder[0])]
Example #2
0
def copy_cluster_weights(shape, weight_file, method="bilinear"):
    """ Copy cluster weights to the given shape from the given weight files

    :param shape: the shape node name containing the cluster deformers
    :type shape: str

    :param weight_file: containing the deformers and weight filter names
    :type weight_file: dict

    :param method: method type that should be used when updating the weights
    :type method: str
    """

    # gets the temporary folder path
    temp_path = get_temp_folder()
    short_name = get_prefix_less_name(shape)

    for node in weight_file:
        if not weight_file[node]:
            continue
        cmds.deformerWeights(weight_file[node],
                             im=True,
                             shape=short_name,
                             deformer=node,
                             path=temp_path,
                             method=method,
                             vertexConnections=True)
Example #3
0
def create_clusters_backup(shape, nodes):
    """ Generates weight files for the given cluster nodes in the given shape

    :param shape: the shape node name containing the cluster deformers nodes
    :type shape: str

    :param nodes: the cluster nodes
    :type nodes: list

    :return: cluster weight files names
    :rtype: dict
    """

    logger.info("Creating cluster weights backup for {}".format(nodes))

    # gets the temp folder path
    temp_path = get_temp_folder()

    # prefix less shape name
    shape = get_prefix_less_name(shape)

    # dict for weights files
    weight_files = {}

    for node in nodes:
        # If there is not weights creating the deformer maps is useless
        try:
            cmds.getAttr("{}.weightList[0].weights".format(node))
        except RuntimeError:
            weight_files[node] = None
            continue
        # Creates the weight map if weights are found on shape points
        cmds.deformerWeights('{}_{}.xml'.format(shape, node),
                             export=True,
                             vertexConnections=True,
                             weightPrecision=5,
                             shape=shape,
                             deformer=node,
                             path=temp_path)
        weight_files[node] = '{}_{}.xml'.format(shape, node)

    return weight_files
def create_blendshapes_backup(source, target, nodes):
    """ Creates an updated backup for the given blendshapes nodes on source

    .. important:: This method does not work as the other source/target type
                   of methods in flex. The source is the current geometry
                   before topology update containing the blendshape nodes.
                   We use it in order to create a wrap to the newer target
                   geometry topology.

    :param source: current shape node
    :type source: str

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

    :return: backup blendshape nodes
    :rtype: list
    """

    logger.debug("Creating blendshapes backup")

    # gets simpler shape name
    shape_name = get_prefix_less_name(target)

    # get attributes types
    attrs = get_shape_type_attributes(target)

    # creates source duplicate
    intermediate = get_shape_orig(source)[0]
    source_duplicate = create_duplicate(intermediate, "{}_flex_bs_sourceShape"
                                        .format(shape_name))

    # first loops to create a clean copy of the blendshape nodes
    nodes_copy = []
    for node in nodes:
        duplicate = copy_blendshape_node(node, source_duplicate)
        if duplicate:
            nodes_copy.append(duplicate)

    # creates wrapped target shape
    warp_target = create_duplicate(target, "{}_flex_bs_warpShape"
                                   .format(shape_name))

    # wraps the duplicate to the source
    create_wrap(source_duplicate, warp_target)

    # creates blendshape target shape
    target_duplicate = create_duplicate(target, "{}_flex_bs_targetShape"
                                        .format(shape_name))

    return_nodes = []

    # loops on the blendshape nodes
    for node in nodes_copy:
        # creates transfer blendshape
        transfer_node = cmds.deformer(target_duplicate, type="blendShape",
                                      name="flex_transfer_{}".format(node))[0]

        # get blendshape targets indices. We skip verification because at this
        # stage the copied blendshapes nodes will always have targets
        targets_idx = cmds.getAttr("{}.weight".format(node), multiIndices=True)

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

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

            # loop on actual targets and in-between targets
            for target in cmds.getAttr(attr_name, multiIndices=True):

                # gets and sets the blendshape weight value
                weight = float((target - 5000) / 1000.0)
                cmds.setAttr("{}.weight[{}]".format(node, idx), weight)

                # geometry target attribute
                geometry_target_attr = "{}[{}].inputGeomTarget".format(
                    attr_name, target)

                shape_target = geometry_target_attr.replace(
                    geometry_target_attr.split(".")[0], transfer_node)

                # updates the target
                cmds.connectAttr("{}.{}".format(warp_target, attrs["output"]),
                                 shape_target, force=True)

                cmds.disconnectAttr("{}.{}"
                                    .format(warp_target, attrs["output"]),
                                    shape_target)

                cmds.setAttr("{}.weight[{}]".format(node, idx), 0)

            cmds.setAttr("{}.weight[{}]".format(transfer_node, idx), 0)

            if target_name:
                cmds.aliasAttr(target_name, "{}.weight[{}]".format(
                    transfer_node, idx))

        # adds blendshape node to nodes to return
        return_nodes.append("{}".format(transfer_node))

    # deletes backup process shapes
    cmds.delete(cmds.listRelatives(source_duplicate, parent=True),
                cmds.listRelatives(warp_target, parent=True))

    # forces refresh
    cmds.refresh()

    return return_nodes