获取分配给着色器的网格名称
我想知道怎么用Python获取给着色器分配的网格名称。
比如,lambert02 对应的是 AreaA_01_geo,lambert03 对应的是 AreaA_03_geo,lambert04 对应的是 AreaA_04_geo。
我试过用
Shader = cmds.ls(type = 'surfaceShader')
for i in Shader:
con = mc.listConnections('%s.outColor' % i)
name = cmds.listConnections(Shader, type="mesh")
但是我从 name
变量里什么都没得到。
3 个回答
在我发布之前的回答后,我偶然发现了Maya中的一个意外行为。
我发现,当我尝试从Hypershade窗口选择一个shadingEngine节点(着色组节点)时,属性编辑器会显示该着色引擎的属性,如下所示:

现在,如果你点击属性编辑器底部的“选择”按钮,试图真正选择那个shadingEngine节点,你会得到以下结果:

Maya实际上为我们选择了分配的网格对象。
所以我尝试用这一行代码做同样的事情:
select('aiHeiyuVarABelts2Shader', replace=True)
Maya也选择了与该着色器相同的网格节点。
这是与我之前回答中的测试场景完全相同的场景。在我之前的代码中,listConnections()返回了连接到shadingEngine节点的变换节点,而使用上述两种新方法选择shadingEngine节点时,Maya实际上为我们选择了网格对象。
因此,利用这种看似不一致的行为,我可以修改我的代码,专门获取你所询问的网格列表。
for shEngine in ls(type='shadingEngine'):
select(shEngine, replace=True)
print 'shading engine:', shEngine
for connection in ls(sl=True):
print '->', connection, '(%s)' % nodeType(connection)
print ''
在我之前回复中的相同示例场景上运行这个,我得到了:
shading engine: aiHeiyuVarALashesShaderSG
-> C_heiYuA_Mesh_lod200_v007:L_lower_eyelash_geoShape (mesh)
-> C_heiYuA_Mesh_lod200_v007:L_upper_eyelash_geoShape (mesh)
-> C_heiYuA_Mesh_lod200_v007:R_lower_eyelash_geoShape (mesh)
-> C_heiYuA_Mesh_lod200_v007:R_upper_eyelash_geoShape (mesh)
shading engine: aiHeiyuVarAPantsShaderSG
-> C_heiYuA_Mesh_lod200_v007:pants_geoShape (mesh)
shading engine: aiHeiyuVarASkinShaderMapSG
-> C_heiYuA_Mesh_lod200_v007:body_geoShape (mesh)
shading engine: aiTopShaderSG
-> C_heiYuA_Mesh_lod200_v007:top_geoShape (mesh)
shading engine: initialParticleSE
shading engine: initialShadingGroup
-> C_heiYuA_Mesh_lod200_v007:upperTeeths_geoShape (mesh)
-> C_heiYuA_Mesh_lod200_v007:lowerTeeths_geoShape (mesh)
-> C_heiYuA_Mesh_lod200_v007:gums_geoShape (mesh)
-> C_heiYuA_Mesh_lod200_v007:L_nail_geoShape (mesh)
-> C_heiYuA_Mesh_lod200_v007:R_nail_geoShape (mesh)
shading engine: phong1SG
shading engine: useBackground1SG
现在代码更短了,所有选择的对象都是网格对象。
要获取与shadingEngine节点连接的着色器节点/表面材质,我们可以使用:
listConnections(shadingEngineNode, type=['shadingDependNode', 'THdependNode'])
就我个人而言,我倾向于避免使用这种方法,因为我觉得这不太优雅,必须依赖select()
,然后用ls(sl=True)
函数来获取选择的对象。
我是不是有点多虑?用这种方法我也会感到不安,总是担心Maya在未来的版本中是否会继续支持这种行为。
我刚在Maya 2014和Maya 2016中测试过,这段代码在这两个版本中的表现完全相同。
总之,它是有效的。如果你愿意,可以随意利用它 :)
编辑:经过更多的挖掘和搜索,我意识到shadingEngine是objectSet的子类。这种“意外行为”实际上是Maya在处理集合(选择集合、渲染集合、灯光链接集合、变形器成员集合等)时的标准行为。
因此,我们可以直接使用sets(setName, q=True)
来查询集合成员。与上述依赖select()
命令,然后查询选择以获取集合成员的方法相比,这种方式更合理、更优雅且更快。
这是最终的代码:
from pymel.core import *
for shEngine in ls(type='shadingEngine'):
print 'shading engine:', shEngine
for connection in sets(shEngine,q=True):
print '\t->', connection, '(%s)' % nodeType(connection)
print ''
我在尝试生成一个场景中已有的着色器列表时,遇到了同样的问题,还想知道每个着色器被分配给了哪些对象(比如网格、形状、变换)。
from pymel.core import *
def getShaders():
for shEngine in ls(type='shadingEngine'):
print 'shading engine:', shEngine
for connection in shEngine.listConnections():
connectionNodeTypeList = nodeType(connection, i=True)
if [x for x in connectionNodeTypeList if 'ependNode' in x]:
# tests for shader nodes. they inherit the 'shadingDependNode' type
# I am using Arnold renderer. Arnold shading nodes inherit the 'THdependNode' type
print '\t<shader> ->', connection, '(%s)'% nodeType(connection)
if 'dagNode' in connectionNodeTypeList:
# tests for transform, geometry and shape node
# any transform, mesh, shape, curves, vertices, edges, faces
# will inherit from the 'dagNode' type
print '\t<dagNode> ->',connection, '(%s)'% nodeType(connection)
print ''
getShaders()
运行在一个测试场景上时,这会生成一个示例输出,如下所示:
shading engine: aiHeiyuVarALashesShaderSG
<dagNode> -> C_heiYuA_Mesh_lod200_v007:L_lower_eyelash_geo (transform)
<dagNode> -> C_heiYuA_Mesh_lod200_v007:L_upper_eyelash_geo (transform)
<dagNode> -> C_heiYuA_Mesh_lod200_v007:R_lower_eyelash_geo (transform)
<dagNode> -> C_heiYuA_Mesh_lod200_v007:R_upper_eyelash_geo (transform)
<shader> -> aiHeiyuVarALashesShader (aiStandard)
shading engine: aiHeiyuVarAPantsShaderSG
<dagNode> -> C_heiYuA_Mesh_lod200_v007:pants_geo (transform)
<shader> -> aiHeiyuVarAPantsShader (aiStandard)
shading engine: aiHeiyuVarASkinShaderMapSG
<dagNode> -> C_heiYuA_Mesh_lod200_v007:body_geo (transform)
<shader> -> aiHeiyuVarASkinShaderMap (aiStandard)
shading engine: aiTopShaderSG
<dagNode> -> C_heiYuA_Mesh_lod200_v007:top_geo (transform)
<shader> -> aiHeiyuVarATopShader (aiStandard)
shading engine: initialParticleSE
<shader> -> lambert1 (lambert)
<shader> -> particleCloud1 (particleCloud)
shading engine: initialShadingGroup
<shader> -> lambert1 (lambert)
<dagNode> -> C_heiYuA_Mesh_lod200_v007:R_nail_geo (transform)
<dagNode> -> C_heiYuA_Mesh_lod200_v007:L_nail_geo (transform)
<dagNode> -> C_heiYuA_Mesh_lod200_v007:gums_geo (transform)
<dagNode> -> C_heiYuA_Mesh_lod200_v007:lowerTeeths_geo (transform)
<dagNode> -> C_heiYuA_Mesh_lod200_v007:upperTeeths_geo (transform)
shading engine: phong1SG
shading engine: useBackground1SG
从这里开始,如果你特别想找网格对象,就很容易找到相关的网格对象。
补充:
在多读了一些资料后,我发现我们可以使用以下命令来获取分配了着色器的网格对象列表。
sets(shadingEngine, q=True)
因此,最终的形式是
from pymel.core import *
def getShaders():
for shEngine in ls(type='shadingEngine'):
print 'shading engine:', shEngine
for connection in [x for x in shEngine.listConnections()]:
myType = nodeType(connection,i=True)
if ('shadingDependNode' in myType or 'THdependNode' in myType):
# found a shader, printing it out
print '\t<shader> ->', connection, '(%s)'% nodeType(connection)
for connection in sets(shEngine, q=True):
# prints out the list of members that the shader is assigned to
print '\t<dagNode> ->',connection, '(%s)'% nodeType(connection)
print ''
getShaders()
这个最新的方法让我们可以同时获取网格节点和着色器节点。
以下是一个示例输出:
shading engine: aiHeiyuVarAPantsShaderSG
<shader> -> aiHeiyuVarAPantsShader (aiStandard)
<dagNode> -> C_heiYuA_Mesh_lod200_v007:pants_geoShape (mesh)
shading engine: aiHeiyuVarASkinShaderMapSG
<shader> -> aiHeiyuVarASkinShaderMap (aiStandard)
<dagNode> -> C_heiYuA_Mesh_lod200_v007:body_geoShape (mesh)
shading engine: aiTopShaderSG
<shader> -> aiHeiyuVarATopShader (aiStandard)
<dagNode> -> C_heiYuA_Mesh_lod200_v007:top_geoShape (mesh)
shading engine: initialParticleSE
<shader> -> lambert1 (lambert)
<shader> -> particleCloud1 (particleCloud)
shading engine: initialShadingGroup
<shader> -> lambert1 (lambert)
<dagNode> -> C_heiYuA_Mesh_lod200_v007:upperTeeths_geoShape (mesh)
<dagNode> -> C_heiYuA_Mesh_lod200_v007:lowerTeeths_geoShape (mesh)
<dagNode> -> C_heiYuA_Mesh_lod200_v007:gums_geoShape (mesh)
<dagNode> -> C_heiYuA_Mesh_lod200_v007:L_nail_geoShape (mesh)
<dagNode> -> C_heiYuA_Mesh_lod200_v007:R_nail_geoShape (mesh)
这个着色器是连接到一个或多个着色集合的,这些集合里包含了各种分配的任务。所以这里不是一对一的关系,而是一对多,然后又是一对多(虽然这种情况并不常见)。请注意,你使用了两个命名空间,而实际上只需要一个就可以了。
import maya.cmds as mc
Shader = mc.ls(type = 'surfaceShader')
for i in Shader:
con = mc.listConnections('%s.outColor' % i)
names = mc.listConnections(con, type="mesh")
print i, "->", ", ".join(names)