在本教程中,我们将了解如何在 Blender 中使用 UV 导出布局的 Python 函数,来导出场景中所有 MESH 对象的 UV 贴图,也就是布局。
本教程的视频版本目前尚未提供该语言版本。英文版视频可通过以下链接观看:
视频文字稿
大家好。在本教程中,我们将了解如何在 Blender 中使用 UV 导出布局的 Python 函数,来导出场景中所有 MESH 对象的 UV 贴图,也就是布局。
如果你需要以图像形式提供 UV 贴图,例如在 3D 素材网站上发布你的 3D 场景时,这个脚本会非常有用。
本教程使用的是 Blender 3.3。有时 Blender 开发者会对 Blender Python API,也就是简称 BPY,进行修改,但这个脚本从 3.x 版本开始都应该可以正常工作。
我们将要使用的 bpy.ops 函数非常简单。它只需要两个参数,一个是要创建的图像的 filepath,另一个是 UV 的尺寸,以像素为单位。不过,由于我们需要对场景中所有可用的 MESH 对象使用它,因此我们会对 MESH 对象使用一个 for 语句。
另外,我还会指定文件扩展名。默认情况下是 PNG。实际上,我会把布局导出为 PNG 文件,但我想向你展示如何进行指定,因为你也可以将 UV 布局导出为 SVG 或 EPS 文件。
好,我们开始吧。
打开一个 BLEND 文件。
你也可以从一个全新的文件开始,但你需要先把它保存到某个位置,因为我们会把 PNG 文件放在与项目相同的文件夹中。
我们先做一些基本的导入:
import bpy
from bpy import *
正如我之前所说,export_layout 函数需要两个参数,所以我们来定义两个变量。我们也可以直接把数值写在函数里,但为了更清晰,我更喜欢在这里定义:
UVpath = bpy.path.abspath("//") + "UV-LAYOUT---"
UVsize = (2048, 2048)
如你所见,bpy.path.abspath 会返回 BLEND 文件在磁盘上的绝对路径。我们会给所有 PNG 文件加上一个前缀,也就是 "UV-LAYOUT---",当然你也可以修改或者移除它。
UVsize 参数是一个包含两个数值的元组,它们表示要创建的图像的尺寸,以像素为单位。
我这里写的是 2048,也就是创建一张 2K 的图像。
为了对场景中所有可用的 MESH 对象执行这个函数,我们需要创建一个 for 语句,可以这样写:
for o in bpy.data.objects:
然后,在 for 语句的代码块内部,也就是不要忘记缩进,我们可以对对象的类型加一个“过滤条件”:
if(o.type=="MESH"):
这个条件很清楚,当前 bpy.data.object 的类型必须是 MESH。
接下来的语句都必须写在 if 里面,所以再一次,不要忘记缩进。
bpy.ops.objects.select_all(action='DESELECT');
我们每次都需要这样做,用来取消选择所有其他对象,否则我们会得到一张包含两个或更多 UV 贴图重叠在一起的图像。
bpy.context.view_layer.objects.active = o
这个赋值操作会设置场景中的活动对象,将当前的网格对象赋给 context.view_layer.objects.active。
我们必须这样做,因为接下来的 OPS,也就是 Blender Python 操作,只会作用于唯一的活动对象。记住,你可以同时选中多个对象,但在任意时刻只能有一个活动对象。
bpy.ops.uv.export_layout(filepath = UVpath + o.name, size = UVsize, mode='PNG')
这个 ops 语句会将活动对象的 UV 布局导出到指定的 filepath。这个路径由 UVpath 变量加上 "UV-LAYOUT---" 前缀,再加上活动对象的名称组成,并且使用指定的尺寸,以像素为单位。

正如我之前告诉你的,你可以将 UV 布局导出为 PNG、EPS 或 SVG 文件。你可以通过 mode 参数来指定输出格式,正如我刚才展示的那样。
如果我们查看输出文件夹,就可以看到脚本创建了与网格数量相同的图像。

由于我这个 “Desk set 3” 3D 模型中的网格共享同一个布局,并且 UV 岛之间没有重叠,我可以把所有对象合并在一起,再次运行脚本,然后得到一张不重叠的、用于整个资产的 UV 布局图。

在结束本教程之前,我给你留一个作业。编辑这个脚本,让它同时导出 2K 和 4K 的 UV 布局,用两个不同的前缀来保存图像,例如 "UV-2K---" 和 "UV-4K---"。
本教程就到这里。
我们下次再见。