将模型导出到Direct3D

(零)序言
你在3ds
max(以下称作max)或Maya(以下称作maya)中为一款游戏制作各种3D模型,你希望自己所做的模型能在一款3D游戏引擎中被活灵活现地显示出来。在那一刻你会感到非常喜悦,因为玩家那充满热情或惊叹的眼神使你感到自己的作品被承认、被赞赏。嗯,这的确值得我们去想象!

 
不过,先别急着去幻想那些情景啦,因为你在进入梦乡前会有足够的时间来想象这些情景。在此之前,你还是要务实一点,先要为能得到那样的眼神而付出相应程度的努力。

 
不知你是否清楚这样一个事实(或,我现在需要告诉你这个事实),那就是,你在max或maya中保存的.max或.ma、mb格式的文件是不能直接“放到”引擎中去显示的。一般来说,游戏引擎都不支持这些格式,通常它们会各自定义一些专门的文件格式来存储模型,而只有具有这种格式的文件才能被引擎直接使用。因此,你就需要将max或maya制作的模型导出为那些格式。

 
      

要知道一般3D游戏引擎都是基于Direct3D(以下简称D3D)或OpenGL编写的。而由于不同引擎支持的格式各不相同,所以在此很难逐一去讨论。正如文章的标题所示,本文主要讨论如何将模型导出到基于Direct3D编写的应用程序或引擎,再或者更精确地说(如果你了解Direct3D的话)导出到Direct3DX的.X文件格式。本文的首要目的就是让你了解导出一个3D模型的概念和具体做法;其次介绍了一种方法来验证你的模型是否能在D3D游戏中被正确的显示出来;最后指出在max中导出.X格式时会遇到的一个小麻烦及解决方法。

 
最后,我假设你用的3D建模软件是max或maya,整篇文章都是围绕在这两种软件中进行导出来说明的。并且我进一步假设你使用的是当前主流版本的max或maya,即3ds

max 5.0或Maya 4.0~5.0,如果你使用的是其它软件,或者版本号太旧或太新,则以下内容可能不是太适合于你。
 
      
OK,开始吧~!
(一)如何导出?
.X文件格式
.X文件是Direct3D开发包所直接支持的唯一一种3D模型格式,也就是说,如果你是一个程序员,你可以很轻松地写出一个Direct3D程序用于显示.X文件所存储的3D模型。.X文件包含了对于一款3D游戏而言有用的信息,诸如模型中顶点的位置、顶点颜色、材质、UV纹理坐标、动画关键帧等等。另外,.X文件有两种存储方式:文本和二进制,两者在功能和用途上没有任何差别,只是形式不同而已。

安装导出插件
      
另外,以下内容中的一些插图和说明以max为例。
 
l      
3ds max 5.0
1)       
如果max已经启动,则先关闭它。
2)       
复制:
XSkinExp.dle
到:
(3ds max所在目录)\plugins\
3)       
启动max后,选择菜单:
Customize-> Plug-in Manager...
检查弹出对话框的列表框中是否存在“XSKINEXP.DLE”,并且其Status是否为“loaded”,如下图:
 
       

l      
Maya 4.0~5.0
1)       
如果maya已经启动,则先关闭它。
2)       
复制:
xExport.mll
到:
(maya所在目录)\bin\plug-ins\
3)       
复制:
bicubicbezierpatches.mel和xfiletranslatoropts.mel
到:
(maya所在目录)\scripts\others\
4)       
启动maya后,选择菜单:
Window->Settings/Preferences->Plug-in
Manager...
检查弹出对话框的列表框中是否存在“xExport.mll”,并且是否构选了“loaded”和“auto
load”,如下图:
 
导出模型
l      
3ds max 5.0
1)       
选择菜单:
File->Export
在弹出对话框中选择保存类型为“X-File (*.X)”,并指定保存路径和文件名。
2)       
然后,可在弹出的导出选项对话框中进行设置,配置好以后按“Go!”按钮,导出选项和解释如下:
 
 
各个选项含义如下:
     
导出选项描述
     
Text文本
     
Binary
     
Binary Compressed二进制
     
压缩的二进制
     
Export Patch Data如果存在高次(high-order)表面则将导出patche以替代polygon网格
     
Include Animation Data是否同时导出动画数据,需要指定动画采样速率(单位:帧/秒)
     
Looping Animation Data是否循环播放动画

l      
Maya 4.0~5.0
1)       
选择菜单:
File->Export All…
在弹出对话框中选择保存类型为“xExport (*.*)”,并指定保存路径和文件名。
2)       

在文件保存的对话框中,按下左下角的“Options…”按钮后,可在弹出的导出选项对话框中进行设置,配置好以后按“Export”按钮,导出选项和解释如下:

 
 
各个选项含义如下:
     
导出选项描述
     
File Options选择文本、二进制、压缩的二进制
     
Tesselation
Options选择高次(high-order)和细分(subdivided)表面,或none为忽略这些表面
     
Material Options选择是否同时导出材质、是否翻转UV纹理坐标轴、纹理文件路径是采用限定路径,还是不限定路径
     
Animation Options“Export
     
Animation”用于选择是否保存动画属性。如果选择保存动画属性和“per-frame”后可以通过“Frame
     
Step”或拖动条来设置采样率;默认值是1,表示1:1的关系。该值与Maya的当前回放(playback)速度有关。
     
Skinning Options“Export
     
Skinning”允许你选择是否保存网格中skinning信息。如果没有选择该选项,则网格不能自我变形(deform),但如果网格继承于带有动画的层级的话,则它只可以在空间中移动。

观察导出结果
1)       
确认已安装了DirectX 9.0运行库(如果这个链接已失效,请点击这里来寻找最新的DirectX)。
2)       
运行Mesh Viewer,选择菜单:
File->Open Mesh File
选择相应的.X文件
1)       

你可尝试通过鼠标左、中、右键来旋转、缩放、移动地观察模型;你还可以选择显示法线、是否剔除(Culling)背面、以何种方式(点、线框、面)来显示模型等,以此来查看模型是否正确。

 
如果在Mesh
Viewer中一切显示正常,那么在基于Direct3D的程序中,一切也会表现良好。如果有些面没有正常显示或导出时就失败了,则说明你的模型存在一些问题,需要进一步检查一下模型,看看法线是否正确、多边形的边是否合拢、是否存在缝隙等。在max中进行导出时你会遇到一个小问题,你在导出前多做一件事情来解决这个问题。继续前进,来让我们看一下在max中导出时发生了什么“怪”事情。

(二)max的导出问题
起因
如果你以为将max制作的模型导出到.X文件后会有一样的外观的话,那你可把世事想得过于完美了。你至少会发现一个非常明显的错误,那就是:模型被关于XY平面作了镜像,譬如拿XY平面比作一面镜子,你在Direct3D中看到的将是那个在镜子中的模型(注意,我在这里没有提及maya,那是因为maya的导出插件已经处理了这个问题,真要感谢编写那个插件的那位作者!)。

 
以一个max模型(该模型系杨·为一同志所做,感谢他提供这个模型,正因为在导出这个模型时显露出来的错误使我更深入地研究了本文所涉及的主题J)为例,它显示出来导出前后模型的变换,导出前我们通过XY平面看到了狮子的背面,而导出后通过XY平面看到的却是狮子的腹部。如果想象原来的狮子站在一面镜子上,那么导出的就好比是那个镜子中的狮子。

 
         
(左图:在max中的模型;右图:导出后在Mesh Viewer中的模型)
 
好,现在你应该活动一下筋骨了,来尝试导出一个模型到.X文件吧。我建议你的试验模型最好不要是对称物体,并且具有一点能标识方向的几何体,我在这里提供了一个模型,如果你想偷点懒的话可以直接用它来做这个试验。然后亲身感受一下这个问题。

经过
      

那是什么原因造成了以上的问题呢?如果你是一个喜欢打破砂锅问到底的人,那这一段正是为你准备的。如果你是一个讲求实效或以“可用即可”作为行事准则的家伙,那么你可以直接跳到“结果”那段,“经过”对于这类人不是最重要的。

 
      

max和maya都使用了“右手坐标系”,以你计算机屏幕的左下角为坐标系原点的话,那么右手坐标系中X、Y、Z轴的正方向依次为向右、向上和向外(即指向你),如下左图。而Direct3D默认使用却是“左手坐标系”,与右手坐标系的唯一区别在于Z轴正方向相反,即向内(指向显示器内部)。另外,OpenGL使用的是右手坐标系,所以这些问题在OpenGL编程中不存在,无论你用max还是maya,直接导出原始的顶点数据即可通过OpenGL绘制出来。

 
(D3D使用的左手坐标系和max、maya、OpenGL使用的右手坐标系)
 
      
好了,当你明白这些知识后,让我们来看一下在从max或maya的右手坐标系转换成D3D的左手坐标系的过程中发生了什么。
 
      
考虑在使用右手坐标系的max中有一个顶点为(0, 0,
1),你应该可以想象它是位于Z轴的正方向那段上。当这个顶点被不加修改地以左手坐标系来解释的话,那么它还是位于Z轴的正向段的Z轴,但是绝对位置却发生了变换。那么当构成一个模型的所有顶点都被这样进行转变的话,那么得到的结果就好比是一个物体关于XY轴所构成的平面作了镜像转换。如下图所示:

        
(左图:建模完成的物体;右图:原来处于右手坐标系中的物体,直接转换到左手坐标系后的情况)
 
      

由上右图你可以看到,“镜子中”物体(即转换到左手坐标系后的物体)不是“现实”物体(原右手坐标系中的物体,也就是你建模完得到的物体)的副本,我希望你能明白我在这里所谓“副本”的含义,我指的是可以与原物体完全吻合的另一个物体、另一个复制品。而现在“现实”中物体无论如何旋转或移动是永远都不可能得到“镜子中”物体的,如果你不信可以想象或比划一下,是不是呢?不是吗?是的。J

结果
想知道解决方法吗?或许聪明的你已经知道该怎么做了。我这里有三种解决方法,可能你会更倾向于其中的某一种吧。
l      
美工解决(推荐)
众所周知,有一句话曰“负负得正”。既然导出后的结果是原模型的镜像结果,那何不在导出前先对模型作一次镜像呢?两次镜像的结果就是原来的样子。

 
在用max制作完一个模型准备导出前,做如下步骤:
1)       
选中整个模型
2)       
完成镜像操作,选择菜单:
Tools->Mirror
在弹出对话框中对于“Mirror Axis”选择“Z”,然后按“OK”按钮
3)       
导出
 
这样做的有两个前提:一、应选中场景中所有的物体来作镜像;二、物体应处于世界坐标系的原点。除非你知道当违反这两个前提时会得到什么结果,并对这样结果有所预期。不然你就应该保证这两点。

 
另外,你可以想象一下如果没有这两个前提的保证下会发生什么情况。对于不满足前提一来说,某些在max作了镜像的物体能如max中所显示的那样,而某些未作镜像的却在导出后被镜像了;而对于前提二来说,如果物体不处于世界原点,则导出结果的模型本身正确了,但位置却作了关于XY平面的镜像。

 
这个方法简单有效,不是吗?而且这种解决方法不是发生在游戏运行时刻,可以节省大量的运行时开销。顺便还能让程序员们可以轻松点!想想他们在成堆的代码中已经够可怜了(当然,有的程序员视为享受,天堂和地狱只在一念之间J),饶了他们吧。

l      
程序解决
你们注定是不平凡的,但同时也注定你们是最辛苦的。因为理论上任何开发相关的事情都可以由你们来完成,只是开发/运行效率存在高低之别而已。

 
      

在当前要解决的问题中,可以通过在程序中作一次镜像来完成,概念上与上述的“负负得正”一样。大致思想是:在进行单个导出物体的世界变换之前,先作关于XY平面的镜像(XY平面可以是世界坐标系的,也可以模型局部坐标系的,两者效果是不一样的),如果选择作关于世界坐标系的XY平面的镜像,则还需要将镜像后的结果移回到原来的位置,即按Z轴平移。以下代码演示了关于世界坐标系的一个镜像,然后将对象移回到原来位置。

 
D3DXMATRIX matWorld;
……
D3DXPLANE plane( 0.0f, 0.0f, 1.0f, 0.0f ); // 关于XY平面的镜像
D3DXMATRIX matReflect;
D3DXMatrixReflect( &matReflect,
&plane ); // 构建一个关于XY平面的反射(镜像)矩阵
float fZ = matWorld._43; // 记录下物体的原Z轴位置
D3DXMATRIX matMoveBack;
D3DXMatrixTranslation( &matMoveBack, 0, 0, -2 * fZ
); // 构建移回矩阵
matWorld = matReflect * matMoveBack * matWorld;
pDevice->SetTransform( D3DTS_WORLD,
&matWorld );
 
这段代码有几处值得进一步优化,但我现在这么写纯粹是出于让你看懂的目的,在你理解之后可作进一步的优化。
 
这种方法具有更多的灵活性,但你需要为此付出运行时开销。如果你用不到该方法带来的灵活性的话,还是从美工的角度来解决这个问题吧。

l      
工具解决
就我知道存在一个转换工具――Deep
Exploration(http://www.righthemisphere.com/),可以将诸如max、maya等多种格式的模型文件转换称.X文件,并且它已经处理了这个镜像的问题。该软件使用非常简单,选择相应的源文件,然后将其另存为.X类型的文件即可,在此就不展开讨论了。

 
可能还有更多工具有待你的发掘,如果找到别忘了告诉我一声。
(三)附录
l      
建模建议
1)       
如果建模软件支持更改坐标系的话,应尽量选择使用左手坐标系来制作将会在D3D用到的模型,由此避免了转换;
2)       
建模过程应尽量使物体的头方向朝着Y轴正方向,右方向朝着X轴正方向,前方向朝着Z轴正方向,这样也可以避免程序在运行时对物体模型进行旋转调整;

3)       
建模时应尽量使用相同比例的坐标单位,这也可以避免运行时的缩放;
4)       
导出模型前检查所有法线朝向是否正确,在max据说所知可以通过加一个XForm来检查。
文章转载自:

Homepage:http://www.zhouweidi.name
email & MSN Messenger:zhouweidi@hotmail.com

游戏开发工具浅谈

转载自http://job.17173.com/content/2008-10-30/20081030174833105.shtml

 作为目前国内游戏业的从业人员,我就我的工作经历把我知道的游戏开发知识分享给大家。所知有限,大家不要见笑哈~今天先说一下一个游戏制作团队需要使用的开发工具。毕竟“工欲善其事,必先利其器”,没有顺手的开发工具,表达和实现难免总是受限。

   
业界标准的游戏制作团队包括设计师(策划)、艺术家(美术)、架构师(程序)三部分,同时也要加上QC(测试)小组以保证迭代开发中的快速验证、除bug与模块稳健度。那么这次就主要介绍各个工作岗位的开发人员需要使用和建议使用的各种开发工具。

   
先从程序说起。程序员需要使用的工具,依据游戏平台的不同、开发端的不同有着不同的区分。但是一般都离不开C++,因此必备的开发工具就是Visual
Studio。以前PC平台上多用C开发,现在基本已经全部采用C++,但考虑到运行效率,有些网络游戏的服务器端开发仍然使用C。但是完全依靠人工写代码不但低效、劳累而且容易出错。因此出现了许多中间件(MiddleWare)开发套件,这些是封装好的图形、物理、粒子、AI、网络、声音、UI模块,内部嵌入了各种游戏中使用的函数。程序员只需要写好接口、加入针对性的运算函数便可以把这些部分的工作量减少很多了。而比较大型的中间件可能包含了这其中的许多模块,这便是游戏引擎(Game
Engine)。游戏引擎有很多种,有综合性的,比如unreal tournament、quake
3D、LithTech、jupiter等等。也有专注性的,最主要专注于两个方面——图形和物理。比如专注图形的ogre和专注物理的havok、ode,现在由于网络游戏开发比较热,引擎的网络部分也得到重视,一般采用C/S方式,也有P2P的方式,有些引擎会提供强大的分布式运算和ado技术。但也有一些引擎没有网络部分,一是由于调用数据的不确定,二是网络端会有专门的优化,许多程序员会写专门的算法处理这一部分。图形用户界面(GUI)有的为团队自己写,因为各种游戏界面需求不太一样。有的用引擎或第三方提供的GUI包写的。有很多……比较著名的是GTK+、wxWidgets、Qt

   
美术方面,二维的标准开发工具是painter和photoshop,三维的标准开发工具是3D
max和maya。二维不用多说,基本多少年都没什么变化。输出的标准格式早期是pcx、bmp,现在最常用的是tga、dds,tga是标准工业格式,已被业内大多数企业所接受很久。dds是为对应directX节省缓存的一种压缩格式,本身也有很多种格式,效果没有无损压缩图像那么好,但对于提高显示效率和节省游戏容量效果很好(图形是游戏中最占容量的部分)。png也是很好用的一种格式,正被逐渐接受。jpeg很少被使用,一是因为图像有损压缩,二是不支持alpha通道,无法实现一些特定效果。三维最早是max和lightwave,但maya的崛起使得其也逐渐成为游戏开发的标准工具。现在不少制作团队都开始转向maya,lightwave在欧美开发团队使用的比较少,日本的开发团队则非常喜欢lightwave。除此之外,由于CG产业的迅猛发展以及开发要求的提高,许多新型的优秀三维工具也进入游戏开发领域。比如softimage、motion
builder等,它们在动画制作方面有着强大的功能。三维输出的主要格式是max(流行)和obj。游戏中各种绚丽的效果是用粒子实现的,这也是美术工作的一部分。一般没有什么标准的工具,只要美术制作出粒子最基础的纹理材质图片(很小的二维图形,常用png格式),再导入到程序中计算路径、发射角、密度、生命周期、着色、受力等。也出现了一些独立的专门制作粒子特效的工具,二维游戏里面最常用的是particle
illusion(它本来是用于影视粒子特效制作的)。三维的有很多,比如particle accelerator、particle
editor等等。

   
策划方面的标准和使用的工具都很杂。由于策划是内容的开发者,所以首先要解决文字和数据的问题。MS 
word和excel是不可少的工具。虽然策划不是美术和程序,但是图像表达和逻辑表达也是策划应该尽量作到的。二维图像表达你至少要会使用word自带的绘图功能,但仍然建议掌握一些基础的平面绘图工具,比如photoshop、fireworks等等,如果你能用动画表示更好,比如flash、gif等;三维建议了解max、maya,我推荐使用轻型快速的三维工具进行表达,比如silo、sketchup等。它们都可以输出为obj格式,方便导入到max中(多用于查看,因为模型会有一定程度的破损,部分需要重新制作),也可以使用截图软件截屏然后制作二维示意图。策划的工作还涉及脚本(script)创作,比如游戏的部分AI、任务逻辑、物品(诞生、消失)控制、运算(hp减血、攻击数值)数据、物理碰撞锁死编辑、触发器等。这些方面的主要文件格式为ini、xml,还有直接封包为bin、pak以及程序自己开发的各种存储格式。不少游戏使用python、lua等通用的脚本语言进行解释,它们可以很方便的嵌入到宿主程序中,加快了调试效率。多数游戏引擎也会提供强大的脚本编译器。

   
其实策划拥有强大的编辑器就可以把上面这些全省了……不过需要程序先把框架搭好,美术先把资源做好,策划才可以拼接设计,这已经耗费了很多时间了。所以能保证制作之前完成规划性的设计是很重要的。策划还需要要考虑可用性、复用性、逻辑锁死以及提出的资源需求(包括质量、数量)对效率的影响。比如哪些美术资源是可以重复使用的,图像质量要求要达到什么程度(过高的要求会大大降低程序渲染效率,也会增加整个团队的工作量),数值变化的临界点以及控制机制。当然这些就是具体的工作内容了,这里不再详述。

   
音乐音效部分有专门的创作团队制作,多数游戏制作商为外包。但也有许多不太注重品质的制作商直接就让策划做了(无敌的音效库……)。标准的创作方法是,首先需要在录音室创作音源,用音频采集卡录制cd品质,在专业工具中进行编辑,包括采样、滤波、除噪、编辑通道、混音、剪辑和合成,最后输出为wav或ogg格式。ogg格式压缩率更高,品质也很好(强于mp3),比起wav格式更省体积;也可以直接创作数字音源,制作midi格式的音乐音效,这就要有更多的专业知识了。这方面的工具有很多,Cubase是标准的开发工具,也可以使用sound
forge、sound editor编辑。