我们在上一节 Maya插件开发笔记(1) 开发环境搭建中搭建好了开发环境,现在我们需要使用CMake来创建一个VisualStudio项目来进行插件代码开发。

首先需要安装CMake,安装好之后进行后续的步骤,这里省略CMake安装步骤。

这里我们跟着官方文档的示例操作一遍:
首先切换到你的 C:\Users\Administrator\devkitBase\plug-ins\plug-ins\ 文件夹下面,然后
然后在这里创建CMakeList.txt,输入以下内容:

cmake_minimum_required(VERSION 3.22.1)

set(PROJECT_NAME helloWorld)
project(${PROJECT_NAME})

include($ENV{DEVKIT_LOCATION}/cmake/pluginEntry.cmake)

set(SOURCE_FILES
    helloWorld.cpp
)

set(LIBRARIES
    OpenMaya Foundation
)

build_plugin()

然后创建一个helloWorld.cpp,输入以下内容

#include <stdio.h>
#include <maya/MString.h>
#include <maya/MArgList.h>
#include <maya/MFnPlugin.h>
#include <maya/MPxCommand.h>
#include <maya/MIOStream.h>

class helloWorld : public MPxCommand
{
    public:
        MStatus doIt( const MArgList& args );
        static void* creator();
};

MStatus helloWorld::doIt( const MArgList& args ) {
    cout << "Hello World " << args.asString( 0 ).asChar() << endl;
    return MS::kSuccess;
}

void* helloWorld::creator() {
    return new helloWorld;
}

MStatus initializePlugin( MObject obj ) {
    MFnPlugin plugin( obj, "Autodesk", "1.0", "Any" );
    plugin.registerCommand( "HelloWorld", helloWorld::creator );
    return MS::kSuccess;
}

MStatus uninitializePlugin( MObject obj ) {
    MFnPlugin plugin( obj );
    plugin.deregisterCommand( "HelloWorld" );
    return MS::kSuccess;
}

然后打开CMD命令控制台,切换到这个目录,运行这个命令:

cmake . -Bbuild -G "Visual Studio 17 2022"

这里参数的含义简单说明一下,官网提供的示例命令是cmake -H. -Bbuild -G "Visual Studio 17 2022"在我下载的CMake3.28.1上面不管用,测试了几次才发现-H已经不是设置目录了,而是和--help一样的效果,这说明Maya官方的文档已经很久没更新了,所以我又摸索出来了上面正确的命令。

其中cmake后面的 . 代表当前目录, -B代表构建目录的名称,后面可以紧跟着也可以空格隔开你指定的构建目录的名称,这里我们指定的是build-G选项用于指定生成器(Generator)或构建系统的名称,这里指的是使用VisualStudio构建,C++标准为C++17,版本号为Visual Studio 2022版本。

运行后会在当前目录下生成一个build目录,目录下面就是一个VisualStudio项目。
在这里插入图片描述
现在我们就可以打开这个helloWorld.sln进行编译了。
切换到Release X64,进行编译
在这里插入图片描述
编译完成后目录下出现Release目录,下面有个.mll文件,这就是编译好的插件
在这里插入图片描述
(当然你选Debug也行,只不过出来的文件是在Debug目录下面,不要死按步骤来,灵活学习这个过程的本质)

然后接下来进入Maya,使用Plug-in Manager插件管理器)导入插件,或者把插件复制到plug-ins目录下面。
原理就是maya运行时会自动加载你之前设置好的plug-ins目录下面的插件,如果不直接放在plug-ins目录下,那就加载不到,这里因为我们是在嵌套的buildRelease下面,所以无法直接读取到,所以得手动加载。

这里我们选择 窗口=>设置/首选项=>插件管理器
在这里插入图片描述
可以看到它并没有在我们上一节设置的环境变量那个plug-ins目录里读取到任何插件
在这里插入图片描述
然后我们点击浏览,选中这个插件的路径,然后点击打开
在这里插入图片描述
加载后是酱紫的,通过浏览手动加载的插件不会在Maya启动时自动加载,而是需要你每次启动Maya都手动加载,所以这里我们可以勾选上自动加载,这样这个插件就会在Maya每次启动时进行加载了。
在这里插入图片描述
这个界面自动加载后面有个 圆圈 i ,点它就会出现一个窗口显示这个插件的信息:
在这里插入图片描述
这里要注意,插件有个选项叫适用于API版本,Maya这种工业软件API会经常改变,所以每次有新版本,你都需要更新你的插件来支持Maya的新版本,不管怎么说还是比Blender这种频繁更新版本换API的要稳定一点,一般公司里用的话,一两个特定版本就能用到项目组解散或者公司倒闭,所以一般情况不需要担心这一点,除非你做的是对外开放的商业插件,那几乎每个新版本都要去测试、重构支持。

到这里,这个Maya插件就加载到项目里面了,然后我们来使用它一下试试。
打开Maya命令行,也就是脚本编辑器,一般在右下角
在这里插入图片描述
可以看到,运行完成后这里显示了HelloWorld,这说明我们运行成功了。

在这里插入图片描述
(这里之所以用HelloWorld 命令进行测试,是因为我们这里代码注册的命令就叫HelloWorld)
在这里插入图片描述

好了,到这里我们就走通了基本的配置环境,构建项目,编译项目,加载插件,测试插件的整个流程了,如果有条件的话可以跟着步骤测试一遍,基本上就能掌握这些基础了。

接下来我们来看一下这个最简单的helloWorld.cpp里的代码,它虽然简单,但是里面包含了几个我们第一次学习Maya插件开发必须了解的概念。

首先就是doIt()函数,它的作用是解析传递过来的参数列表,然后把它输出到Maya的output窗口。

MStatus helloWorld::doIt( const MArgList& args ) {
    cout << "Hello World " << args.asString( 0 ).asChar() << endl;
    return MS::kSuccess;
}

MArgList 会收集传递过来的参数并把它们放到一个列表里,它就和C++的main方法里接收的argcargv的概念比较类似,就是纯用来接收参数的这么一个数据类型。
asString()会把参数列表转换为一个MString对象,然后asChar()MString又转换为C++的char *类型,这样才能交给cout进行输出。

Maya的官方文档提到,在更加复杂的插件里,doIt()的作用一般是解析参数,设置内部变量的值,或者做其他准备性的工作,doIt()会在调用redoIt()之前完成这些工作,然后redoIt()才是真正调用command命令的地方。

可能突然又出现个redoIt()你不知道这是干嘛的,这里就不得不提到Maya的设计了,如果你设计的这个插件的这个命令是可以被撤销的,那doIt()里只能放准备工作的代码,真正执行命令的代码要放到redoIt(),然后你还得额外提供一个undoIt()来撤销redoIt()里干的事情,这个就是Maya的一种设计规范,还是有点麻烦的不如Blender封装的好,不过更低的粒度意味着我们有更多的空间来开发出更强大的插件,所以其实是好事儿。。

当然,如果你的插件提供的命令是不可撤销的,那就不用实现redoIt()undoIt()了,比如只是简单的打印几个字符串输出之类的,但是大部分对数据对象的操作我们都需要提供可以撤销的命令,不然不小心用错了没法撤销是很严重的事情。

接下来看插件的命令,插件的命令是使用creator()来实例化的。

void* helloWorld::creator() {
    return new helloWorld;
}

然后是初始化插件和取消插件的初始化

MStatus initializePlugin( MObject obj ) {
    MFnPlugin plugin( obj, "Autodesk", "1.0", "Any" );
    plugin.registerCommand( "HelloWorld", helloWorld::creator );
    return MS::kSuccess;
}

MStatus uninitializePlugin( MObject obj ) {
    MFnPlugin plugin( obj );
    plugin.deregisterCommand( "HelloWorld" );
    return MS::kSuccess;
}

所有的Maya插件都需要实现initializePlugin()uninitializePlugin()函数,如果initializePlugin()函数运行失败了,则整个插件都无法成功加载,initializePlugin()函数里会调用registerCommand()来注册一个新的命令,uninitializePlugin()函数会调用deregisterCommand()来取消一个命令的注册。

可以说initializePlugin()uninitializePlugin()函数就是Maya插件的入口点,initializePlugin()函数一般会注册比如命令,节点,工具,以及其它额外的东西,uninitializePlugin()函数则是在插件卸载的时候要执行的操作,他会把插件在加载时注册的东西全部取消注册一遍。

对于一个命令类插件,initializePlugin()必须得调用registerCommand()uninitializePlugin()函数必须得调用deregisterCommand()
对于一个依赖节点类型插件(dependency node),initializePlugin()必须调用registerNode()来注册命令,同样,uninitializePlugin()函数必须得调用deregisterNode()

因为initializePlugin()uninitializePlugin()函数就是Maya插件的入口点,所以如果你的Maya插件代码里不提供这俩函数的话,基本上插件是无法被Maya加载的。

好了,到这里基本上你就能编译出一个最简单的Maya插件来进行测试了,当你整个流程测试通过,并且理解了Maya插件的入口点initializePlugin()uninitializePlugin()函数的设计之后,我们就可以开始后面的学习了,后面的内容可能会记录Maya一些基础API的用法,或者是一些效果的实现案例。

本节内容就到此结束,希望能对你有所帮助。

Logo

技术共进,成长同行——讯飞AI开发者社区

更多推荐