前言:
原本目的是想寻求一种方式来对cpu计算密集型代码部分进行加速替代,但是maya中mll插件的插件套路在传递参数上会占用大量的io,对于数据比较大的部分也会有相当消耗。如果全部写在c++部分又感觉缺乏灵活性,所以琢磨的一种可以在python中实现逻辑,pyd中实现算法的方式。
问题:
纯python api来编译pyd的计算模块会有大量的数据转换,比如获取模型所有的顶点会得到MFloatPointArray,获取所有SkinMesh的蒙皮权重会得到MDoubleArray,这些数据直接获取都很快,但是要把他们转换成python api所支持的数据格式就很麻烦,计算完成后还要转换回来,一旦模型面熟很高很耗费时间。作为一个懒人不能忍~
思路:
maya api 1.0使用swig做封装,借助swig解封PyObject指针的功能自动将python指针对象转换成maya内置的M数据类型。
流程:
- 下载swig,解压到本地,路径添加到添加到环境变量中
- 创建一个空的vs工程
3. 添加一个文件compute.h,我们所有的代码都放这个头文件里面
4. 针对所有平台,设置一下vs工程,方便代码提示
输出格式
包含目录,库目录
依赖库,只用基本的数据类型
输出文件(带下划线,下面有解释)
随便写一个累加的测试函数
// compute.h#pragma once
#include <maya/MIntArray.h>int testMIntArray(MIntArray input)
{int sum = 0;for (int i = 0; i < input.length(); i++){sum += input[i];}return sum;
}
编写swig的compute.i
%module TestMayaApi%{
#include "compute.h"
%}%include "compute.h"
添加到工程,设置一下生成事件,每次编译之前先生成包裹函数
接下来编译就可以了
maya中测试:
import sys
sys.path.append('F:/swig_maya_test/swig_maya_test')
import TestMayaApiimport maya.OpenMaya as om
iList=om.MIntArray()
for i in range(100):iList.append(i)print TestMayaApi.testMIntArray(iList)
优化:
swig会生成两个文件py和pyd的,py是模块名,pyd是_模块名,要不然导入python模块会失败,要把pyd模块名的修改成TestMayaApi,只修改工程设置里面的输出文件是不行的,导入会报错,需要修改源码,这样我们只需要pyd就可以了。
- 先将输出文件修改
2. 禁用生成事件,改为手动运行cmd
3. 将swig生成的compute_wrap.cxx添加进来,搜索替换模块名
每次运行swig都要重新生成替换。
重新生成后我们就不需要.py文件了,直接删掉,只保留TestMayaApi.pyd
返回值的坑:
c++函数不能直接返回maya内置类型,如果函数定义成这样,python中接受到的返回值是swig object指针,传递给其它python api时会出错
MIntArray testMIntArray(MIntArray input)
解决办法:
将参数传递改成引用类型,这样就可以直接修改数据,不用返回,和api 1.0大多数做法一致
void testMIntArrayMul(MIntArray input,int mul, MIntArray& output)
{output.setLength(input.length());for (int i = 0; i < input.length(); i++){output[i] = input[i] * mul;}
}
maya测试代码
import sys
sys.path.append('F:/swig_maya_test/swig_maya_test')
import TestMayaApiimport maya.OpenMaya as om
iList=om.MIntArray()
for i in range(100):iList.append(i)outList=om.MIntArray()
TestMayaApi.testMIntArrayMul(iList,2,outList)
print outList
总结:
算是maya plugin和python api的之外的一种计算模块的方式,编译之后maya 2016以下版本可以共用一个pyd,其它版本可能要单独编译,没测试很全。好处就是用起来更舒服,不用转换数据,和python api无缝衔接,可以直接用MxxxArray,并且支持OpenMP多线程计算。