分享
 
 
 

用DirectX8实现SkinMeshes的点点滴滴

王朝other·作者佚名  2008-05-19
窄屏简体版  字體: |||超大  

Skin Meshes的概述

Skin meshes是分层场景(hierarchical scene)的一种类型。分层场景(hierarchical scene)被用于对象的相互连接。例如,手指属于手掌,手掌属于前臂等等。每个对象坐标的给予是相对于属于对象的局部空间,因此,旋转前臂将也引起手掌和手指的移动和旋转。下列插图显示如何人体使用一个分层场景如何构造。

用数学公式能非常简单的表示这个场景;矩阵代数是关键。给予场景,如果我们考虑前臂矩阵到前臂的变换矩阵,手掌矩阵到手掌的变换矩阵与手指矩阵到手指的变换矩阵,然后我们能简单的计算手指相对于世界的变换矩阵,由下列公式:

FingerWorldMat = FingerMat * PalmMat * ForearmMat * ... * BodyMat

在上面的公式里,我们考虑了分层场景的基础是身体,因此,它的矩阵是相对于世界空间。有我们的mesh拆分进入局部在那里每个部分是被一个特定骨架的世界矩阵变换了的,将使我们能够容易的活动mesh。

然而,有的人物是由分开的固定子对象组成现在不接受这种做法,因为在关节处它会引起裂缝。今后上升到skin meshes。Skin meshes克服了这个问题由人物根据位置和骨架的方位改变较小的部分的已有的外形。Skin meshes同样有骨架体系,但一个skin mesh的单个部分能被不止一个骨架变换。下列一个线性插值公式,顶点能有它们的位置被两个(或更多)骨架代替一个骨架影响。下列方法,我们能克服裂缝的问题。这个技术我们叫作顶点混合(Vertex Blending)。顶点混合要求每个顶点有一个混合权以便顶点描影能确定骨架如何影响顶点。例如,如果我们有一个顶点被两个骨架影响,下列公式将给予顶点的世界坐标作为被两个骨架影响:

Vw = Vm * M1 * w + Vm * M2 * (1-w)

在上面Vw是顶点在世界坐标里的位置。Vm是顶点相对于模型的局部空间位置。M1和M2是两个骨架的变换矩阵。w是混合权。注意混合权要求骨架数字小于1。

你能参考DX8文档看关于顶点混合更详细的信息。

Skin Meshes and DirectX 8

重要的是在开始实现我们的skin mesh代码以前应该知道DX如何处理skin mesh。当然,有许多文件格式能存储skin mesh但在此时最容易的一个是X文件。X文件能存储标准的静态meshes以外还能存储skin meshes。在我们讨论skin meshes以前,让我们对X文件有一个一般概念。我将讨论X文件的通用设计并且你能参考DX文档获得更详细的信息。X文件存储数据作为一套模版。象C语音的结构一样,模版有定义决定数据将如何存储在模版的实例里。模版的每个类型,你能有一个或更多的实例。有模版的许多类型,每一个想象成存储一个专用的数据类型。模版能有子类模版,使我们能够构造分层场景。虽然它不是强制性的,模版的实例能有名字。我们不需要用模版的所有类型直接处理,DX将为我们处理大多数工作,但在我们能开始工作以前我们需要有一些关于下列模版的概念。

l Frame

模版用于存储一个框架。框架是建造分层场景的成份。框架有它们的自己的变换矩阵并且它们能包含子类对象。框架也能包含子类框架。在skin mesh里,一个骨架参照一个框架。

l FrameTransformationMatrix

与名字暗示一样,这个是为框架的变换矩阵。它在框架模版内被用于实例的说明。

l Mesh

模版存储单个静态mesh和它的材质一起。在skin mesh里,整个人物将用一个mesh并且s皮肤信息规定mesh的每个部分如何被骨架影响。Mesh将在内部的分裂进入子对象;每个子对象将被一个骨架的特定设置影响。

l XSkinMeshHeader

这个模版存储关于皮肤的自然信息,信息用mesh输出。这个模版包含在Mesh模版内。

l SkinWeights

真实的皮肤信息存储在这里。模版定义一个特定的骨架如何能影响mesh。也就是,这个模版为影响mesh的每个骨架具体说明一次。如果有十二个骨架影响mesh,mesh模版将有十二个SkinWeights模版在内部说明。

在skin mesh与静态mesh之间的差别只是XSkinMeshHeader和SkinWeights模版的存在。从任何skin mesh的mesh模版移去这两个模版就把它变成了一个静态mesh。

其它的模版我们将也处理活动数据。我将在文章后面提涉它们。

有好消息也有坏消息。好消息是DX将处理所有的工作读取mesh需要它的材质和皮肤信息。坏消息是我们必须做余下的。我们将需要读取框架和构造分层场景。我们将也需要连接skin mesh到骨架。通常,X文件将包含一个框架分层结构并且包含一个(或更多)与皮肤信息一起的mesh模版。我们将独立的读取每个框架分层结构与mesh模版,然后手动连接mesh到它的骨架(框架)。用一个skin mesh建立一个X文件是制作模型者的任务。在用任何商业软件制作人物后,制作模型者能容易使用为这个目的设计特殊的插件导出它的模型到一个X文件。在Microsoft的网址上,你能找到为3DMAX和MAYA导出为X文件的插件。你甚至能找到支持建立X文件的应用程序。

现在我们知道数据在X文件里是如何组织的。为了读取数据,我们需要使用X文件库。IDirectXFile是库的主要接口。IDirectXFile有一个方法为创建IDirectXFileEnumObject。IDirectXFileEnumObject方法是被用于从一个指定的X文件里检索数据。IDirectXFileEnumObject::GetNextDataObject将循环通过在X文件里所有的顶层模版并且返回一个IDirectXFileData接口。稍后在X文件内部被用于检索单个模版的数据。相似于IDirectXFileEnumObject::GetNextDataObject,方法IDirectXFileData::GetNextObject循环通过所有的子类模版并且返回一个IDirectXFileData接口。方法IDirectXFileData::GetData被用于从模版里检索数据,但在我们能检索数据以前,我们需要知道模版的类型。方法IDirectXFileData::GetID返回模版的GUID。例如,如果模版是一个框架模版,GetID将返回TID_D3DRMFrame,它被预先定义在DX的头文件里。假如你需要模版的实例的名字(象是用框架的情况一样),方法GetName把名字将给你。

在我们进行通过X文件模版期间,我们将寻找一个模版与一个GUID等于TID_D3DRMMesh,它意味着它包含一个mesh。现在是DX给我们一些帮助的时候了。函数D3DXLoadSkinMeshFromXof将读取skin mesh与所有的余下的数据。仅给它一个指向IDirectXFileData接口的指针并且它将做余下的工作。

函数D3DXLoadSkinMeshFromXof将给予我们一个指向ID3DXSkinMesh对象的指针。这个对象包含skin mesh。在内部,这个对象包含mesh数据作为组(group)。每个组(group)被一个不同骨架的设置变换。函数将也返回一个材质数据由skin mesh使用。与我先前提到的一样,我们的工作是连接skin mesh到骨架。D3DXLoadSkinMeshFromXof给予一个缓冲区包含影响mesh的所有骨架的名字。它也给予其它缓冲区包含它们的变换。我们将使用名字为指定的骨架查遍我们的框架分层结构。骨架变换有点让人混乱。假定变换不在这里被包含在框架里。事实上,这个变换是骨架偏移(bone offset)。那么骨架偏移又是什么呢?重要的知道skin mesh的所有顶点是被存储在相对于一个原点,它是mesh的原点并不是骨架的局部原点。这意味着在mesh上为了有骨架的影响,我们应该使mesh变形由位于骨架的当前变换与骨架的原点变换之间的差别。或者换句话说,我们应该变换顶点到骨架的局部空间,然后变换它们回到mesh的空间使用新的骨架的变换。为了我们有一个更清楚的概念,让我们示范举例。让我们说说我们有一个骨架被放置在(0,50,0)与一个顶点被放置在(0,51,0)并且让我们假定这个顶点是只由一个骨架影响。如果我们移动骨架从它的原始位置到这个新的位置(0,51,0),顶点应该被移动到位置(0,52,0),但如果我们简单的由骨架的变换乘顶点,顶点将有新的位置等于(0,102,0)它是错误的坐标。因此,我们使用骨架的偏移矩阵到变换顶点从它的原始位置到一个相对于骨架的位置。新的位置将是(0,1,0)它将是被骨架的当前矩阵到新的位置变换,它是(0,52,0)。简单步骤如下:当你使用一个骨架,由偏移矩阵乘以它的当前变换矩阵并且使用结果作为世界矩阵。

让我们回到我们的ID3DXSkinMesh对象。这个对象在它的原型里包含skin mesh。这个对象为渲染skin mesh没有任何机能。因此,我们需要首先转换mesh进入一个ID3DXMesh对象。函数ConvertToBlendedMesh将做这工作。虽然它是相同的对象被用于渲染静态mesh,ID3DXMesh获得从ConvertToBlendedMesh里有区别它的顶点包含混合权,因此我们所需要做的是启用顶点混合并且在调用ID3DXMesh的DrawSubset方法以前设置我们的骨架矩阵。象前面提到的一样,mesh将被分裂进入组或子对象。每个子对象应该与一个指定的材质和一个指定的骨架设置一起被渲染。结构D3DXBONECOMBINATION指定材质和骨架被用于一个mesh的单个子对象。结构的数组也从ConvertToBlendedMesh函数里获得。我们所需要做的是循环通过这个数组,设置材质与骨架然后调用ID3DXMesh的DrawSubset方法给予它在数据里的下标。

实现

现在我们准备开始写实现我们的skin mesh代码了。多数重要的部分设计如下,下列插图显示我们代码的设计:

插图不显示所有类的成员,它只显示重要的东西。与在插图里显示的一样,类CMeshNode和CFrameNode两者从CObject里划分出来的。CObject的目的是提供连接三个机构;任何对象是从CObject里划分出来的将有能力连接进入一个连接树。CFrameNode是建立我们的场景分层结构的元素并且CmeshNode包含它自己的mesh。CMeshNode是包含在CFrameNode内部,CFrameNode包含在CSkinMesh内部。整个场景开始在CSkinMesh里因为它包含基础的框架。所有有关操作skin mesh将在CSkinMesh类里被初始化它依次将传递控制到分层结构作为必要的,因此,主程序将只处理CSkinMesh;CFrameNode和CMeshNode

 
 
 
免责声明:本文为网络用户发布,其观点仅代表作者个人观点,与本站无关,本站仅提供信息存储服务。文中陈述内容未经本站证实,其真实性、完整性、及时性本站不作任何保证或承诺,请读者仅作参考,并请自行核实相关内容。
2023年上半年GDP全球前十五强
 百态   2023-10-24
美众议院议长启动对拜登的弹劾调查
 百态   2023-09-13
上海、济南、武汉等多地出现不明坠落物
 探索   2023-09-06
印度或要将国名改为“巴拉特”
 百态   2023-09-06
男子为女友送行,买票不登机被捕
 百态   2023-08-20
手机地震预警功能怎么开?
 干货   2023-08-06
女子4年卖2套房花700多万做美容:不但没变美脸,面部还出现变形
 百态   2023-08-04
住户一楼被水淹 还冲来8头猪
 百态   2023-07-31
女子体内爬出大量瓜子状活虫
 百态   2023-07-25
地球连续35年收到神秘规律性信号,网友:不要回答!
 探索   2023-07-21
全球镓价格本周大涨27%
 探索   2023-07-09
钱都流向了那些不缺钱的人,苦都留给了能吃苦的人
 探索   2023-07-02
倩女手游刀客魅者强控制(强混乱强眩晕强睡眠)和对应控制抗性的关系
 百态   2020-08-20
美国5月9日最新疫情:美国确诊人数突破131万
 百态   2020-05-09
荷兰政府宣布将集体辞职
 干货   2020-04-30
倩女幽魂手游师徒任务情义春秋猜成语答案逍遥观:鹏程万里
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案神机营:射石饮羽
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案昆仑山:拔刀相助
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案天工阁:鬼斧神工
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案丝路古道:单枪匹马
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案镇郊荒野:与虎谋皮
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案镇郊荒野:李代桃僵
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案镇郊荒野:指鹿为马
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案金陵:小鸟依人
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案金陵:千金买邻
 干货   2019-11-12
 
推荐阅读
 
 
 
>>返回首頁<<
 
靜靜地坐在廢墟上,四周的荒凉一望無際,忽然覺得,淒涼也很美
© 2005- 王朝網路 版權所有