<?xml version="1.0" encoding="utf-8"?><?xml-stylesheet type='text/xsl' href='http://flipcode.spaces.live.com/mmm2008-05-17_13.22/rsspretty.aspx?rssquery=en-US;http%3a%2f%2fflipcode.spaces.live.com%2fcategory%2f%e6%8f%92%e4%bb%b6%e7%bc%96%e7%a8%8b%2ffeed.rss' version='1.0'?><rss version="2.0" xmlns:slash="http://purl.org/rss/1.0/modules/slash/" xmlns:msn="http://schemas.microsoft.com/msn/spaces/2005/rss" xmlns:live="http://schemas.microsoft.com/live/spaces/2006/rss" xmlns:dcterms="http://purl.org/dc/terms/" xmlns:cf="http://www.microsoft.com/schemas/rss/core/2005" xmlns:wfw="http://wellformedweb.org/CommentAPI/"><channel><title>飘零风雨亭: 插件编程</title><description /><link>http://flipcode.spaces.live.com/?_c11_BlogPart_BlogPart=blogview&amp;_c=BlogPart&amp;partqs=cat%25E6%258F%2592%25E4%25BB%25B6%25E7%25BC%2596%25E7%25A8%258B</link><language>en-US</language><pubDate>Mon, 23 Jun 2008 08:31:31 GMT</pubDate><lastBuildDate>Mon, 23 Jun 2008 08:31:31 GMT</lastBuildDate><generator>Microsoft Spaces v1.1</generator><docs>http://www.rssboard.org/rss-specification</docs><ttl>60</ttl><cf:parentRSS>http://flipcode.spaces.live.com/blog/feed.rss</cf:parentRSS><live:type>blogcategory</live:type><live:identity><live:id>-8189920746979949719</live:id><live:alias>flipcode</live:alias></live:identity><cf:listinfo><cf:group ns="http://schemas.microsoft.com/live/spaces/2006/rss" element="typelabel" label="Type" /><cf:group ns="http://schemas.microsoft.com/live/spaces/2006/rss" element="tag" label="Tag" /><cf:group element="category" label="Category" /><cf:sort element="pubDate" label="Date" data-type="date" default="true" /><cf:sort element="title" label="Title" data-type="string" /><cf:sort ns="http://purl.org/rss/1.0/modules/slash/" element="comments" label="Comments" data-type="number" /></cf:listinfo><item><title>The Pipeline and the INode TM Methods</title><link>http://flipcode.spaces.live.com/Blog/cns!8E578E7901A88369!863.entry</link><description>&lt;div&gt;备忘&lt;/div&gt;
&lt;div&gt;&lt;a href="http://sparks.discreet.com/knowledgebase/sdkdocs_v8/prog/main/sdk_pipe_the_pipeline_and_the_inode_tm_methods.html"&gt;http://sparks.discreet.com/knowledgebase/sdkdocs_v8/prog/main/sdk_pipe_the_pipeline_and_the_inode_tm_methods.html&lt;/a&gt;&lt;/div&gt;
&lt;div&gt;The Pipeline and the INode TM Methods&lt;/div&gt;
&lt;div&gt;This section discusses the INode methods GetObjectTM(), GetObjTMBeforeWSM() and GetObjTMAfterWSM() and their relationship to the pipeline.&lt;/div&gt;
&lt;div&gt;The INode::GetObjectTM(...) method returns a matrix that is used to transform the points of the object from object space to world space. Let's look at an example of how this method is used. Consider how the cylinder node is drawn in the scene. The cylinder draws itself in its BaseObject::Display() method. Into this method is passed an INode pointer. What the implementation of Display()does is call INode::GetObjectTM(). This method returns the matrix that is used to transform the points of the object from object space to world space. The Display() method then takes the matrix returned from GetObjectTM() and sets it into the graphics window (using GraphicsWindow::setTransform()). In this way, when the object starts drawing points in object space, they will be transformed with this matrix. This puts them into world space as they are drawn.&lt;/div&gt;
&lt;div&gt;Below is the code from the SimpleObject implementation of BaseObject::Display(). This is the code that the cylinder uses to draw itself. Note the GetObjectTM(t) and setTransform(mat) calls.&lt;/div&gt;
&lt;div&gt;int SimpleObject::Display(TimeValue t, &lt;/div&gt;
&lt;div&gt;         INode* inode, &lt;/div&gt;
&lt;div&gt;         ViewExp *vpt, &lt;/div&gt;
&lt;div&gt;         int flags) &lt;/div&gt;
&lt;div&gt;{ &lt;/div&gt;
&lt;div&gt;   if (!OKtoDisplay(t)) return 0; &lt;/div&gt;
&lt;div&gt;   GraphicsWindow *gw = vpt-&amp;gt;getGW(); &lt;/div&gt;
&lt;div&gt;   Matrix3 mat = inode-&amp;gt;GetObjectTM(t); &lt;/div&gt;
&lt;div&gt;   UpdateMesh(t); // UpdateMesh just calls BuildMesh() if req'd at time t. &lt;/div&gt;
&lt;div&gt;  &lt;/div&gt;
&lt;div&gt;   gw-&amp;gt;setTransform(mat); &lt;/div&gt;
&lt;div&gt;   mesh.render( gw, inode-&amp;gt;Mtls(), &lt;/div&gt;
&lt;div&gt;         (flags&amp;amp;USE_DAMAGE_RECT) ? &amp;amp;vpt-&amp;gt;GetDammageRect() : NULL, COMP_ALL, &lt;/div&gt;
&lt;div&gt;         inode-&amp;gt;NumMtls()); &lt;/div&gt;
&lt;div&gt;   return(0); &lt;/div&gt;
&lt;div&gt;}&lt;/div&gt;
&lt;div&gt;There is a case when world space modifiers are applied to an object where the points of the object may have already been transformed into world space. If a world space modifier has been applied, the points of the object may have already been transformed into world space and then deformed by the world space modifier. With the bent, rippled, cylinder example above, this is exactly what has happened. When the ripple space warp was applied, the points of the object were transformed into world space. In this case, the points should not be transformed into world space again when they are drawn (since they were already by the space warp). The problem is, the object does not know if it has been transformed into world space or not.&lt;/div&gt;
&lt;div&gt;The way 3ds Max handles this situation is by storing some state information with the node. Before the system calls Display(), HitTest(), etc. on the object it sets a flag. The flag indicates if the object has already been transformed into world space. The GetObjectTM() method looks at this flag to determine the proper matrix to return. In this way, when GetObjectTM() is called, it returns the matrix the object needs to be multiplied by in order to get into world space. If the object is already in world space it will return the identity matrix. If it's not in world space, it will return the matrix to get it there. So all any objects need to do in their Display() methods is call GetObjectTM() and use whatever matrix is returned.&lt;/div&gt;
&lt;div&gt;There may be times when a developer needs to access the full object TM regardless of whether the points of the object have been transformed into world space already. For example, if a developer was creating a utility plugin to align two objects. In this case, the developer would need to get the full object TM including the NodeTM and the object offset transformation. It would not matter if the points of the object had already been transformed into world space, the TM is what matters. In this case GetObjectTM() would not work. This is because it returns the identity matrix if the object is already in world space.&lt;/div&gt;
&lt;div&gt;To solve this problem 3ds Max provides two other INode methods that may be used.&lt;/div&gt;
&lt;div&gt;GetObjTMBeforeWSM()&lt;/div&gt;
&lt;div&gt;This method explicitly gets the full NodeTM and object-offset transformation affect before the affect of any world space modifiers.&lt;/div&gt;
&lt;div&gt;GetObjTMAfterWSM().&lt;/div&gt;
&lt;div&gt;This method explicitly gets the full NodeTM and object-offset transformation and world space modifier affect unless the points of the object have already been transformed into world space in which case it will return the identity matrix.&lt;/div&gt;
&lt;div&gt;Example&lt;br&gt;Using these methods a developer has complete access to any transformation matrix they require. Below is a code example that uses all these methods. This function computes the bounding box of the first object in the current selection set at the current time. It removes anything but scaling from the Object TM. In this way rotation of the node will not affect the bounding box.&lt;/div&gt;
&lt;div&gt;To do this we first need to determine if the object is in world space or in object space. Since we are after the object space bounding box (and will later apply scaling) we need to convert the TM back into object space if it is in world space. To check if the object is in world space we call GetObjTMAfterWSM(). If this matrix is the identity we know we are in world space. This is because when the points of the object get transformed by the ObjectState TM to put them into world space the ObjectState TM is set to the identity. Therefore if the matrix is the identity we are in world space.&lt;/div&gt;
&lt;div&gt;If the object is in world space we need to compute the object space TM. We can do this by taking the inverse of the world space TM.&lt;/div&gt;
&lt;div&gt;If the object is not in world space we just need to get its object TM by calling GetObjectTM().&lt;/div&gt;
&lt;div&gt;Once we have the object space TM we want to extract just the scaling portion of the matrix. 3ds Max provides a set of APIs that make this easy. This is done by calling decomp_affine(). This function decomposes a matrix into its translation, rotation and scaling components. See Structure AffineParts for more details.&lt;/div&gt;
&lt;div&gt;Once we have the scaling portion of the matrix we can get the bounding box and apply the scaling by calling GetDeformBBox().&lt;/div&gt;
&lt;div&gt;void Utility::ComputeBBox(Interface *ip) &lt;/div&gt;
&lt;div&gt;{ &lt;/div&gt;
&lt;div&gt;   if (ip-&amp;gt;GetSelNodeCount()) &lt;/div&gt;
&lt;div&gt;   { &lt;/div&gt;
&lt;div&gt;     INode *node = ip-&amp;gt;GetSelNode(0); &lt;/div&gt;
&lt;div&gt;     Box3 box; // The computed box &lt;/div&gt;
&lt;div&gt;     Matrix3 mat; // The Object TM &lt;/div&gt;
&lt;div&gt;     Matrix3 sclMat(1); // This will be used to apply the scaling &lt;/div&gt;
&lt;div&gt;  &lt;/div&gt;
&lt;div&gt;     // Get the result of the pipeline at the current time &lt;/div&gt;
&lt;div&gt;     TimeValue t = ip-&amp;gt;GetTime(); &lt;/div&gt;
&lt;div&gt;     Object *obj = node-&amp;gt;EvalWorldState(t).obj; &lt;/div&gt;
&lt;div&gt;  &lt;/div&gt;
&lt;div&gt;     // Determine if the object is in world space or object space &lt;/div&gt;
&lt;div&gt;     // so we can get the correct TM. We can check this by getting &lt;/div&gt;
&lt;div&gt;     // the Object TM after the world space modifiers have been &lt;/div&gt;
&lt;div&gt;     // applied. It the matrix returned is the identity matrix the &lt;/div&gt;
&lt;div&gt;     // points of the object have been transformed into world space. &lt;/div&gt;
&lt;div&gt;     if (node-&amp;gt;GetObjTMAfterWSM(t).IsIdentity()) &lt;/div&gt;
&lt;div&gt;     { &lt;/div&gt;
&lt;div&gt;       // It's in world space, so put it back into object &lt;/div&gt;
&lt;div&gt;       // space. We can do this by computing the inverse &lt;/div&gt;
&lt;div&gt;       // of the matrix returned before any world space &lt;/div&gt;
&lt;div&gt;       // modifiers were applied. &lt;/div&gt;
&lt;div&gt;       mat = Inverse(node-&amp;gt;GetObjTMBeforeWSM(t)); &lt;/div&gt;
&lt;div&gt;     } &lt;/div&gt;
&lt;div&gt;     else&lt;/div&gt;
&lt;div&gt;     { &lt;/div&gt;
&lt;div&gt;       // It's in object space, get the Object TM. &lt;/div&gt;
&lt;div&gt;       mat = node-&amp;gt;GetObjectTM(t); &lt;/div&gt;
&lt;div&gt;     } &lt;/div&gt;
&lt;div&gt;  &lt;/div&gt;
&lt;div&gt;     // Extract just the scaling part from the TM &lt;/div&gt;
&lt;div&gt;     AffineParts parts; &lt;/div&gt;
&lt;div&gt;     decomp_affine(mat, &amp;amp;parts); &lt;/div&gt;
&lt;div&gt;     ApplyScaling(sclMat, ScaleValue(parts.k*parts.f, parts.u)); &lt;/div&gt;
&lt;div&gt;  &lt;/div&gt;
&lt;div&gt;     // Get the bound box, and affect it by just &lt;/div&gt;
&lt;div&gt;     // the scaling portion &lt;/div&gt;
&lt;div&gt;     obj-&amp;gt;GetDeformBBox(t, box, &amp;amp;sclMat); &lt;/div&gt;
&lt;div&gt;  &lt;/div&gt;
&lt;div&gt;     // Show the size and frame number &lt;/div&gt;
&lt;div&gt;     float sx = box.pmax.x-box.pmin.x; &lt;/div&gt;
&lt;div&gt;     float sy = box.pmax.y-box.pmin.y; &lt;/div&gt;
&lt;div&gt;     float sz = box.pmax.z-box.pmin.z; &lt;/div&gt;
&lt;div&gt;  &lt;/div&gt;
&lt;div&gt;     TSTR title; &lt;/div&gt;
&lt;div&gt;     title.printf(_T(&amp;quot;Result at frame %d&amp;quot;), t/GetTicksPerFrame()); &lt;/div&gt;
&lt;div&gt;     TSTR buf; &lt;/div&gt;
&lt;div&gt;     buf.printf(_T(&amp;quot;The size is: (%.1f, %.1f, %.1f)&amp;quot;), sx, sy, sz); &lt;/div&gt;
&lt;div&gt;     MessageBox(NULL, buf, title, MB_ICONINFORMATION|MB_OK); &lt;/div&gt;
&lt;div&gt;   } &lt;/div&gt;
&lt;div&gt;}&lt;/div&gt;
&lt;div&gt; &lt;br&gt;&lt;/div&gt;&lt;img src="http://c.services.spaces.live.com/CollectionWebService/c.gif?cid=-8189920746979949719&amp;page=RSS%3a+The+Pipeline+and+the+INode+TM+Methods&amp;referrer=" width="1px" height="1px" border="0" alt=""&gt;&lt;img style="position:absolute" alt="" width="0px" height="0px" src="http://c.live.com/c.gif?NC=31263&amp;amp;NA=1149&amp;amp;PI=73329&amp;amp;RF=&amp;amp;DI=3919&amp;amp;PS=85545&amp;amp;TP=flipcode.spaces.live.com&amp;amp;GT1=flipcode"&gt;</description><comments>http://flipcode.spaces.live.com/Blog/cns!8E578E7901A88369!863.entry#comment</comments><guid isPermaLink="true">http://flipcode.spaces.live.com/Blog/cns!8E578E7901A88369!863.entry</guid><pubDate>Mon, 30 Oct 2006 03:29:41 GMT</pubDate><slash:comments>0</slash:comments><msn:type>blogentry</msn:type><live:type>blogentry</live:type><live:typelabel>Blog entry</live:typelabel><wfw:commentRss>http://flipcode.spaces.live.com/blog/cns!8E578E7901A88369!863/comments/feed.rss</wfw:commentRss><wfw:comment>http://flipcode.spaces.live.com/Blog/cns!8E578E7901A88369!863.entry#comment</wfw:comment><dcterms:modified>2006-10-30T03:29:41Z</dcterms:modified></item><item><title>maya插件说明(以helixTool.mll为例):</title><link>http://flipcode.spaces.live.com/Blog/cns!8E578E7901A88369!577.entry</link><description>&lt;div&gt;&lt;a href="mailto:flipcode@msn.com"&gt;&lt;/a&gt; &lt;/div&gt;
&lt;div&gt;maya插件说明(以helixTool.mll为例):&lt;/div&gt;
&lt;div&gt;&lt;a href="mailto:flipcode@msn.com"&gt;flipcode@msn.com&lt;/a&gt;&lt;/div&gt;
&lt;div&gt;一。装入插件helixTool.mll时:&lt;br&gt;    创建上下文件命令对象(helixContextCmd):&lt;br&gt; MStatus initializePlugin( MObject obj ){&lt;br&gt;  status = plugin.registerContextCommand(&amp;quot;helixToolContext&amp;quot;,&lt;br&gt;              _ helixContextCmd::creator,&lt;br&gt;             |  &amp;quot;helixToolCmd&amp;quot;,&lt;br&gt;             |  helixTool::creator,&lt;br&gt;             |  helixTool::newSyntax);&lt;br&gt;             |&lt;br&gt;             |__ &lt;br&gt;              　　这里回调用helixContextCmd::creator(){ return new helixContextCmd;}&lt;br&gt; }&lt;/div&gt;
&lt;div&gt;二。装入helixTool.mel内容:&lt;br&gt; 1.创建工具上下文helixToolContext1对象:&lt;br&gt; helixToolContext helixToolContext1;&lt;br&gt;   1) helixContextCmd::appendSyntax()映射参数类型. &lt;br&gt;      如: mySyntax = syntax(); &lt;br&gt;          mySyntax.addFlag(&amp;quot;ncv&amp;quot;,&amp;quot;numCVs&amp;quot;, kUnsigned) // (shortName,longName, kType)&lt;br&gt;   2) helixContextCmd::makeObj()创建helixContext.&lt;br&gt;      如:&lt;br&gt;        fHelixContext = new helixContext();&lt;br&gt;          return fHelixContext;&lt;br&gt;   3) 调用helixContextCmd::doEditFlags()分释参数字串设给fHelixContext&lt;br&gt;   &lt;br&gt;   4) 调用helixContextCmd::doQueryFlags()获取fHelixContext的参数值刷新UI&lt;br&gt; &lt;br&gt; 2.创建helixtTool图标，关联上helixToolContext1&lt;br&gt; setParent Shelf1;&lt;br&gt; toolButton -doubleClickCommand &amp;quot;toolPropertyWindow&amp;quot; // 双击进入属性框&lt;br&gt;    -cl toolCluster       // collection&lt;br&gt;    -t helixToolContext1  // tool 关联到 helixToolContext1&lt;br&gt;    -i1 &amp;quot;helixTool.xpm&amp;quot;   // icon&lt;br&gt;    helixTool1;           // name&lt;/div&gt;
&lt;div&gt;三。点击helixtTool图标:&lt;br&gt;    1). 这时helixtTool图标关联的helixToolContext1变成当前context,&lt;br&gt;    2). 调用helixContext::toolOnSetup(MEvent &amp;amp;)，可在其中设置要显示的帮助字符。&lt;br&gt;    3). 开始接收鼠标事件的触发，如doPress(MEvent &amp;amp;event)等&lt;br&gt;    &lt;br&gt;四。视图交互:&lt;br&gt;    1). 当鼠标点击视图时,调用helixContext::doPress(..){...}&lt;br&gt;    2). 当鼠标松开时,调用helixContext::doRelease(..){...}&lt;/div&gt;
&lt;div&gt; &lt;/div&gt;
&lt;div&gt;五。helixtTool的产生:&lt;br&gt;    一般会是在视图中按下的鼠标松开时在helixContext::doRelease(..)函数中&lt;br&gt; 1. helixTool * cmd = (helixTool*)newToolCommand();&lt;br&gt; 2. cmd-&amp;gt;setPitch( height/numCV ); // 给产生后的tool设参数&lt;br&gt;    // cmd-&amp;gt;setNumCVs( numCV ); 等等&lt;br&gt; 3. cmd-&amp;gt;redoIt();                 // 执行操作&lt;br&gt; 4. cmd-&amp;gt;finalize();               // 告知结束。在finalize()会将参数内容打包回传给UI右边属性框进行刷新&lt;br&gt; &lt;br&gt;    说明: 在1.中分两步:&lt;br&gt;    1.) 产生前先回调进行参数类型映射:&lt;br&gt;    MSyntax helixTool::newSyntax()&lt;br&gt;    {&lt;br&gt;     MSyntax syntax;&lt;br&gt;  syntax.addFlag(kPitchFlag, kPitchFlagLong, MSyntax::kDouble);&lt;br&gt;  syntax.addFlag(kRadiusFlag, kRadiusFlagLong, MSyntax::kDouble); &lt;br&gt;  // ...&lt;br&gt;  return syntax;&lt;br&gt;    }&lt;br&gt;    2.) 再回调注册的静态创建函数来产生:&lt;br&gt;    static void* helixTool::creator(){  return new helixTool; }&lt;br&gt;   &lt;br&gt;六。与右边UI(操作参数框)的互动:&lt;br&gt; 在脚本编辑器中source以下两文件&lt;br&gt; helixProperties.mel&lt;br&gt; helixValues.mel&lt;br&gt; 1. 双击helixTool图标，右边UI出现helixContextCmd的操作参数框&lt;br&gt; 系统回调了helixContextCmd::doQueryFlags()来获取fHelixContext的参数值UI参数框&lt;br&gt; &lt;br&gt;    2. 当拖动numCvs拖动改变numCVs个数时,&lt;br&gt;    a.系统调用helixContextCmd::doEditFlags()分释参数字串设给fHelixContext &lt;br&gt;    b.系统回调了helixContextCmd::doQueryFlags()来获取fHelixContext的参数值UI参数框 &lt;/div&gt;
&lt;div&gt;    3.命令参数操作&lt;br&gt;    a.查询参数: helixToolContext -q -numCVs helixToolContext1&lt;br&gt;    b.修改参数: helixToolContext -e -numCVs 32 helixToolContext1&lt;/div&gt;&lt;img src="http://c.services.spaces.live.com/CollectionWebService/c.gif?cid=-8189920746979949719&amp;page=RSS%3a+maya%e6%8f%92%e4%bb%b6%e8%af%b4%e6%98%8e(%e4%bb%a5helixTool.mll%e4%b8%ba%e4%be%8b)%3a&amp;referrer=" width="1px" height="1px" border="0" alt=""&gt;&lt;img style="position:absolute" alt="" width="0px" height="0px" src="http://c.live.com/c.gif?NC=31263&amp;amp;NA=1149&amp;amp;PI=73329&amp;amp;RF=&amp;amp;DI=3919&amp;amp;PS=85545&amp;amp;TP=flipcode.spaces.live.com&amp;amp;GT1=flipcode"&gt;</description><comments>http://flipcode.spaces.live.com/Blog/cns!8E578E7901A88369!577.entry#comment</comments><guid isPermaLink="true">http://flipcode.spaces.live.com/Blog/cns!8E578E7901A88369!577.entry</guid><pubDate>Sat, 25 Mar 2006 10:05:46 GMT</pubDate><slash:comments>0</slash:comments><msn:type>blogentry</msn:type><live:type>blogentry</live:type><live:typelabel>Blog entry</live:typelabel><wfw:commentRss>http://flipcode.spaces.live.com/blog/cns!8E578E7901A88369!577/comments/feed.rss</wfw:commentRss><wfw:comment>http://flipcode.spaces.live.com/Blog/cns!8E578E7901A88369!577.entry#comment</wfw:comment><dcterms:modified>2006-03-25T10:08:54Z</dcterms:modified></item><item><title>3dsMax7数据导出方法及存在问题 (转)</title><link>http://flipcode.spaces.live.com/Blog/cns!8E578E7901A88369!355.entry</link><description>&lt;div&gt;3dsMax7数据导出方法及存在问题 (转)&lt;/div&gt;
&lt;div&gt;来源:&lt;/div&gt;
&lt;div&gt;&lt;a href="http://blog.csdn.net/csdn_gamedev/archive/2005/12/12/550173.aspx"&gt;http://blog.csdn.net/csdn_gamedev/archive/2005/12/12/550173.aspx&lt;/a&gt;&lt;br&gt;关键字：3D 3dsmax7 插件 maxscript 3dmaxSDK 游戏开发&lt;/div&gt;
&lt;div&gt;&lt;br&gt;作者：卢立祎  来自：愤怒的犬夜叉&lt;/div&gt;
&lt;div&gt;&lt;br&gt;　　在游戏开发过程中需要大量的模型数据来描述人物、建筑、场景，如果开发编辑器来编辑网格、顶点，代价太大，因此往往利用一些现成的3D建模软件来代替。&lt;/div&gt;
&lt;div&gt;　　使用 3dsMax7 进行模型、动画数据导出是3D引擎开发过程中的一个必然环节（或者使用Maya等类似的3D建模工具）。然而discreet公司在指导用户进行二次开发的方面做得并不是太好，有一些问题是在开发过程中会常常遇到。&lt;/div&gt;
&lt;div&gt;　　美术工作人员在3dsMax环境中编辑好了三维人物或物体，加入了动作动画，指定了渲染方式，编辑了贴图和UV坐标之后，我们就必须想方设法把这类数据从编辑环境中导出成文件以供引擎使用。一般来说，最主要有三种方式来取得需要的数据：&lt;/div&gt;
&lt;div&gt;1. 利用已有的导出格式取得数据&lt;/div&gt;
&lt;div&gt;2. 制作max的export插件输出数据&lt;/div&gt;
&lt;div&gt;3. 编写maxscript输出数据&lt;/div&gt;
&lt;div&gt;&lt;br&gt;利用已有的导出格式取得数据&lt;br&gt;　　使用3ds文件和xml文件作为导出源文件，然后直接在引擎中读取数据转化为自己定义的数据格式。一般来说会使用一些转换工具转换为更加高效的文件格式。比如在早期的MS DirectX SDK 中，就有一个convert3DS 的工具，把3ds格式的文件转换为D3DX使用的X文件。由于这种方式受到源文件信息固定的限制，渐渐的不被采用。DirectX SDK 也开始使用插件的方式导出数据。&lt;/div&gt;
&lt;div&gt;　　Max7中，在菜单文件中选择导出，可以看到“IGame Exporter”，可以导出XML格式的文本文件，由于现在解析XML文件已经非常简单，甚至可以用序列化直接映射到数据结构，因此此方法有一定的使用价值。&lt;/div&gt;
&lt;div&gt;&lt;br&gt;制作max的export插件输出数据&lt;br&gt;　　使用maxSDK进行插件开发是大家普遍采用的方法，网上也可以查到相关的很多资料。在3dsmax7的目录中，可以找到maxsdk的目录，其中的help目录可以找到一些使用和开发帮助：&lt;/div&gt;
&lt;div&gt;1. Sdk.chm&lt;/div&gt;
&lt;div&gt;　　SDK的帮助文件。版本为6。个人感觉无论从整体结构还是编排都很糟糕，很难再非常快的时间内找到你想要的资料。&lt;/div&gt;
&lt;div&gt;　　如果要使用CS（Character Studio）的功能，就必须包含Include\CS目录下的头文件，以前max版本必须先安装CS的SDK才可以使用此功能，在max7中，CS已经成为了max的一个标准组件，因此CS SDK的部分也已经在max SDK中包含。&lt;/div&gt;
&lt;div&gt;　　Max7包含的CS的版本号为4.2。&lt;/div&gt;
&lt;div&gt;2. IGameHelp.chm&lt;/div&gt;
&lt;div&gt;　　Discreet提供了一套IGame的接口用来导出一般游戏制作需要导出的数据。“IGame Exporter”就是使用了此接口。可以在maxsdk\samples目录下找到这个插件的源代码。&lt;/div&gt;
&lt;div&gt;　　DirectX9提供的max插件也是使用了IGame接口导出数据，可以在DirectX SDK中的\Utilities\Source\Max找到此插件的源代码以供参考。&lt;/div&gt;
&lt;div&gt;　　IGameHelp.chm是使用Doxygen(&lt;a href="http://www.doxygen.org/"&gt;http://www.doxygen.org/&lt;/a&gt;)自动生成的文档文件，因此使用和查找习惯于Doxygen通用生成格式相同。&lt;/div&gt;
&lt;div&gt;　　其中的IGameSkin已经自动包含了Skin和Physique两种Modifier，无须分别写两套处理代码。&lt;/div&gt;
&lt;div&gt;　　Max7自带的IGameInterface版本号为1.121。&lt;/div&gt;
&lt;div&gt;3. sparks_archive.chm&lt;/div&gt;
&lt;div&gt;　　sparks是max的一个讨论站点，在里面可以找到很多你需要的问题的答案，sparks_archive.chm可以自动更新到最新，但是我从来没有更新成功过。&lt;/div&gt;
&lt;div&gt; &lt;/div&gt;
&lt;div&gt;　　此外，max7依旧提供了一套Ravi K Karra编写的VC6的3ds max Plugin Wizard，可以自动生成所需要的插件框架，很可惜，版本还是R5，搭配max7的SDK会有一些小问题。把文件\MAXSDK\HELP\SDKAPWZ.ZIP拷贝到VistualStudio的模版目录中（比如：\Microsoft Visual Studio\Common\MSDev98\Template），解压缩zip文件，VC6的新建模版中就会出现max Plugin Wizard这一项。&lt;/div&gt;
&lt;div&gt;　　如果要在VC6上编译max7的插件，还需要对一个头文件作一点小小的修改：在文件include\istdplug.h文件的第1685行：&lt;/div&gt;
&lt;div&gt;typedef struct { 改为： typedef struct Options{&lt;/div&gt;
&lt;div&gt;1708行：&lt;/div&gt;
&lt;div&gt;class Options2: public Options 改为：class Options2: public IAssignVertexColors::Options&lt;/div&gt;
&lt;div&gt;　　这都是因为VC6编译器无法对匿名结构进行继承。&lt;/div&gt;
&lt;div&gt;　　当然，也可以选择使用VC7\7.1进行Plug编写。可以在 &lt;a href="http://sparks.discreet.com/downloads/downloadshome.cfm?f=2&amp;amp;wf_id=134"&gt;http://sparks.discreet.com/downloads/downloadshome.cfm?f=2&amp;amp;wf_id=134&lt;/a&gt; 下载到3ds max 6 and 7 Plugin Wizard for Visual Studio 7。&lt;/div&gt;
&lt;div&gt;&lt;br&gt;　　使用插件导出数据有一个很大的弊端：在插件编写调试过程中，经常要重新重新启动max，浪费了不少时间，这一点无法与maxscript相比。&lt;/div&gt;
&lt;div&gt;&lt;br&gt;编写maxscript输出数据&lt;br&gt;　　使用maxscript进行数据输出是现在我手头项目的使用方法，使用简单、调试方便，每次有了改动不用重新启动3ds max。可以在帮助菜单内找到MAXScript Reference 7.0。maxscript可以操作max编辑环境内的所有的对象，并且可以通过plugin来增加功能与接口（插件的gup类型）。Max还内置了一个脚本编辑器，有语法高亮功能（到处是Bug!），建议使用EditPlus等文本编辑软件来编写脚本，并且可以在&lt;a href="http://www.editplus.com/files/maxscript.zip"&gt;http://www.editplus.com/files/maxscript.zip&lt;/a&gt; 下载到最新的EditPlus的maxscript语法高亮配置文件。&lt;/div&gt;
&lt;div&gt;　　Max7内置的Visual MaxScirpt编辑器可以方便的编辑界面，所见即所得，很方便，但是附带的方法编辑器同样非常难用，建议使用外部编辑。&lt;/div&gt;
&lt;div&gt;　　如果需要导出Character Studio数据，需要注意一些问题。&lt;/div&gt;
&lt;div&gt;　　Character Studio包含Biped、Physique和群组三个组件，一般我们会用到前两个。&lt;/div&gt;
&lt;div&gt;　　Biped是CS中主要的和最受认可的组件，它是用与类人角色的通用装备，但同时又足够灵活，可以进行自定义以适合各种不同形状的角色。在MAXScript Reference 7.0中的MAXScript Extensions中可以找到相应扩展各种使用方式的介绍和范例。&lt;/div&gt;
&lt;div&gt;　　Physique是类似于“蒙皮”的修改器，但它有额外的功能以更好的控制基本骨骼影响网格的方式。当使用Biped时，不需要Physique。它只是一种可选的蒙皮系统，也可以使用编准的“蒙皮”修改器。虽然在MAXScript Reference 7.0也有对Physique扩展方法的介绍以及范例，但是遗憾的是，Discreet并没有在Max7种实现它（这一点非常奇怪，有了说明却没有实现。据说在Max8中，这个扩展已经被删除）。如果在脚本中使用了此扩展，运行时会报告undefined。因此，我们必须手动实现此扩展，编写扩展的plugin。幸好已经有人把这个扩展导出插件写好，名字叫IPhysique，网上可以搜索到IPhysique.zip或者IPhysique.gup这个文件，把它拷贝到max的plugins目录下就可以了。因为这个导出方法和Reference中的方法不兼容，因此需要阅读自带的IPhysique.doc文档，里面大致介绍了各种函数方法的使用。在使用的时候，不要忘记在函数调用前加上physiqueOps前缀，比如physiqueOps.getPhysiqueModifier。但是要注意的是：网上下载的IPhysique.gup有不同的版本，一般来说是for max5.1的，无法在max7中使用，因此，可以有两个选择来解决这个问题：&lt;/div&gt;
&lt;div&gt;下载源代码，重新在maxSDK7下编译。源代码地址：&lt;/div&gt;
&lt;div&gt;&lt;a href="http://sparks.discreet.com/downloads/downloadshome.cfm?f=2&amp;amp;wf_id=130"&gt;http://sparks.discreet.com/downloads/downloadshome.cfm?f=2&amp;amp;wf_id=130&lt;/a&gt; &lt;/div&gt;
&lt;div&gt;有人已经把它在maxSDK7下编译生成了二进制文件。下载地址：&lt;/div&gt;
&lt;div&gt;&lt;a href="http://sparks.discreet.com/downloads/downloadshome.cfm?f=2&amp;amp;wf_id=146"&gt;http://sparks.discreet.com/downloads/downloadshome.cfm?f=2&amp;amp;wf_id=146&lt;/a&gt; &lt;/div&gt;
&lt;div&gt;这样，就可以很方便的使用Physique的功能进行数据导出了。&lt;/div&gt;
&lt;div&gt;&lt;br&gt;总结&lt;br&gt;　　总的来说，使用maxscript来进行数据导出是一个比较好的选择，无须编译、无须重启max，方便调试。&lt;/div&gt;
&lt;div&gt;&lt;a href="http://sparks.discreet.com/downloads/downloadshome.cfm?f=2&amp;amp;wf_id=130"&gt;http://sparks.discreet.com/downloads/downloadshome.cfm?f=2&amp;amp;wf_id=130&lt;/a&gt; &lt;/div&gt;
&lt;div&gt;有人已经把它在maxSDK7下编译生成了二进制文件。下载地址：&lt;/div&gt;
&lt;div&gt;&lt;a href="http://sparks.discreet.com/downloads/downloadshome.cfm?f=2&amp;amp;wf_id=146"&gt;http://sparks.discreet.com/downloads/downloadshome.cfm?f=2&amp;amp;wf_id=146&lt;/a&gt; &lt;/div&gt;
&lt;div&gt;这样，就可以很方便的使用Physique的功能进行数据导出了。&lt;/div&gt;
&lt;div&gt;&lt;br&gt;总结&lt;br&gt;　　总的来说，使用maxscript来进行数据导出是一个比较好的选择，无须编译、无须重启max，方便调试。&lt;/div&gt;
&lt;div&gt;&lt;br&gt;Trackback: &lt;a href="http://tb.blog.csdn.net/TrackBack.aspx?PostId=550173"&gt;http://tb.blog.csdn.net/TrackBack.aspx?PostId=550173&lt;/a&gt;&lt;br&gt;&lt;/div&gt;&lt;img src="http://c.services.spaces.live.com/CollectionWebService/c.gif?cid=-8189920746979949719&amp;page=RSS%3a+3dsMax7%e6%95%b0%e6%8d%ae%e5%af%bc%e5%87%ba%e6%96%b9%e6%b3%95%e5%8f%8a%e5%ad%98%e5%9c%a8%e9%97%ae%e9%a2%98+(%e8%bd%ac)&amp;referrer=" width="1px" height="1px" border="0" alt=""&gt;&lt;img style="position:absolute" alt="" width="0px" height="0px" src="http://c.live.com/c.gif?NC=31263&amp;amp;NA=1149&amp;amp;PI=73329&amp;amp;RF=&amp;amp;DI=3919&amp;amp;PS=85545&amp;amp;TP=flipcode.spaces.live.com&amp;amp;GT1=flipcode"&gt;</description><comments>http://flipcode.spaces.live.com/Blog/cns!8E578E7901A88369!355.entry#comment</comments><guid isPermaLink="true">http://flipcode.spaces.live.com/Blog/cns!8E578E7901A88369!355.entry</guid><pubDate>Tue, 21 Feb 2006 05:33:19 GMT</pubDate><slash:comments>0</slash:comments><msn:type>blogentry</msn:type><live:type>blogentry</live:type><live:typelabel>Blog entry</live:typelabel><wfw:commentRss>http://flipcode.spaces.live.com/blog/cns!8E578E7901A88369!355/comments/feed.rss</wfw:commentRss><wfw:comment>http://flipcode.spaces.live.com/Blog/cns!8E578E7901A88369!355.entry#comment</wfw:comment><dcterms:modified>2006-02-21T05:33:19Z</dcterms:modified></item><item><title>maya PlugInsAPI 笔记　</title><link>http://flipcode.spaces.live.com/Blog/cns!8E578E7901A88369!125.entry</link><description>&lt;div&gt;maya PlugInsAPI 笔记 
&lt;p&gt;
&lt;p&gt;以下是我在学maya时所作的笔记，对你也许没什么用，不过如果你也想知道如何编写maya插件的话，在我的“精彩网址链接”中有链接.&lt;br&gt;// 一.&lt;br&gt;MPxContexCommand  ---  脚本&lt;br&gt;MpxContex         ---  处理事件工具&lt;br&gt;MpxToolCommand    ---  给MpxContex用:如制模(在MpxContex的鼠标释放事件中产生一个newToolCommand临时对象来调用它的MpxToolCommand的doIt方法来产生模型)
&lt;p&gt;注册&lt;br&gt;initializePlugin(...)&lt;br&gt;{&lt;br&gt;status = plugin.registerContextCommand(&lt;br&gt;            &amp;quot;helixToolContext&amp;quot;, helixContextCmd::creator,&lt;br&gt;            &amp;quot;helixToolCmd&amp;quot;, helixTool::creator,&lt;br&gt;            helixTool::newSyntax);&lt;br&gt;}&lt;br&gt;反注册&lt;br&gt;uninitializePlugin
&lt;p&gt;// 二. 激活方法:&lt;br&gt;1. 用setToolTo command&lt;br&gt;2. 添加icon到shelf中&lt;br&gt;marqueeToolContext marqueeToolContext1; // 注意marqueeToolContext 是你在注册时的名字&lt;br&gt;setParent Shelf1;&lt;br&gt;toolButton  -cl toolCluster&lt;br&gt;            -t marqueeToolContext1&lt;br&gt;            -i1 &amp;quot;marqueeTool.xpm&amp;quot; marqueeTool1;&lt;br&gt;This code could either be sourced by hand from the MEL command window, or it could be invoked with MGlobal::sourceFile() in the initializePlugin() method of the plug-in.
&lt;p&gt;// 三. Tool Property Sheets：&lt;br&gt;为了处理工具表单要写两个Mel文件:&lt;br&gt;1.&amp;lt;yourContextName&amp;gt;Properties.mel&lt;br&gt;2. &amp;lt;yourContextNamevalues.mel
&lt;p&gt;// 四. 获取信息:&lt;br&gt;1. 遍历MItDag时得到MDagPath&lt;br&gt;2. 通过MDagPath得到对应MFnDagNode&lt;br&gt;3. 去掉不要的信息:如dagPath.isIntermediateObject()是这中间数据（如修改模型顶点时会保留原来的模型和被改后的模型在同一Transform结点下）, 而只找我们所要的，如MfnDagNode.hasFn(Mfn:kMesh)&lt;br&gt;4. 获得信息： fnMesh.getPoints(MPointArrary, MSpace:kWorld);
&lt;p&gt;&lt;br&gt;&lt;/div&gt;&lt;img src="http://c.services.spaces.live.com/CollectionWebService/c.gif?cid=-8189920746979949719&amp;page=RSS%3a+maya+PlugInsAPI+%e7%ac%94%e8%ae%b0%e3%80%80&amp;referrer=" width="1px" height="1px" border="0" alt=""&gt;&lt;img style="position:absolute" alt="" width="0px" height="0px" src="http://c.live.com/c.gif?NC=31263&amp;amp;NA=1149&amp;amp;PI=73329&amp;amp;RF=&amp;amp;DI=3919&amp;amp;PS=85545&amp;amp;TP=flipcode.spaces.live.com&amp;amp;GT1=flipcode"&gt;</description><comments>http://flipcode.spaces.live.com/Blog/cns!8E578E7901A88369!125.entry#comment</comments><guid isPermaLink="true">http://flipcode.spaces.live.com/Blog/cns!8E578E7901A88369!125.entry</guid><pubDate>Fri, 25 Nov 2005 03:21:22 GMT</pubDate><slash:comments>0</slash:comments><msn:type>blogentry</msn:type><live:type>blogentry</live:type><live:typelabel>Blog entry</live:typelabel><wfw:commentRss>http://flipcode.spaces.live.com/blog/cns!8E578E7901A88369!125/comments/feed.rss</wfw:commentRss><wfw:comment>http://flipcode.spaces.live.com/Blog/cns!8E578E7901A88369!125.entry#comment</wfw:comment><dcterms:modified>2005-11-27T05:26:45Z</dcterms:modified></item></channel></rss>