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()