作品:《在Maya和UE5中制作批量重命名工具》

作品:《在Maya和UE5中制作批量重命名工具》

Shuhang Luan Archie

Completed Image:

Introduction:

《Maya重命名工具》,是我在腾讯天美工作室,担任技术美术实习生时,最常见也最实用的一个工具,这也是我认为逻辑清晰,也非常容易制作的工具。特别是在辅助程序组进行批量创建模型,测试性能的时候,自己创建一个这样的工具,能够大大提高工作效率。

这里分享两个工具制作:

  1. UE5 Widget工具蓝图,应用于UE5引擎内的资源管理。可以快速使用内置的函数库,来通过节点连接的方式,制作出简单的重命名工具。
  2. Python in Maya,应用于Maya软件内的资源管理,通过在maya中使用Python的Maya API 工具,来制作出简单有效的重命名工具。
UE5-Widget工具展示:

程序图集合

程序图集合

UE5 widget 工具不多赘述,逻辑原理与python同理。

Design Thinking:

建立窗口

  • 创建后缀字典:
1
2
3
4
5
6
7
8
SUFFIXES = {
"mesh": "GEO",
"joint": "JNT",
"camera": "CAM",
"ambientLight": "LGT",
"directionalLight": "LGT",
"pointLight": "LGT",
"spotLight": "LGT",
  • 创建类,设定窗口名称
  • Tips:创建类的目的是把相关的代码封装在一起,并提供可重复使用的接口和工具,方便管理和维护代码。在这个例子中,RenamerUi 类的目的是创建 Maya 的批量重命名工具的用户界面。使用类可以把 UI 元素封装在一起,并在需要时方便地创建、显示、删除等。
  • 在创建窗口前,先删去之前的同名窗口
1
2
3
4
5
6
7
class RenamerUi(object):
WINDOW_NAME = "BatchNamingUi"
APP_NAME = "Batch naming"

@classmethod
def display(cls):
cls.delete()
  • 建立窗口并命名
1
2
3
4
5
6
# 建立窗口
# 主主控件
main_window = cmds.window(cls.WINDOW_NAME, title="Batch Renamer", sizeable=True, menuBar=True)
main_layout = cmds.columnLayout(adjustableColumn=True, parent=main_window)


UI界面

主控件

  • 设置界面内的主控件,并依附于窗口
  • 创建UI:选择方法
1
2
3
4
5
6
7
8
9
10
11
12
# 选择界面
method_layout = cmds.formLayout(parent=main_layout)

cls.method = cmds.radioButtonGrp(numberOfRadioButtons=2,
label="Method: ",
columnWidth=(1, 75),
h=27,
w=512,
sl=1,
labelArray2=("Selected","Hierarchy"),
parent=method_layout)

UI- 重命名

子控件与输入窗口
  • “Rename”窗口不需要输入值,因此使用cmds.frameLayout()命令创建栏目,并使用bgs=True添加颜色

  • 使用cmds.textFieldGrp()命令创建帧布局窗口小部件,返回的值为字符串

  • 使用columnWidth1/2=命令控制标签和帧布局窗口的宽度

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
# 名称窗口
rename_layout = cmds.frameLayout(label="Rename", parent=main_layout, bgs=True
rename_form_layout = cmds.formLayout(parent=rename_layout, h=60)

#cw1:将name向右移动一段位置(增加空格)cw2:控制输入文本位置
cls.name_tfg = cmds.textFieldGrp(label="Name: ",
columnWidth=(1, 75),
columnWidth2=(2, 426),
editable=True,
parent=rename_form_layout)

cls.prefix_tfg = cmds.textFieldGrp(label="Prefix: ",
columnWidth=(1, 75),
columnWidth2=(2, 426),
editable=True,
parent=rename_form_layout)

cls.suffix_tfg = cmds.textFieldGrp(label="Suffix: ",
columnWidth=(1, 40),
columnWidth2=(2, 80),
editable=True,
parent=rename_form_layout)

cls.autoSuffix_cbg = cmds.checkBoxGrp(numberOfCheckBoxes=1,
label="Auto Suffix: ",
columnWidth=(1, 70),
io=False,
changeCommand=cls.toggleSuffixField,
parent=rename_form_layout)
# 设定后缀-数字位数
# 创建标签
padding_label = cmds.text("Padding: ", align="right", width=60, parent=rename_form_layout)

  • 读取整数字段,控制后缀名的数值位数
1
2
3
4
5
6
cls.padding = cmds.intField(width=50,
value=1,
minValue=1,
maxValue=6,
step=1,
parent=rename_form_layout)
布局排版
  • 使用cmds.formLayout()命令,控制各控件进行排版
  • 例如:ac=(cls.autoSuffix_cbg, "left", 0, cls.suffix_tfg) 表示将 autoSuffix_cbg 这个控件的左侧对齐到 suffix_tfg 这个控件的右侧,并且二者之间没有空白区域
1
2
3
4
5
6
7
8
9
10
11
cmds.formLayout(rename_form_layout, e=True, af=(cls.name_tfg, "top", 6))
cmds.formLayout(rename_form_layout, e=True, af=(cls.name_tfg, "left", 0))
cmds.formLayout(rename_form_layout, e=True, ac=(cls.prefix_tfg, "top", 3, cls.name_tfg))
cmds.formLayout(rename_form_layout, e=True, ac=(cls.suffix_tfg, "top", 3, cls.name_tfg))
cmds.formLayout(rename_form_layout, e=True, ac=(cls.suffix_tfg, "left", 0, cls.prefix_tfg))
cmds.formLayout(rename_form_layout, e=True, ac=(cls.autoSuffix_cbg, "top", 6, cls.name_tfg))
cmds.formLayout(rename_form_layout, e=True, ac=(cls.autoSuffix_cbg, "left", 0, cls.suffix_tfg))
cmds.formLayout(rename_form_layout, e=True, ac=(padding_label, "top", 6, cls.name_tfg))
cmds.formLayout(rename_form_layout, e=True, ac=(padding_label, "left", 0, cls.autoSuffix_cbg))
cmds.formLayout(rename_form_layout, e=True, ac=(cls.padding, "top", 3, cls.name_tfg))
cmds.formLayout(rename_form_layout, e=True, ac=(cls.padding, "left", 0, padding_label))

UI- 搜索和替换

  • 使用相同方法创建搜索和替换的UI界面,在此不多赘述…
  • 最后加入cmds.showWindow(main_window)打开窗口
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
# Search and Replace UI
replace_layout = cmds.frameLayout(label="Search and Replace", parent=main_layout, bgs=True)

replace_form_layout = cmds.formLayout(parent=replace_layout, h=65)

cls.searchFor_tfg = cmds.textFieldGrp(label="Search For: ",
columnWidth=(1, 75),
columnWidth2=(2, 426),
editable=True,
parent=replace_form_layout)

cls.replaceWith_tfg = cmds.textFieldGrp(label="Replace With: ",
columnWidth=(1, 75),
columnWidth2=(2, 426),
editable=True,
parent=replace_form_layout)

cmds.formLayout(replace_form_layout, e=True, af=(cls.searchFor_tfg, "top", 6))
cmds.formLayout(replace_form_layout, e=True, af=(cls.searchFor_tfg, "left", 0))
cmds.formLayout(replace_form_layout, e=True, ac=(cls.replaceWith_tfg, "top", 3, cls.searchFor_tfg))

# Buttons UI
button_layout = cmds.flowLayout(parent=main_layout)
rename_btn = cmds.button(label="Rename",
width=170,
height=28,
command="batchRenamerUi.rename_objects()",
parent=button_layout)

replace_btn = cmds.button(label="Replace",
width=170,
height=28,
command="batchRenamerUi.replace_objects()",
parent=button_layout)

replace_btn = cmds.button(label="Cancel",
width=170,
height=28,
command="batchRenamerUi.delete()",
parent=button_layout)

cmds.window(main_window, e=True, w=200, h=150)
cmds.window(main_window, e=True, sizeable=True)
cmds.window(main_window, e=True, rtf=True)

cmds.showWindow(main_window)

重命名函数

退出设定

  • 如果关闭窗口,则退出UI界面
1
2
3
4
@classmethod
def delete(cls):
if cmds.window(cls.WINDOW_NAME, exists=True):
cmds.deleteUI(cls.WINDOW_NAME, window=True)

自动后缀设定

  • 如果自动后缀功能开启,则无法使用后缀重命名
1
2
3
4
5
6
@classmethod
def toggleSuffixField(cls, value):
if value:
cmds.textFieldGrp(cls.suffix_tfg, e=1, en=0)
else:
cmds.textFieldGrp(cls.suffix_tfg, e=1, en=1)

重命名函数

获取值
  • 获取UI中所有的值,并保存到相应变量
  • 定义appending中的counter初始值为1,以作后用
1
2
3
4
5
6
7
8
@classmethod
def rename_objects(cls):

rename_data = cmds.textFieldGrp(cls.name_tfg, query=True, text=True)
prefix_data = cmds.textFieldGrp(cls.prefix_tfg, query=True, text=True)
padding_data = cmds.intField(cls.padding, query=True, value=True)
hierarchy_data = cmds.radioButtonGrp(cls.method, query=True, select=True)
counter = 1
方法判定
  • 判定选择方法,如果 hierarchy_data = 2,则代表选择了第二个选项,代表选择了hierarchy
  • 如果用户选择了hierarchy,则使用cmds.listRelatives()获取所有后代物体,并选中(很好用!)
  • 若选择的是select,则只选择场景中选中的模型
1
2
3
4
5
6
7
if hierarchy_data == 2:
sel = cmds.ls(sl=True, tr=True)
children = cmds.listRelatives(sel, ad=True, type='transform')
cmds.select(children, add=True)
sel = cmds.ls(sl=True)
else:
sel = cmds.ls(sl=True)
获取后缀
  • 错误判定,若未选择模型,则提示报错
  • 检查box里是否选择了自动后缀,若无,则获取用户输入的后缀信息
  • 若有,则获取层级下的所有子对象的type,并对照字典一一赋予
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
if len(sel) < 1:
raise RuntimeError("Please select at least one object to rename")

else:
for obj in sel:
if cmds.checkBoxGrp(cls.autoSuffix_cbg, query=True, value1=True):
objType = cmds.objectType(obj)

if objType == "transform":
children = cmds.listRelatives(obj, children=True, ni=True)[0]
objType = cmds.objectType(children)
suffix_data = "_" + SUFFIXES.get(objType, DEFAULT_SUFFIX)
else:
suffix_data = cmds.textFieldGrp(cls.suffix_tfg, query=True, text=True)


重命名:
  • "{0}{1}{2}{3}".format(prefix_data, rename_data, str(counter).zfill(padding_data), suffix_data中的"{0}{1}{2}{3}".表示将后方的4个数值合并为一个新的字符串
  • 每复制一个物体,计数器增加1
  • 最后清除选择
1
2
3
4
5
6
7
  			cmds.rename("{0}{1}{2}{3}".format(prefix_data, rename_data, 			     						str(counter).zfill(padding_data), suffix_data))
counter+=1

# 输出有多少模型被更改

print("Renamed {0} Objects".format(len(sel)))
cmds.select(cl=True)

搜索与替换函数:

获取值
  • 定义搜索与替换函数
  • 获取搜索、替换和方法值
1
2
3
4
5
6
@classmethod
def replace_objects(cls):

searchFor_data = cmds.textFieldGrp(cls.searchFor_tfg, query=True, text=True)
replaceWith_data = cmds.textFieldGrp(cls.replaceWith_tfg, query=True, text=True)
hierarchy_data = cmds.radioButtonGrp(cls.method, query=True, select=True)
判定与替换:
  • 同上:获取所选模型,并保存到sel变量中(selection缩写)
  • 使用str.replace命令,把新名称替换旧名称
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
if hierarchy_data == 2:
sel = cmds.ls(sl=True, tr=True)
children = cmds.listRelatives(sel, ad=True, type='transform')
cmds.select(children, add=True)
sel = cmds.ls(sl=True)
else:
sel = cmds.ls(sl=True)

if len(sel) < 1:
raise RuntimeError("Please select at least one object to replace")
elif searchFor_data == "":
raise RuntimeError("Please enter a name to search for")
elif replaceWith_data == "":
raise RuntimeError("Please enter a name to replace with")
else:
for i in sel:
if searchFor_data in i:
renamedString = i.replace(searchFor_data, replaceWith_data)
cmds.rename(i, renamedString)
  • !!!重点:replace 是 Python 字符串方法,用于替换字符串中的子字符串。注意!这只是在 Python 中修改了字符串,它并不会实际更改场景中物体的名称。因此,要更改场景中的物体名称,还是需要使用 cmds.rename(oldname,newname) 命令(血的教训!!!)
  • Title: 作品:《在Maya和UE5中制作批量重命名工具》
  • Author: Shuhang Luan
  • Created at: 2023-02-01 16:05:07
  • Updated at: 2023-03-19 10:37:37
  • Link: https://archieluan.github.io/2023/02/01/rename-maya-tool/
  • License: This work is licensed under CC BY-NC-SA 4.0.
推荐阅读
作品:《用Python创建飓风模拟器》 作品:《用Python创建飓风模拟器》 作品:《风格化森林-程序化生成工具》 作品:《风格化森林-程序化生成工具》 文档:《从农场到游戏:实现有机食品虚拟场景中的模块化材质技术》 文档:《从农场到游戏:实现有机食品虚拟场景中的模块化材质技术》
 Comments
评论
  • 按正序
  • 按倒序
  • 按热度
Powered by Waline v2.14.7
On this page
作品:《在Maya和UE5中制作批量重命名工具》