[Python] 向3ds Max中写入UV数据

这篇博客对应于上一篇博客:[Python] 从FBX文件中读取数据,介绍如何将获得的UV数据写入到3ds MAX中的模型中。

首先,必须要知道的一个重要常识是,3ds Max中的索引大部分都是从1开始的,与Python不同,使用时必须注意到这点去转换索引。

1. 获取要写入的模型

通过getNodeByName接口就可以直接根据模型名称获取到需要写入的模型

# 引入Max的python库
from pymxs import runtime as rt

triObj = rt.getNodeByName(fbxMeshName) 

由于模型类型poly和mesh类型的接口不一致,为了方便起见,可以通过类型判断,用一个变量统一地使用接口

rt_convert = rt.polyop
nodecls = rt.classOf(triObj)
if str(nodecls) == "Editable_mesh":
    rt_convert = rt.meshop

2. 添加通道

通过defaultMapFaces方法可以新建一个初始化好的新通道,并使用channelInfo.NameChannel来为通道命名

注意 使用这种方法获得的新通道不是修改器形式

为了可以更好的控制 我们可以通过channelInfo.AddChannel方法来新建一个通道 再使用defaultMapFaces方法进行初始化 这样新通道就是以修改器形式展示的了

可以访问节点的修改器属性triObj.modifiers[0].name为该修改器命名 以更好的理解

rt.channelInfo.AddChannel(oriObj)
rt_convert.defaultMapFaces(triObj, uv_num + 1) # 初始化通道
rt.channelInfo.NameChannel(triObj, 3, uv_num + 1, "new") # 为新通道命名
triObj.modifiers[0].name = "AutoUV - Add EmptyUV"

3. 设置通道

这里的UVCount表示UV面的大小数组,UVValue是UV顶点数组

uvWriteChannel = 2
nfaces = len(UVCount)
nverts = int(len(UVValue) / 2)

rt_convert.setMapSupport(triObj, uvWriteChannel, True)
rt_convert.setNumMapVerts(triObj, uvWriteChannel, nverts)
rt_convert.setNumMapFaces(triObj, uvWriteChannel, nfaces)

使用 SetMapSupport()设置 UV 映射支持启用2号通道, 使用SetNumMapVerts() 设置UV 映射的顶点数,使用 SetNumMapFaces() 设置UV 映射的面数

4. 设置顶点

3ds Max中的顶点类型为Point3类型,由于UV数据为二维坐标,这里将获取到顶点分别设置为Point3的x和y,将z设置为0
接着遍历所有顶点 使用setMapVert方法设置每个顶点的坐标

# faces
for vert in range(nverts):
    UVVert = rt.Point3(UVValue[2 * vert], UVValue[2 * vert + 1], 0)
    rt_convert.setMapVert(triObj, uvWriteChannel, vert + 1, UVVert)

5. 设置面

由于不同的类型会导致对应模型面数组的不一致,因此这里通过类型判断分别设置了面数组的类型
接着遍历每个面,构成对应的面的顶点序号数组,最后使用setMapFace方法将面数据写入3ds Max中

faceIndex = -1
for face in range(nfaces):
    if str(triObjcls) == "Editable_mesh":
        faceVertex = rt_convert.getMapFace(triObj, uvWriteChannel, face + 1)
    else:
        faceVertex = rt.Array()
    for d in range(UVCount[face]):
        faceIndex += 1
        if str(triObjcls) == "Editable_mesh":
            faceVertex[d] = UVIndex[faceIndex] + 1
        else:
            rt.append(faceVertex, UVIndex[faceIndex] + 1)

    rt_convert.setMapFace(triObj, uvWriteChannel, face + 1, faceVertex)