defbuildUI(self): cmds.columnLayout(adj=True) cmds.button(label='Smooth Normal To VertCol', ann='Smooth Normal To VertCol', h=60, w=300, command=self.CalculateSmoothNormalToVerCol) cmds.button(label='Smooth Normal To Texture', ann='Smooth Normal To Texture', h=60, w=300, command=self.CalculateSmoothNormalToTexture)
if selectList.isEmpty(): om.MGlobal.displayError("You Need To Select A Target") return if selectList.length() > 1: om.MGlobal.displayError("You Can Just Handle One Target Once") return
uvSet = cmds.polyUVSet(SelectionModels[0], query=True, currentUVSet=True) colorSet = cmds.polyColorSet(SelectionModels[0], query=True, currentColorSet=True) if uvSet == None: om.MGlobal.displayError("You Need To Creat A UV Set For Selected Model") return else: uvSet = uvSet[0] if colorSet == None: om.MGlobal.displayError("You Need To Apply A Color Set For Selected Model") om.MGlobal.displayInfo("Method: Select Target -> Mesh Display/Apply Color") return else: colorSet = colorSet[0] print("Color Set Exist: %s" % (colorSet))
if isToVertex: fnMesh.setColors(self.NormalTS,colorSet) else: print("To Texture is Not Available") white = om.MColorArray() for i inrange(fnMesh.numFaceVertices): white.append(om.MColor([1.0, 1.0, 1.0])) fnMesh.setColors(white, colorSet)
defbuildUI(self): cmds.columnLayout(adj=True) cmds.button(label='Smooth Normal To VertCol', ann='Smooth Normal To VertCol', h=60, w=300, command=self.CalculateSmoothNormalToVerCol) cmds.button(label='Smooth Normal To Texture', ann='Smooth Normal To Texture', h=60, w=300, command=self.CalculateSmoothNormalToTexture)
if selectList.isEmpty(): om.MGlobal.displayError("You Need To Select A Target") return if selectList.length() > 1: om.MGlobal.displayError("You Can Just Handle One Target Once") return
uvSet = cmds.polyUVSet(SelectionModels[0], query=True, currentUVSet=True) colorSet = cmds.polyColorSet(SelectionModels[0], query=True, currentColorSet=True) if uvSet == None: om.MGlobal.displayError("You Need To Creat A UV Set For Selected Model") return else: uvSet = uvSet[0] if colorSet == None: om.MGlobal.displayError("You Need To Apply A Color Set For Selected Model") om.MGlobal.displayInfo("Method: Select Target -> Mesh Display/Apply Color") return else: colorSet = colorSet[0] print("Color Set Exist: %s" % (colorSet))
if isToVertex: fnMesh.setColors(self.NormalTS,colorSet) else: print("To Texture is Not Available") white = om.MColorArray() for i inrange(fnMesh.numFaceVertices): white.append(om.MColor([1.0, 1.0, 1.0])) fnMesh.setColors(white, colorSet)
defbuildUI(self): # 窗口中UI(两个Button)的创建 cmds.columnLayout(adj=True) cmds.button(label='Smooth Normal To VertCol', ann='Smooth Normal To VertCol', h=60, w=300, command=self.CalculateSmoothNormalToVerCol) cmds.button(label='Smooth Normal To Texture', ann='Smooth Normal To Texture', h=60, w=300, command=self.CalculateSmoothNormalToTexture)
defExecute(self, isToVertex): SelectionModels = cmds.ls(sl=True, l=True) selectList = om.MGlobal.getActiveSelectionList() # Return an MSelectionList containing the nodes, components and plugs currently selected in Maya # 返回的是一个选择列表MSelectionList,MSelectionList是一个MObject、MPlug、MDagPath的异构列表 # 需要通过遍历选择列表,通过利用遍历的index获取DAGPath,然后利用DAGPath来获取到MFnMesh # MFnMesh类中存储了许多网格体的信息
# 限制同时处理的对象(有且只能有1个) if selectList.isEmpty(): om.MGlobal.displayError("You Need To Select A Target") return if selectList.length() > 1: om.MGlobal.displayError("You Can Just Handle One Target Once") return
# 检查选中的对象是否有Colorset和UVset uvSet = cmds.polyUVSet(SelectionModels[0], query=True, currentUVSet=True) colorSet = cmds.polyColorSet(SelectionModels[0], query=True, currentColorSet=True) if uvSet == None: om.MGlobal.displayError("You Need To Creat A UV Set For Selected Model") return else: uvSet = uvSet[0] if colorSet == None: om.MGlobal.displayError("You Need To Apply A Color Set For Selected Model") om.MGlobal.displayInfo("Method: Select Target -> Mesh Display/Apply Color") return else: colorSet = colorSet[0] print("Color Set Exist: %s" % (colorSet))
dagPath = selectList.getDagPath(0) # DAG是Directed Acyclic Graph的缩写 # DAG节点是Maya场景中的节点,包括transform和shape两种类型的节点。 # transform节点提供位置、旋转、缩放等信息,并且可以有子节点;shape节点只提供几何信息,并且没有子节点。 # 可以把dagPath理解为指向一个特定模型对象的路径,通过这个路径可以获取有关这个物体的很多信息,并以此填充到特定数据结构(类)中 fnMesh = om.MFnMesh(dagPath) # 通过dagPath路径获得多边形网格模型 fnMesh.setCurrentColorSetName(colorSet) normals = fnMesh.getNormals() # Returns a copy of the mesh's normals. The normals are the per-polygon per-vertex normals. # 即获取模型的法线信息,返回值是MFloatVectorArray,如果要获得特定顶点的法线,需要通过getFaceNormalIds()来获得数组的索引 itVerts = om.MItMeshVertex(dagPath) # 获取多边形网格模型的顶点迭代器vertex iterator self.NormalOS.setLength(fnMesh.numFaceVertices) self.NormalTS.setLength(fnMesh.numFaceVertices) # 基于顶点数量来设置之前创建的数组的长度
whilenot itVerts.isDone(): # 逐个顶点进行计算和顶点色写入 associatedNormalIndices = itVerts.getNormalIndices() # This method returns the normal indices of the face/vertex associated with the current vertex # 返回与这个顶点相关联的顶点、面的法线索引(平均值这不仅来了吗!) for normalIndex in associatedNormalIndices: averageNormal += normals[normalIndex] averageNormal.normalize() # 求和取平均,直接使用MFloatVector类带的normalize即可
colorIndices = itVerts.getColorIndices(colorSet) # This method returns the colorIndices into the color array # 获取当前顶点的全部顶点色索引(一个顶点可能有多个顶点色索引,指向不同的颜色集合,这一点我认为是和一个顶点在Maya中可能有多个法线同理,导出后会变成多个顶点,但会与信息一一对应) for colorIndex in colorIndices: averageColor.r = averageNormal.x averageColor.g = averageNormal.y averageColor.b = averageNormal.z averageColor.a = 1.0 self.NormalOS.__setitem__(colorIndex, averageColor) # 写入NormalOS的Color数组,因为这套逻辑中设置顶点是直接统一用一个数组去Copy设置的,所以需要保证这里的索引值与顶点色中的索引值相同 # 同样也可以一个一个去setColors averageNormal = om.MFloatVector(0.0, 0.0, 0.0) # 重置一下averageNormal,然后继续计算下一个平滑法线颜色 itVerts.next() print("ObjectSpace Smooth Normal Calculation Finished")
self.NormalTS.__setitem__(colIndex, averageColor) itFaceVerts.next() print("ObjectSpace To TangentSpace Transformation Finished")
学习心得
起初看了一些写Python代码的教程,是通过学习Python调用Maya.cmds来入门的Python For Maya,也跟着教程简单的写了几个小工具。到后面实际去做自己想要的工具时,发现cmds能够实现的功能很有限制,同时找到了那位大佬的文章,就去跟着他的代码学习了一下OpenMaya的库,基本上就是结合它的代码,一行一行地读,不会的就去官方文档查,并借助NewBing去寻找更多的资料。在全部理解完大佬的代码后,就参考着他的源码,结合之前学的一些创建可视化窗口和面向对象的知识,写出了这个工具