现在的位置: 首页 > 综合 > 正文

3DS Max 插件制作学习心得 1

2013年10月05日 ⁄ 综合 ⁄ 共 4018字 ⁄ 字号 评论关闭

             要从3ds Max中导出场景信息,大概有两种方式:1.利用3ds Max的sdk制作插件。2.利用3ds Max的Max Script编写场景输出脚本。两种方式各有优劣,这里仅叙述我用了数天研究3ds Max SDK并制作插件的学习心得。

        1.前期环境配置工作。

       首先肯定要安装带SDK的3ds Max,我安装的是3ds Max7。安装后在maxsdk/help下有个sdkapwz.zip,把这个文件解压到VS 6.0或VS 2003的application wizard路径下,启动VS就会有3ds Max plug-in的应用程序向导来生成插件程序的框架。

       2.制作插件需要了解的几个基本概念。

       2.1 我所了解的插件原理是:3ds Max会公布一些接口,插件制作者需要做的是实现这些接口。例如利用向导生成一个用于场景导出的插件。就会发现在生成的程序中有一个类继承于class SceneExport,而 SDK 中关于这个接口的描述是:

       This is a base class for creating file export plug-ins. The plug-in implements methods of this class  to describe the properties of the export plug-in and a method that handles the actual export  process. 

       再看下面的函数说明,可以看到函数是虚函数的方式声明的,所以必须要将其所有的函数进行实现。

       2.2 3ds Max是怎样识别插件的接口?还是以上面的场景到处插件为例,程序中还会生成一个继承于 ClassDesc2的类,这个类会实现一些关于类的ID,层次信息处理的函数。估计系统就是根据这个识别处我的插件的接口,没有具体去研究,只了解个大概。

       2.3 如何调试所编写的插件,SDK中有说明,我这里简单说一下,将工程属性设置为Hybrid(默认是Debug),并且把输出dle文件的路径设为3ds Max的plug-in的路径,再把调试的可执行程序设为3ds Max.exe,这样 调试的时候就会启动3ds Max主程序,其他诸如设置断点,单步等调试手段和普通程序的调试方法一样。

       3.通过一个例子学习插件编程。 

    这部分还真不好写,涉及到一些代码,代码中又有很多API需要讲解,API中又有很多基本知识需要说明,唉,硬着头皮来吧。

       还是以那个场景导出类为例,可以看到,SceneExport中有个非常重要的函数需要实现:

       virtual int DoExport(const TCHAR *name,ExpInterface *ei,Interface *i,
       BOOL suppressPrompts=FALSE, DWORD options=0) = 0;

       先看看参数:

      name 表示要导出的文件名。

      ei 用来枚举场景,需要注意的是:由于这个函数是由系统调用的,所以这个参数是系统传递的,不      用去思考怎么实现ExpInterface这个接口。

      i 提供一个用来调用3ds Max方法的指针,可以把它视作一个指向3ds Max的指针。同样,这个指针      也是由系统传递的。

      剩下两个参数暂不关心。

      现在来研究eii两个参数:

      class ExpInterface仅包含一个成员:IScene *theScene。这样的类设计的简直是无耻。再去研究IScene吧。IScene中有一个很重要的函数:

virtual int EnumTree( ITreeEnumProc *proc )=0;

       根据SDK的说明,该函数的功能是:用来枚举场景中的每个INode。因此需要一个ItreeEnumProc*作为参数,由于是自己调用整个函数,因而必须自己实现ItreeEnumProc接口,还好这个接口不是很复杂,把这个回调函数实现就可以了:

        virtual int callback( INode *node )=0;

    因为是回调函数,所以node也是系统传递进来的,为了证明这一点,我们可以编程实验一下:

class MyEnumProc: public ITreeEnumProc
{
publicint callback( INode *node )
    
{
             
int a = 0;//在这里设置断点
             return a; 
        }

}


在MyExport中添加这一个成员变量:
MyEnumProc MyProc;

int    MyExport::DoExport(const TCHAR *name,ExpInterface *ei,Interface *i, BOOL suppressPrompts, DWORD options)
{
        
/*在函数中添加这行代码*/
    ei
->theScene->EnumTree(&this->MyProc );

    
if(!suppressPrompts)
        DialogBoxParam(hInstance, 
                MAKEINTRESOURCE(IDD_PANEL), 
                GetActiveWindow(), 
                MY5OptionsDlgProc, (LPARAM)
this);
    
return FALSE;
}

     调试这个例子,在场景中绘制三个立方体,可以看到系统会调用callback三次,这说明一个物体就是一个Node。那么怎么来导出一个Node几何信息呢?看下面这个代码。

publicint callback( INode *node )
{
    Object 
*lobj;
    lobj 
= node->GetObjectRef();
    
if (lobj->SuperClassID()== GEOMOBJECT_CLASS_ID)
    
{
        GeomObject
* gobj = (GeomObject*)lobj;
        Class_ID triID 
= Class_ID(TRIOBJ_CLASS_ID,0);
        Class_ID boxID 
= Class_ID(BOXOBJ_CLASS_ID,0);      
        
if (lobj->ClassID()==boxID)
        
{
            
if (lobj->CanConvertToType(triID))
            
{

                TriObject *triobj = (TriObject *)lobj->ConvertToType
                    (
0,triID);
                Mesh mesh 
= triobj->mesh;
                
int numVerts = mesh.getNumVerts();
            }


            IParamArray
* array = lobj->GetParamBlock();
            
float length = 0.0f;
            
float height = 0.0f;
            
float width = 0.0f;
                
           array
->GetValue( lobj->GetParamBlockIndex(BOXOBJ_LENGTH),
                0
, length, FOREVER);
           array
->GetValue( lobj->GetParamBlockIndex(BOXOBJ_HEIGHT),
               
0, height, FOREVER);
           array
->GetValue( lobj->GetParamBlockIndex(BOXOBJ_WIDTH),
               
0, width, FOREVER);
        }

}

   

首先node->GetObjectRef()会返回这个节点的物体引用。关于ObjectRef有一套几何流水线的说明,这里实在是没功夫写了。接着首先判断这物体的SuperClassID是否为GEOMOBJECT_CLAS- S_ID,如果是,则再看它是否能转换为TriObject,即由三角形组成的物体,至于为什么要这样转,我只能说只有这个类可以返回一个Mesh,而通 Mesh能够获得诸如顶点,法线,面等一般3D程序所需要的几何信息(这里只获取了该Mesh的面的个数)。当然,对于一个Box,我们可能只想获得它 的长宽高,所以,代码中又提供了另一个方法来返回其几何信息。

      虽然只实现了这么短的代码,但却花了数天的时间,主要对3ds Max的结构不熟悉,加上SDK写得真叫一个乱,还好总算有些进展,正所谓万事开头难。下一步将研究如何导出场景的光照,物体的纹理贴图等信息。

      这里介绍几个网站,感谢它们对我提供的帮助:

      http://www.cgsir.com
      http://discussion.autodesk.com/index.jspa
      也希望看到这篇文章的人能够给予指正,毕竟我是刚开始学3ds Max plug-in.


         

抱歉!评论已关闭.