3dsmax插件开发新手上路
点击可看原帖地址
[原创]3dsmax插件开发新手上路
作者:老狼
email: cgwolver@163.com
QQ:4197680024
我尽量把话题说的通俗易懂一点,因为要做插件的可能不只是程序员:)
所谓插件,其实就是动态链接库,windows 系统上就是dll,打开Autodesk\3ds Max 9\stdplugs文件夹,会看到下面一大堆扩展名叫dlu,dlo,等等的文件。其实这都是dll改的名字,本质还是dll。当宿主程序运行起来的时候,会加载这个文件夹下的所有dlxx扩展名的文件。因此你可以用任何创建dll的方法来生成它,比如用Win32 DLL Project,或者MFC DLL Project;我本人更喜欢用MFC DLL Project,可以方便的用MFC的功能;在3dsmax插件中使用MFC DLL Project ,有一些需要注意的问题,将在后文叙述.
如果你想快速写插件,通常使用 maxsdk提供的 vc wizard 最容易创建一个特定的插件框架程序.这里简单说一下设置 3dsmax vc wizard 的方法:
安装了3dsmax product以后,还要安装maxsdk,sdk和大量的sample在dvd完整安装版本上,PluginWizard 的路径在Autodesk\3ds Max 2009 SDK\maxsdk\howto\3dsmaxPluginWizard下面,里面有readme.txt文件,大意是这样的:用文本编辑器打开3dsmaxPluginWizard.vsz,我装的是3dsmax2009,打开这个vsz文件的内容如下:
VSWIZARD 7.0
Wizard=VsWizard.VsWizardEngine.8.0
Param="WIZARD_NAME = 3dsmaxPluginWizard"
Param="ABSOLUTE_PATH = C:\dev\p4\gouda\3dswin\src\maxsdk\howto\3dsmaxPluginWizard"
Param="FALLBACK_LCID = 1033"
把ABSOLUTE_PATH 的路径改为 D:\Autodesk\3ds Max 2009 SDK\maxsdk\howto\3dsmaxPluginWizard,就是你复制文件的原路径
这个时候用VC8 新建 Project ,选择VC++,会看到一个 3ds max plugin Wizard 列表项,然后按照提示一步一步操作就能创建一个基本的插件框架.
这里我要多说一点的是用自定义dll project方法创建3dsmax plugins的方法,我本人不太喜欢用现成的东西,凡事总喜欢自己亲手做来的东西,这样理解的也比较深刻透彻
3dsmax插件,有几个标准的可导出函数,3dsmax.exe装载插件时,用GetProcAddress API找出预定的几个标准接口,然后调用一个LibClassDesc的接口,创建出用户自定义的对象实例,类似于"抽象厂"方法
3dsmax 插件中必须定义的标准导出函数:
#define DLLEXPORT_API __declspec(dllexport)
//插件描述
DLLEXPORT_API const TCHAR* LibDescription()
{
LoadString( IDS_LIBDESCRIPTION );
}
//这个dll中有几个插件
DLLEXPORT_API int LibNumberClasses()
{
return 1;
}
//取得插件描述块,3dsmax.exe用它来创建你的插件类的实例
DLLEXPORT_API ClassDesc* LibClassDesc(int i)
{
switch(i)
{
case 0: return GetMyClassDesc();
default: return 0;
}
}
//LibVersion用来匹配插件和宿主3dsmax.exe之间的版本匹配问题.
DLLEXPORT_API ULONG LibVersion()
{
return VERSION_3DSMAX;
}
关于如何在VC中创建DLL Project,不需要多说了,要说的一点就是导出函数必须用 _declspec(dllexport) 修饰,另外还需要在def文件中列出导出函数的名字如下:
假定一个导出插件的文件名是SampleExporter
//SampleExporter.def
LIBRARY SampleExporter
EXPORTS
LibDescription @1
LibNumberClasses @2
LibClassDesc @3
LibVersion @4
SECTIONS
.data READ WRITE
下面着重说GetMyClassDesc() 这个函数...
#define SampleExporter_CLASS_ID Class_ID(0xc2a1ee34, 0x832cc295) //这个Class_ID用Autodesk\3ds Max 2009 SDK\maxsdk\help\getcid.exe 自己生成,只要不存在冲突就可以.
//SampleExporter 是从SceneExport 继承的导出插件类,SceneExport是sdk预定义的用于实现导出插件的基类,用户写导出插件,只需要继承它,然后实现相应的纯虚接口即可.
//导入插件基于SceneExport,辅助插件基于UtilityObj,还有创建面板上的,详见3ds Max SDK Programmer'sGuide中的Type of Plug-Ins 介绍.
//函数DoExport是3dsmax.exe和导出插件程序交互的主要接口,选择File/Export菜单,然后选择SampleExporter后,将会进入DoExport函数...
class SampleExporter : public SceneExport {
public:
static HWND hParams;
int ExtCount(); // Number of extensions supported
const TCHAR * Ext(int n); // Extension #n (i.e. "3DS")
const TCHAR * LongDesc(); // Long ASCII description (i.e. "Autodesk 3D Studio File")
const TCHAR * ShortDesc(); // Short ASCII description (i.e. "3D Studio")
const TCHAR * AuthorName(); // ASCII Author name
const TCHAR * CopyrightMessage(); // ASCII Copyright message
const TCHAR * OtherMessage1(); // Other message #1
const TCHAR * OtherMessage2(); // Other message #2
unsigned int Version(); // Version number * 100 (i.e. v3.01 = 301)
void ShowAbout(HWND hWnd); // Show DLL's "About..." box
BOOL SupportsOptions(int ext, DWORD options);
int DoExport(const TCHAR *name,ExpInterface *ei,Interface *i, BOOL suppressPrompts=FALSE, DWORD options=0);
//Constructor/Destructor
SampleExporter ();
~SampleExporter ();
};
//3dsmax.exe如何与用户自定义的插件建立起联系,就是通过下面这个ClassDesc类来获得创建插件对象实例所需要的必要的信息
class SampleExporterClassDesc: public ClassDesc2
{
public:
virtual int IsPublic() { return TRUE; }
virtual void* Create(BOOL /*loading = FALSE*/) { return new SampleExporter (); }//这里其实就是"抽象厂"方法,让用户提供一个实例
virtual const TCHAR * ClassName() { return GetString(IDS_CLASS_NAME); }
virtual SClass_ID SuperClassID() { return SCENE_EXPORT_CLASS_ID; }
virtual Class_ID ClassID() { return SampleExporter_CLASS_ID; }
virtual const TCHAR* Category() { return GetString(IDS_CATEGORY); }
virtual const TCHAR* InternalName() { return _T("SampleExporter"); } // returns fixed parsable name (scripter-visible name)
virtual HINSTANCE HInstance() { return hInstance; } // returns owning module handle
};
static SampleExporterClassDesc expoertDesc;
ClassDesc2* GetMyClassDesc() { return &expoertDesc; }
//下面是SampleExporter类的实现代码
SampleExporter::SampleExporter()
{
}
SampleExporter::~SampleExporter()
{
}
int SampleExporter::ExtCount()
{
#pragma message(TODO("Returns the number of file name extensions supported by the plug-in."))
return 1;
}
const TCHAR *SampleExporter::Ext(int n)
{
#pragma message(TODO("Return the 'i-th' file name extension (i.e. \"3DS\")."))
return _T("");
}
const TCHAR *SampleExporter::LongDesc()
{
#pragma message(TODO("Return long ASCII description (i.e. \"Targa 2.0 Image File\")"))
return _T("");
}
const TCHAR *SampleExporter::ShortDesc()
{
#pragma message(TODO("Return short ASCII description (i.e. \"Targa\")"))
return _T("");
}
const TCHAR *SampleExporter::AuthorName()
{
#pragma message(TODO("Return ASCII Author name"))
return _T("");
}
const TCHAR *SampleExporter::CopyrightMessage()
{
#pragma message(TODO("Return ASCII Copyright message"))
return _T("");
}
const TCHAR *SampleExporter::OtherMessage1()
{
//TODO: Return Other message #1 if any
return _T("");
}
const TCHAR *SampleExporter::OtherMessage2()
{
//TODO: Return other message #2 in any
return _T("");
}
unsigned int SampleExporter::Version()
{
#pragma message(TODO("Return Version number * 100 (i.e. v3.01 = 301)"))
return 100;
}
void SampleExporter::ShowAbout(HWND hWnd)
{
// Optional
}
BOOL SampleExporter::SupportsOptions(int ext, DWORD options)
{
#pragma message(TODO("Decide which options to support. Simply return true for each option supported by each Extension the exporter supports."))
return TRUE;
}
//这里是真正的导出函数入口,用户选择导出后,将执行到这里
int SampleExporter::DoExport(const TCHAR *name,ExpInterface *ei,Interface *i, BOOL suppressPrompts, DWORD options)
{
#pragma message(TODO("Implement the actual file Export here and"))
if(!suppressPrompts)
DialogBoxParam(hInstance,
MAKEINTRESOURCE(IDD_PANEL),
GetActiveWindow(),
maxProject1OptionsDlgProc, (LPARAM)this);
#pragma message(TODO("return TRUE If the file is exported properly"))
return FALSE;
}
至此一个基本的插件程序框架就搭建起来了,剩下的就是要遍历场景节点,实现你自己的数据导出功能了
(完)
3dsmax插件开发新手上路相关推荐
- Windows内核新手上路1——挂钩SSDT
Windows内核新手上路1--挂钩SSDT 这个系列记录学习我学习windows内核的点点滴滴,高手请直接无视. 文章核心内容:挂钩SSDT中函数列NtOpenProcess,NtDuplicate ...
- Windows内核新手上路3——挂钩KeUserModeCallBack
Windows内核新手上路3--挂钩KeUserModeCallBack 1. 简介 在Windows系统中,提供了几种方式从R0调用位于R3的函数,其中一种方式是KeUserModeCall ...
- Windows内核新手上路2——挂钩shadow SSDT
Windows内核新手上路2--挂钩shadow SSDT 文章核心内容:安全软件窗口保护.安全输入.截屏保护的一些思路.挂钩NtUserFindWindowEx.NtUserGetForegroun ...
- Linux新手上路命令
Linux新手上路命令 命令:www.ahlinux.com Ctrl+Alt+F1 进入命令界面 Ctrl+Alt+F7 返回图形界面 root用户和普通用户切换 administrator 2 ...
- 千寻和省cors精度对比_测量员新手上路攻略:解析省CORS和千寻CORS账号区别及其如何选择运用...
原标题:测量员新手上路攻略:解析省CORS和千寻CORS账号区别及其如何选择运用 说到CORS.CORS账号,想必大家都不陌生,CORS-连续运行卫星定位服务系统,现在多代指网络RTK,是在传统RTK ...
- python必备基础代码-新手上路必学的Python函数基础知识,全在这里了(多段代码举例)...
原标题:新手上路必学的Python函数基础知识,全在这里了(多段代码举例) 导读:函数是Python中最重要.最基础的代码组织和代码复用方式.根据经验,如果你需要多次重复相同或类似的代码,就非常值得写 ...
- 软件项目经理新手上路16 - 后记,一切才刚刚开始
如果你内向,同时觉得自己够聪明,就去做软件开发人员吧.这是我当时为什么从事软件行业的原因.而且,我发现不是我一个人这么想,中国内向的聪明人实在是太多了.这些人都认为,相对于面对人而言,他们更善于面对电 ...
- 固定字符结尾的正则_新手上路:图文解读助你理解和使用正则表达式
选自janmeppe.com 作者:Jan Meppe 机器之心编译 参与:韩放.杜伟 这篇博客是关于正则表达式(regex)的插图指南,旨在为那些从来没有使用过正则表达式,想尝试但又望而生畏的新手提 ...
- HanLP《自然语言处理入门》笔记--1.新手上路
文章目录 1. 新手上路 1.1 自然语言与编程语言的比较 1.2 自然语言处理的层次 1.3 自然语言处理的流派 1.4 机器学习 1.5 语料库 1.6 开源工具 1.7 总结 1.8 GitHu ...
最新文章
- Tensorflow【实战Google深度学习框架】—完整的TensorFlow入门教程
- php 新闻列表,php原生开发新闻站之新闻列表(二)
- php haystack,haystack(示例代码)
- Default process group has not been initialized, please make sure to call init_process_group
- linux cut 命令详解
- 对口本科计算机专业,对口高考计算机类专业综合试题(卷).doc
- miui linux桌面图标,小米主题编辑器(miui主题编辑工具)下载了最新的正式版v5.3.23...
- 研发/项目计划管理表格
- iPadOS、iOS13降级iOS12.3.1方法
- PX4 mixer load
- 光照 (4) 漫反射光照
- c语言kill暂停和恢复进程,Linux暂停和恢复进程
- SpringMVC 配置定时执行任务
- Python小课们是如何赚钱的
- 免费文本转语音(在线文本转语音)
- 任正非:为什么华为选择与西工大合作,而没选清华北大
- 基于 MaxCompute+PAI 的用户增长方案实践
- 直播、录播、录视频等
- 本地创建git仓库并提交到码云
- mmc驱动框架基础介绍
热门文章
- TypeScript创建泛型类报错(泛型类)
- 人工神经网络反向传播,神经网络后向传播
- 网传分享的Wordpressripro主题4.8版本后门分析_盾给网下载修复文件[建站教程]
- 物流中转站---最短距离和
- 大学生数学竞赛教程【蒲和平】
- 论文写作课程心得和总结
- Element-UI中调用tinymce6实现本地化加载,并解决提示:This domain is not registered with TinyMCE Cloud,省去api-key
- 收集的卡通动漫模型手办之01
- 侠盗猎车手:圣安地列斯作弊码
- English语法_地点副词