mayaで大量のリファレンスを扱うことってありませんか?
アニメーターとして働いていると多々そんな場面があります。大手の会社ならバージョンアップ、ダウンのランチャーがありとても便利なのですが、中規模だとそこまで整っていなかったりするので自分でポチポチ変換する羽目になります。
が、ついに大量にウインドウ呼び出してパス張り替えての繰り返しに飽きたので自分用に作ったものをここで公開したいと思います。
import maya.cmds as cmds
import os
# --------------------------------------------------
# Utility functions
# --------------------------------------------------
def _normalize(p):
return p.replace("\\", "/")
def _resolve_ref_node(node):
"""Return reference node name from a selected node, or None if not applicable."""
if cmds.nodeType(node) == "reference":
if node.startswith("sharedReferenceNode"):
return None
return node
try:
if cmds.referenceQuery(node, isNodeReferenced=True):
return cmds.referenceQuery(node, referenceNode=True)
except Exception:
pass
return None
def _list_reference_nodes():
"""Return a list of valid reference nodes in the scene."""
out = []
for ref in cmds.ls(type="reference") or []:
if ref.startswith("sharedReferenceNode"):
continue
try:
_ = cmds.referenceQuery(ref, filename=True)
out.append(ref)
except Exception:
continue
return sorted(set(out))
# --------------------------------------------------
# Replace References
# --------------------------------------------------
def change_selected_reference_paths(new_file_path):
"""Replace all selected references with the same file (full path)."""
new_file_path = _normalize(new_file_path)
sel = cmds.ls(sl=True) or []
if not sel:
cmds.warning("Please select reference nodes or nodes inside references.")
return
if not os.path.isfile(new_file_path):
cmds.warning("File does not exist: {}".format(new_file_path))
return
ref_nodes = set()
for n in sel:
ref = _resolve_ref_node(n)
if ref:
ref_nodes.add(ref)
if not ref_nodes:
cmds.warning("No reference nodes were found from the selection.")
return
for ref_node in sorted(ref_nodes):
try:
old_path = cmds.referenceQuery(ref_node, filename=True)
except Exception:
old_path = "<unknown>"
try:
cmds.file(new_file_path, loadReference=ref_node)
print("[Batch Replace] {}: {} → {}".format(ref_node, old_path, new_file_path))
except Exception as e:
cmds.warning("{} failed to reload: {}".format(ref_node, e))
def change_reference_path(ref_node, new_path):
"""Replace a single reference with a new full path."""
new_path = _normalize(new_path)
if not os.path.isfile(new_path):
cmds.warning("File does not exist: {}".format(new_path))
return
try:
cmds.file(new_path, loadReference=ref_node)
print("[Individual Replace] {} → {}".format(ref_node, new_path))
except Exception as e:
cmds.warning("{} failed to reload: {}".format(ref_node, e))
# --------------------------------------------------
# Delete References
# --------------------------------------------------
def delete_selected_references():
"""Delete all references found from the current selection."""
sel = cmds.ls(sl=True) or []
if not sel:
cmds.warning("Please select reference nodes or nodes inside references.")
return
ref_nodes = set()
for n in sel:
ref = _resolve_ref_node(n)
if ref:
ref_nodes.add(ref)
if not ref_nodes:
cmds.warning("No reference nodes were found from the selection.")
return
for ref_node in sorted(ref_nodes):
try:
cmds.file(removeReference=True, referenceNode=ref_node)
print("[Deleted] Reference node: {}".format(ref_node))
except Exception as e:
cmds.warning("Failed to delete {}: {}".format(ref_node, e))
# --------------------------------------------------
# UI
# --------------------------------------------------
WIN_ID = "referenceToolsUI"
INDIV_COL = "referenceToolsUI_individualCol"
def _rebuild_individual_list():
"""Rebuild the list of references for individual replacement."""
if not cmds.layout(INDIV_COL, exists=True):
return
for child in cmds.layout(INDIV_COL, q=True, ca=True) or []:
cmds.deleteUI(child)
for ref in _list_reference_nodes():
try:
path = cmds.referenceQuery(ref, filename=True)
except Exception:
path = ""
row = cmds.rowLayout(numberOfColumns=3, columnWidth3=[220, 420, 80],
adjustableColumn=2, parent=INDIV_COL)
cmds.text(label=ref, align="left")
field = cmds.textField(text=path, parent=row)
cmds.button(label="Replace",
parent=row,
c=lambda _, r=ref, f=field: change_reference_path(
r, cmds.textField(f, q=True, text=True)))
def show_reference_tools_ui():
"""Show the Reference Tools UI (Replace & Delete)."""
if cmds.window(WIN_ID, exists=True):
cmds.deleteUI(WIN_ID)
cmds.window(WIN_ID, title="Reference Tools", widthHeight=(760, 600))
cmds.scrollLayout(horizontalScrollBarThickness=16, verticalScrollBarThickness=16)
cmds.columnLayout(adjustableColumn=True, rowSpacing=12)
# === Batch Replace ===
cmds.frameLayout(label="Batch Replace (replace all selected references with the same file)",
collapsable=True, marginHeight=6)
cmds.columnLayout(adjustableColumn=True, rowSpacing=6)
cmds.text(label="Enter the new file full path:")
bulk_path_field = cmds.textField(text="")
cmds.button(label="Batch Replace Selected References", bgc=(0.3, 0.6, 0.3),
c=lambda *args: change_selected_reference_paths(
cmds.textField(bulk_path_field, q=True, text=True)))
cmds.setParent(".."); cmds.setParent("..")
# === Individual Replace ===
cmds.frameLayout(label="Individual Replace (set file path per reference)",
collapsable=True, marginHeight=6)
cmds.columnLayout(adjustableColumn=True, rowSpacing=6)
cmds.rowLayout(numberOfColumns=2, columnWidth2=[200, 200])
cmds.button(label="Refresh List", c=lambda *_: _rebuild_individual_list())
cmds.setParent("..")
cmds.columnLayout(INDIV_COL, adjustableColumn=True, rowSpacing=4)
cmds.setParent(".."); cmds.setParent("..")
# === Delete References ===
cmds.frameLayout(label="Delete References",
collapsable=True, marginHeight=6)
cmds.columnLayout(adjustableColumn=True, rowSpacing=6)
cmds.text(label="Deletes all references found in the current selection.")
cmds.button(label="Delete Selected References", bgc=(0.8, 0.3, 0.3),
c=lambda *args: delete_selected_references())
cmds.setParent(".."); cmds.setParent("..")
cmds.showWindow(WIN_ID)
_rebuild_individual_list()
上のスクリプトをscriptフォルダに入れて
import reference_tools; reference_tools.show_reference_tools_ui()
で実行すればUIが立ち上がります
このUIは3つのセクションから構成されています。
section A
アウトライナーで選択したリファレンスを一括リプレイスする。
テキストボックスに置き換えたいファイルのパスを挿入して、batch replace selected referenceのボタンを押しせば、全て入れ替えます。
section B
シーン内のリファレンスを個別でリプレイスする。
Refresh List のボタンを押すとシーン内のリファレンスをリストします。
テキストボックには現在使用しているリファレンスへのリンクが出ているので、入れ替えたいファイルへのリンクを入れ、Replaceボタンで個別に入れ替えることができます。
section C
アウトライナーで選択しているリファレンスを一括消去する。
シーンから削除したいリファレンスを選択し、Delete Selected Referencesボタンを押すと、一括消去されます。
以上になります! Merry X'mas !!!
