获取分配给着色器的网格名称

3 投票
3 回答
6658 浏览
提问于 2025-04-18 10:20

我想知道怎么用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 个回答

0

在我发布之前的回答后,我偶然发现了Maya中的一个意外行为。

我发现,当我尝试从Hypershade窗口选择一个shadingEngine节点(着色组节点)时,属性编辑器会显示该着色引擎的属性,如下所示:

在Hypershade窗口中选择的着色组节点

现在,如果你点击属性编辑器底部的“选择”按钮,试图真正选择那个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 ''
2

我在尝试生成一个场景中已有的着色器列表时,遇到了同样的问题,还想知道每个着色器被分配给了哪些对象(比如网格、形状、变换)。

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)
3

这个着色器是连接到一个或多个着色集合的,这些集合里包含了各种分配的任务。所以这里不是一对一的关系,而是一对多,然后又是一对多(虽然这种情况并不常见)。请注意,你使用了两个命名空间,而实际上只需要一个就可以了。

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)

撰写回答