Maya Python script "Place2DNode Connector"

Have you ran into those situations where you want all of your textures to share the same 2D node and wish you didn't have to do it manually? Look no further! This script connects all of the selected textures to a single Place2D node. Left over 2D nodes are not deleted automatically, so you can "delete all unused nodes" from the menu if you wish.

__________________________

# Maya Python: Connect selected 2D texture nodes to a single place2dTexture

# Usage: select any number of 2D texture nodes (and optionally one place2dTexture), then run.


import maya.cmds as cmds


SHARED_PLACE2D_NAME = "shared_place2dTexture"


# Standard connections from place2dTexture -> 2D textures

PAIR_ATTRS = [

    ("coverage",          "coverage"),

    ("translateFrame",    "translateFrame"),

    ("rotateFrame",       "rotateFrame"),

    ("mirrorU",           "mirrorU"),

    ("mirrorV",           "mirrorV"),

    ("stagger",           "stagger"),

    ("wrapU",             "wrapU"),

    ("wrapV",             "wrapV"),

    ("repeatUV",          "repeatUV"),

    ("offset",            "offset"),

    ("rotateUV",          "rotateUV"),

    ("noiseUV",           "noiseUV"),

    ("vertexUvOne",       "vertexUvOne"),

    ("vertexUvTwo",       "vertexUvTwo"),

    ("vertexUvThree",     "vertexUvThree"),

    ("vertexCameraOne",   "vertexCameraOne"),

    ("outUV",             "uvCoord"),

    ("outUvFilterSize",   "uvFilterSize"),

]


def _is_place2d(node):

    return cmds.nodeType(node) == "place2dTexture"


def _has_attr(node, attr):

    return cmds.attributeQuery(attr, n=node, exists=True)


def _is_2d_texture(node):

    # Heuristic: any texture-like node that has a 'uvCoord' input is a 2D texture

    if _is_place2d(node):

        return False

    try:

        return _has_attr(node, "uvCoord")

    except Exception:

        return False


def get_selection_partitions():

    sel = cmds.ls(sl=True) or []

    place2ds = [n for n in sel if _is_place2d(n)]

    tex2ds   = [n for n in sel if _is_2d_texture(n)]

    return place2ds, tex2ds


def get_or_create_target_place2d(selected_place2ds):

    # Priority:

    # 1) Use first selected place2dTexture (if any)

    # 2) Reuse shared by name if present

    # 3) Create a new shared place2dTexture

    if selected_place2ds:

        return selected_place2ds[0]

    if cmds.objExists(SHARED_PLACE2D_NAME) and _is_place2d(SHARED_PLACE2D_NAME):

        return SHARED_PLACE2D_NAME

    return cmds.shadingNode("place2dTexture", asUtility=True, name=SHARED_PLACE2D_NAME)


def connect_place2d_to_texture(place2d, tex):

    made = 0

    for src_attr, dst_attr in PAIR_ATTRS:

        if not _has_attr(place2d, src_attr) or not _has_attr(tex, dst_attr):

            continue

        try:

            cmds.connectAttr("{}.{}".format(place2d, src_attr),

                             "{}.{}".format(tex,   dst_attr),

                             force=True)

            made += 1

        except Exception:

            pass

    return made


def main():

    place2ds, tex2ds = get_selection_partitions()


    if not tex2ds:

        cmds.warning("Select one or more 2D texture nodes (nodes with a 'uvCoord' input).")

        return


    target_place2d = get_or_create_target_place2d(place2ds)


    cmds.undoInfo(openChunk=True)

    total_links = 0

    try:

        for t in tex2ds:

            total_links += connect_place2d_to_texture(target_place2d, t)

    finally:

        cmds.undoInfo(closeChunk=True)


    msg = "Connected {} 2D texture(s) to: {}".format(len(tex2ds), target_place2d)

    print("#"*60)

    print(msg)

    print("Attributes linked (total connections made): {}".format(total_links))

    print("#"*60)

    try:

        cmds.inViewMessage(amg='{} <hl>{}</hl>'.format("Connected selected 2D textures to", target_place2d),

                           pos='botCenter', fade=True)

    except Exception:

        pass


# Run it

main()