Maya第三方库minq学习
Maya第三方库minq学习
lingyunminq是一个在maya场景中快速物体对象查询的库
仓库地址:https://github.com/theodox/minq
minq简单介绍
这个项目是为了减少Maya中每次对物体查询时,用到命令比如ls()
,listRelatives()
和listHistory()
的频次。意在直接了当的获取所需的物体对象。
举个例子,比如我们想找到场景中角色的IK手柄,你需要:
1 | iks = cmds.ls(type = 'ikHandle') or [] |
对于一个简单的需求,这显然会产生很多的代码。
而且不同的命令返回的结果格式不一样,比如ls()
返回一个列表,你需要在后面加上[]
。
如果你想要返回完整的物体路径,使用ls()
还需要添加long
参数,使用listRelatives()
则要使用fullPath
参数。
minq是一个简化查询过程的这么一个库,例:
1 | q = Scene(['top']) |
它将返回一个minq.Stream
对象。不过它不是最终的查询结果,你需要调用.execute()
函数来将它转换成列表:
1 | print q.execute() |
你也可以直接进行迭代:
1 | q = Scene(['top', 'front']) |
通常也可以直接把它们变成一个元组或列表:
1 | tuple(Cameras()) |
当然也可以使用一些关键字,如in
,any
和all
:
1 | u'|top' in Cameras() |
关联式查询
在minq中,minq.Stream
对象可以使用一些表达式进行关联式查询,下面是一些例子:
1 | Meshes() # 获取所有polyMesh节点 |
通常我们要实现上述的需求,可能要用到这样的代码:
1 | results = [] |
和普通的查询一样,关联式查询也可以使用execute()
函数,或直接进行迭代:
1 | cubes = Meshes().get(Parents).like('cube') |
再次声明,minq的查询结果不是一个列表,而是一个可迭代的对象。
通常我们看到查询链中的最后一个关键字决定了查询结果:
1 | Selected().only(Transforms) |
刚刚的代码可以返回所有选择的Transforms节点。我们也可以使用append()
方法将其它的对象加入进去:
1 | Selected().only(Transforms).append(AllChildren) |
对于更复杂的查询组合,你还可以使用集合操作。
比如当我们想用一个或多个已知名称的对象开始查询,using()
函数会用你提供的名称来创建Stream
对象。
1 | using("character_root").get(AllChidren).only(IKHandles) |
这将会返回在character_root下的所有ik手柄。using()
函数可以放入多个名称。
过滤
绝大多数的查询都会通过过滤的方式来缩减实际需要的结果。在minq中主要有以下三种方式:
.like()
.only()
.where()
.like()
这个方法是一个正则表达式过滤器,默认返回包含传入字符的对象,不区分大小写。
1 | print Cameras() |
如果你需要更精确的匹配,可以加入关键字exact
。
1 | print Cameras().like('top', exact=True) |
其次,like()
也可以使用完整的表达式。
1 | print Joints().like('Left(hand|foot)$') |
.only()
这个方法是过滤Stream
对象的结果类型。
常见的用法是这样:
1 | some_stream.only('camera','light') |
这将会从某个Stream
中过滤出摄像机和灯光的对象。
minq为我们设置好了许多类型相关的关键字,所以还有种写法是:
1 | some_stream.only(Meshes, Cameras) |
only()
还可以使用参数来指定命名空间进行查询:
1 | Transforms().only(namespace = 'test') |
使用冒号:
来精确的匹配命名空间:
1 | ransforms().only(namespace=':test') |
命名空间也可以与过滤类型进行组合:
1 | DagNodes().only('skinClusters', namespace="export") |
.where()
这个方法是可以添加一个函数对每个物体对象进行过滤。
比如下面的一个情况:
1 | # get all the meshes whose translateX is larger than 50 |
.where()
接受一个函数作为参数,它会将左边所有Steam里的元素作为参数,过滤出结果返回为True的对象。
1 | tx_over_fifty = lambda p: cmds.getAttr(p + ".tx") > 50 |
它还可以简单的写作:
1 | Meshes().where(item.tx > 50) # item是minq的特殊类,代表左侧Steam中每个元素 |
你也可以利用.where()
的特性,找到所有被连接的节点:
1 | Scene().where(cmds.listConnections) |
特殊类item
还可以简单的对父级,子级,关联关系,历史进行查询。
比如item.has()
方法:
1 | # 找到所有含有子级的Transforms节点 |
与之相似的还有item.has_attr()
方法,判断每个元素是否存在某个属性。
1 | has_tx = Transforms().where(item.has_attr('tx')) |
.having()
.having()
方法同样是判断某个属性是否存在。
比如找到所有带有”exportable”属性的Transforms节点:
1 | export_set = Transforms().having('exportable') |
相较于
.has_attr()
,.having()
的效率会快一些。
扩展
使用minq得到一个列表后,可以使用.get()
对结果进行转换。
1 | # 将结果转换为其transform节点 |
还有一些.get()
无法获取到物体的名称,比如:
1 | mesh_translates = Meshes().get(Parents).get(Attribute, 't').get(Values) |
你可以使用foreach()
对Stream结果里每个结果执行一个自定义的函数操作:
1 | print Cameras().short().foreach(lambda p: p.upper()) |
foreach()
也可以用作复杂过滤的转换:
1 | def connected_shaders(object): |
制表显示
minq支持对结果进行制表显示,需要用到.join()
方法。
下面的例子制表显示所有模型和对应的材质。
1 | mesh_stream = Meshes() |
从上述输出的结果来看,返回的列表里的元素是具名元组。所以我们也可以将它转换成字典:
1 | meshes, shaders = Meshes().split(2) |
上面的例子没有进行过优化,mesh_stream
和shader_stream
会重复的执行Meshes()
查询。在对性能有要求的情况下,可以使用.split()
函数将Stream结果复制分成两份。
1 | meshes, shaders = Meshes().split(2) |
打组
时常会将Stream的结果根据需要进行打组分类。
比如根据面数对模型分类:
1 | def poly_category(obj): |
对于Stream结果中包含dataRows
元素的,你可以使用行列数进行分类,而不要使用分组函数。
集合的操作
查询可以像集合一样操作。
比如对两个结果相加:
1 | cube_parents = nodes().of_type('polyCube').parents |
同样,你需要使用.execute()
将其转换成列表。
1 | q = Cameras() # all cameras |