本篇博客是对应于上一篇博客:Python下自定义数据导出为FBX,这篇博客主要介绍如何将FBX模型中的UV数据提取出来。
1. 初始化FBX设置
首先要做的就是是创建FBX SDK管理器,它几乎是所有FBX SDK中的类的对象分配器。
接着,创建FBX IO设置,并为FBX SDK管理器设置IO设置。
然后,创建一个空白的场景,用于读入数据。
lSdkManager = FbxManager.Create()
if not lSdkManager:
sys.exit(0)
ios = FbxIOSettings.Create(lSdkManager, IOSROOT)
lSdkManager.SetIOSettings(ios)
lScene = FbxScene.Create(lSdkManager, "")
2. 导入模型
导入模型时,先创建FbxImporter
并初始化,Initialize
方法的第一个参数是导入文件保存路径,第二个参数表示导入的FBX文件类型,这里1代表为ASCii码格式。然后,调用该对象的Import
方法将fbx模型导入到当前的场景,最后使用GetRootNode
获取场景的根节点。
def import_scene(fbxManager, fbxScene, fbxFilePath):
lImporter = FbxImporter.Create(fbxManager, "")
result = lImporter.Initialize(fbxFilePath, 1, fbxManager.GetIOSettings())
if not result:
return False
result = lImporter.Import(fbxScene)
lImporter.Destroy()
fbxIOSettings = FbxIOSettings.Create(fbxManager, IOSROOT)
fbxManager.SetIOSettings(fbxIOSettings)
if not result:
raise IOError("load file [{}] failed".format(fbxFilePath))
fbxRootNode = fbxScene.GetRootNode()
return fbxRootNode, fbxIOSettings
3. 读入模型UV数据
3.1 读入mesh数据
首先,通过GetChild(i)
遍历获取fbx文件中的每个模型,然后调用GetMesh
获取每个模型的mesh数据。
下一步,使用 GetControlPoints()
方法获取网格的控制点。然后,我们遍历控制点,并将每个控制点的坐标存储在 vertices
数组中。
接下来,我们使用 GetPolygonCount()
方法获取网格的多边形数,并使用 GetPolygonSize()
和 GetPolygonVertex()
方法获取每个多边形的顶点索引,并将它们存储在 faces
数组中。
最后,我们使用 GetNormals()
方法获取网格的法线数据,并将它们存储在 normals
数组中。
for i in range(fbxRootNode.GetChildCount()):
fbxMesh = fbxRootNode.GetChild(i)
if fbxMesh is None:
raise RuntimeError("The node is null!")
fbxMeshName = fbxMesh.GetName()
mesh = fbxMesh.GetMesh()
# 提取顶点数据
vertices = []
control_points = mesh.GetControlPoints()
for i in range(mesh.GetControlPointsCount()):
vertices.append((control_points[i][0], control_points[i][1], control_points[i][2]))
# 提取面数据
faces = []
polygon_count = mesh.GetPolygonCount()
for i in range(polygon_count):
polygon_size = mesh.GetPolygonSize(i)
for j in range(polygon_size):
faces.append(mesh.GetPolygonVertex(i, j))
# 提取法线数据
normals = []
layer_element_normal = mesh.GetLayer(0).GetNormals()
if layer_element_normal:
for i in range(mesh.GetPolygonCount() * 3):
normal = layer_element_normal.GetDirectArray().GetAt(i)
normals.append((normal[0], normal[1], normal[2]))
3.2 读入UV数据
对于UV数据,直接调用GetElementUV
方法即可获取对应名称的UV数据
然后用UVValue
存放UV中的顶点数据,用UVIndex
存放面中的顶点序号数组,用UVCount
存放每个面的顶点数目。
通过UV数据的GetDirectArray()
可以访问其顶点数组,通过GetIndexArray()
可以访问面的顶点序号数组。
接着分别调用对应数组的GetAt
方法获取对应的数据存入UVValue
和UVIndex
,最后使用GetPolygonSize
方法获取每个面的大小存入UVCount
中.
try:
# init output uv data
UVValue = []
UVIndex = []
UVCount = []
UVData = mesh.GetElementUV("map01")
numVtx = UVData.GetDirectArray().GetCount()
numIndex = UVData.GetIndexArray().GetCount()
# separate uv data: value, index, count
for i in range(numVtx):
UVValue.append(UVData.GetDirectArray().GetAt(i)[0])
UVValue.append(UVData.GetDirectArray().GetAt(i)[1])
for j in range(numIndex):
UVIndex.append(UVData.GetIndexArray().GetAt(j))
for k in range(mesh.GetPolygonCount()):
UVCount.append(mesh.GetPolygonSize(k))
except Exception as e:
runtime_msg.popup_msgbox(info_loader.return_tips_msg(plugin_msg_code.PLUGIN_E_WRITE_UV))
raise e