学习进度
0/9 已勾只保存在这台浏览器;勾满 9 项即视为本题完成。
先把题目说成人话
一个角色往往带着许多外观图片:有的负责皮肤颜色,有的负责凹凸,有的只控制头发哪里透明。若文件都叫“最终版”“新最终版”,人和引擎都无法稳定判断它属于谁、贴在哪个部位、负责什么。
这题要写的脚本不是生成贴图,而是先识别现有贴图的身份,再生成规范名称。模型上挂一套外观的位置叫材质槽(Material Slot),一张图具体负责什么叫贴图用途(Map Type)。真正执行改名时,磁盘文件和所有仍在寻找旧路径的材质引用必须一起改变,否则角色会立刻丢图。
这是虚构教学故事,不是个人项目经历。
场景:先让问题变得看得见
制作软件(Blender)里有一个角色,身体、头发和盔甲分别使用不同材质。图片却叫“最终版”“新最终版”和“未命名三号”,几张灰色缩略图看起来几乎一样。
(右脑)画面:小明按照旧文件名里的几个字母批量改名。一张名字像法线的图片实际连在粗糙度上,结果被贴错身份;另一张“最终版”完全看不出用途。小红不再猜名字,而是顺着图片后面的连线观察它最终接到材质的哪一个入口:进入颜色入口的叫基础颜色,经过法线转换后进入表面方向入口的叫法线,进入粗糙程度入口的叫粗糙度。工具先铺开一张“旧名字、连接位置、候选新名字”的清单;用途看不清的停下来,两张图想占同一个名字的也停下来。确认以后,一份真实图片只搬动一次,而所有牵着它的材质连线同时跟到新位置。角色重新打开时,脸、头发和盔甲仍然各自找到原来的图片。
(左脑)对表:名称可由 {asset}_{material}_{mapType}[.{UDIM}].ext 组成。用途优先从材质节点连接判断,旧文件后缀只作低可信提示;混合节点、节点组和通道打包无法证明时进入人工复核。同一物理文件可能被多个节点引用,必须先按规范化路径聚合,再生成唯一目标并更新全部引用。执行前检查多源同目标、目标已存在、权限、大小写和跨盘风险,完成后重新打开 DCC,并导入 Unity 验证贴图类型与颜色空间。
小明:先形成一个完整猜测
小明直接用正则把 diff 替换成 basecolor、把 nrm 替换成 normal。结果一张命名错误的粗糙度图被继续认错,HeroA_Body_diff.1001.exr 又与另一张候选基础颜色贴图撞名。文件虽然改了,材质节点仍指向旧路径。失败说明:旧名字不能证明语义,改名也不是一次孤立的字符串替换。
小红:把猜测放回现实检查
小红先让 Blender Python 脚本停在“只分类、不改名”。它真的遍历当前选中模型、材质槽与 Image Texture 节点;用途优先从节点连接判断,无法判定就进入人工确认:
import bpy
from pathlib import Path
SOCKET_TYPES = {
"Base Color": "basecolor",
"Roughness": "roughness",
"Metallic": "metallic",
"Alpha": "opacity",
}
def linked_map_type(tex_node):
for output in tex_node.outputs:
for link in output.links:
target = link.to_node
if target.type == "NORMAL_MAP":
return "normal"
if target.type == "BSDF_PRINCIPLED":
return SOCKET_TYPES.get(link.to_socket.name)
return None # 间接节点链不能靠文件后缀冒猜
plan = []
for obj in bpy.context.selected_objects:
asset = obj.get("asset_id") or obj.name
for slot in obj.material_slots:
mat = slot.material
if not mat or not mat.use_nodes:
continue
for node in mat.node_tree.nodes:
if node.type != "TEX_IMAGE" or not node.image:
continue
map_type = linked_map_type(node)
src = Path(bpy.path.abspath(node.image.filepath))
if not map_type:
plan.append({"status": "review", "image": node.image, "src": src})
continue
udim = ".<UDIM>" if node.image.source == "TILED" else ""
dst = src.with_name(
f"{asset}_{mat.name}_{map_type}{udim}{src.suffix.lower()}")
plan.append({"status": "ready", "image": node.image,
"src": src, "dst": dst})
这段代码已经落到 DCC API,但得到的 plan 仍只是“每个节点一行”的发现结果,还故意没有移动文件。执行前先把相对路径、分隔符和路径片段规范化;是否折叠大小写必须服从目标文件系统,符号链接也要有固定解析策略。普通图片以规范化物理路径为键;平铺图片则先展开并校验全部 tile,再以规范化 UDIM 模板和完整 tile 清单组成一个集合键。随后按键合并重复行,聚合所有 Image 数据块、纹理节点、材质和对象引用者。若同一物理文件或 UDIM 集因不同材质语义算出多个目标名,只能进入 review,不能执行多次改名。
聚合结果写入 manifest 后,才检查多个物理来源映射同一目标、目标已存在、只读文件、跨盘移动与所有 review 项。通过后一组物理文件只执行一次“源路径 → 唯一临时路径 → 最终路径”的迁移,并把该组所有 image.filepath 一并更新;UDIM 的每个 tile 分别记录源、目标和哈希,但整组共同提交。任一步失败时,每个物理文件只逆向搬一次,再恢复全部聚合引用。角色名来自资产标识,材质名来自绑定槽,UDIM 占位与扩展名被保留。
我:用检查结果修正模型
我把执行做成两阶段。第一阶段按“规范化物理文件或完整 UDIM 集”聚合所有引用,生成 manifest,并阻断未知用途、同一来源产生多种语义、多源映射同一目标和目标已经存在等冲突。确认后,每组物理文件先搬到唯一临时名,再搬到最终名,避免名称互换或大小写变化造成覆盖;所有引用者同时更新。任一步失败,就按 manifest 反向恢复物理路径和引用。
完整流程是:遍历所选模型的材质槽 → 找纹理节点 → 分类用途 → 规范化物理路径并展开 UDIM 集 → 按物理键聚合引用 → 生成候选名 → 全局检测冲突 → 预览 → 每组一次临时改名 → 更新全部引用 → 每组一次最终改名 → 保存副本并重新打开验证。改名完成后还要把产物导入目标 Unity 项目,确认规则确实触发了正确的色彩空间和材质槽。示例只处理直接连接;经过 Mix、Separate Color 或节点组的图必须扩展图遍历,不能让这段最小代码假装覆盖所有材质。同一文件若把粗糙度、金属度和遮罩装进不同通道,就应识别成一份带通道契约的打包贴图,不能为每条连接各改成一个互相冲突的单用途名字;UDIM 也要枚举、逐 tile 计算哈希并作为整组校验。
目前没有证据证明你写过这款自动命名脚本。本页不能替你补写真实工具经历;它只能作为一套 Blender Python 或 MaxScript 的设计方案。
(右脑)画面修正:再看那几张灰扑扑的图片,改名不再是撕掉旧标签、贴上新标签就走。小红先确认每张图现在连着角色的哪个部位,再把新名字和新的去处一起预演出来。遇到两张图想占同一个名字,她先让它们各自停在不同的临时位置;遇到看不出用途的图,她宁可留下待确认,也不替美术猜。角色重新打开时,脸和盔甲都仍然接着自己的图片。
(左脑)严格对表:严格流程是:遍历选中对象与材质槽 → 沿已支持的节点连接确定单用途或通道打包契约 → 无法证明的用途标记 review → 将普通文件规范化成物理路径键、将平铺图片展开成“规范化模板 + 完整 tile 清单”的 UDIM 集键 → 按键聚合所有 Image 数据块、节点、材质与对象引用 → 用 asset、material、mapType、UDIM、扩展名生成候选路径 → 同一键出现多种语义或目标时转人工,拒绝多源同目标、已存在目标、权限和跨盘风险 → 写出含逐物理文件哈希与全部引用者的 manifest → 每组源文件只改一次唯一临时名并同步全部引用 → 再改最终名 → 保存副本、重新打开并导入 Unity 验证。任一步失败时每个物理文件只逆向恢复一次,再恢复全部引用;只有文件、DCC 引用和 Unity 语义三者一致才通过,真实项目规模与成绩不能由这段教学算法代填。
老师解惑
- 命名契约:推荐形式可为
{asset}_{material}_{mapType}[.{UDIM}].ext,但项目必须定义唯一词典。 - 语义来源:节点连到了 Base Color 还是 Normal,比文件原名更可靠;无法确定时要停下来。
- 两阶段改名:先到临时唯一名,再到最终名,避免交换名称与大小写差异造成覆盖。
- manifest:记录源、目标、引用者、哈希、规则版本和状态,是恢复与审计依据。
工具分工
- MaxScript/Python DCC API:读取选中模型、材质槽、Bitmap/File 节点并更新路径。
- 文件系统层:检查存在性、大小写、权限与跨盘移动;不允许静默覆盖。
- 规则配置:保存别名字典、目录规则、UDIM 和通道打包约定。
- Unity 导入检查:验证命名规则是否正确触发 sRGB、Normal Map 等设置。
记忆钩子
先从材质连接认出“它是谁”,再生成名字;改文件和改引用必须是一件可回滚的事。
这是教学场景,不是目标项目的真实捕获或个人经历。
下一步:验证这条因果
贴图旧路径怎样被解析为材质与通道,再生成可审查的新路径、冲突和回滚标识。
教学边界:它不读取真实像素、不验证颜色空间,也不会真的调用 Unity AssetDatabase 写盘。