虚拟人(行走)运动控制设计实现论文_第1页
虚拟人(行走)运动控制设计实现论文_第2页
虚拟人(行走)运动控制设计实现论文_第3页
虚拟人(行走)运动控制设计实现论文_第4页
虚拟人(行走)运动控制设计实现论文_第5页
已阅读5页,还剩34页未读 继续免费阅读

下载本文档

版权说明:本文档由用户提供并上传,收益归属内容提供方,若内容存在侵权,请进行举报或认领

文档简介

PAGE摘要本文在参阅和分析了大量有关文献的基础上,对现有的各种实现虚拟人运动控制的方法进行了总结,特别是对当前广泛使用的参数化关键帧技术,基于物理的仿真技术,运动捕获技术以及运动编辑技术等,对各种方法的优缺点进行了分析。在此基础上研究并实现了虚拟人(行走)运动控制。通过对虚拟人模型的研究,在VC6.0平台基于DIRECTX的基础上,结合计算机图形学的基本知识,使用参数化关键帧技术实现了虚拟人的运动,通过坐标平移实现虚拟人的行走,旋转实现虚拟人的转弯。关键词:DIRECTX,虚拟人,人体动画,运动控制,关键帧,运动捕获AbstractInthispaper,onthebasisoftheanalysisandclassificationofavarietyofmethodsformotioncontrolinvirtualhuman,aclearoverallpictureofallthosemethodsisprovided.Itisdiscussedinthepaperthetechnologiesofmotioncontrolsuchaskeyframing,proceduremethod,motioncapture,simulationbasedonphysicsandtheiradvantagesanddisadvantagesaswell.Andthenwestudyandimplementthecontrolofthevirtualhuman'smovement(walking).BasedontheknowledgeoftheComputerGraphics,thetenchnologyofkeyframingisusedtoachieveitontheplatformofVC6.0andDIRECTX.Indetail,weimplementthewalkingofthevirtuanhumanbythetranslationofthecoordinate,andtheswervebythecoordinate'srotation.Keywords:virtualhuman,humananimation,motioncontrol,keyframe,motioncapture -PAGEii-目录第1章绪论 11.1虚拟人的作用和意义 11.2本论文的背景 2第2章虚拟人运动控制的研究现状 31.1概述 32.2虚拟人运动模型 42.3虚拟人运动关键技术 52.4小结 8第3章DIRECTX技术 93.1概述 93.2DIRECTX3D对象及设备 103.2.1DIRECTX对象(D3DObject) 103.2.2DIRECTX设备(D3DDEVICE) 103.3矩阵(Matrices) 123.3.13D迪卡尔坐标系统和矩阵定义 123.3.2矩阵变换 123.3.3场景变换矩阵 143.4在DIRECTX3D中使用网格模型 153.4.1载入一个网格模型对象 153.4.2渲染一个网格模型对象 173.4.3释放一个网格模型对象 173.5DIRECTINPUT 183.6小结 18第4章用DIRECTX设计实现虚拟人运动控制 194.1虚拟人造型 194.1.1用3DMAX建模 194.1.2虚拟人数据导出 194.1.3虚拟人数据结构 204.2使用DIRECTX实现虚拟运动控制 254.2.1关键帧的设计 254.2.2平移实现行走 264.2.3旋转实现转弯 274.2.4程序的构造和流程 284.2.5行走实现例子 33第5章结束语 345.1本文的工作总结 345.2展望 34参考文献 35致谢 36江苏大学本科生毕业论文-PAGE36-第1章绪论1.1虚拟人的作用和意义虚拟人是完全由计算机表示,看起来像真人的图形实体[1],即人的计算机模型。它作为虚拟环境中有特色的群体,历来受到研究者的额外重视。一方面,它可以作为真人的替代者对计算机设计的车辆,工作区域,机器工具,装配线等在实际构造前进行人类工效学的评估;在真人无法到达的环境中进行各种精密的,甚至危险的实验;在军事上代替真人接受各种训练;在医学上代替真人接受一些矫形手术;在航空军事上代替真人从事太空作业等等。另一方面,它可以作为我们自身或其他实际参与者在虚拟环境中的实时表示。图1-1给出了几种虚拟人的表示:图SEQ图\*ARABIC1-1虚拟人模型通过对虚拟人的研究和应用,可以使用户得到以下两种特性:(1)逼真性:用户通过虚拟人所得到的感受与他在真实系统中得到的感受尽可能相同,通过各种感官和系统发生交互作用,具有“身临其境”的逼真感。(2)虚拟性:用户通过虚拟人能够得到他在真实物理世界中所无法亲身体验的感受,突破物理空间,时间的限制和避免涉及生命安全的和环境,用户得到了虚拟人的“超越现实”的虚拟性。虚拟人的研究和发展,使研究者可以直接以人为研究对象,开展各种有意义的人类活动的研究,一方面提高对人类自身的认识,一方面进行各种在现实中无法进行的,于人类有益的试验。例如,在生物力学领域,可以对人后背的变形,不正确姿态的影响,语言机能障碍和视觉机能障碍进行仿真。模拟处于危险状况中的人:交通事故,飞机失事,火灾,爆炸等。在虚拟战场中,模拟对军事人员的训练等等。这一切对于改善人类的生活,生活环境,扩展人类的活动范围,提高人类的生存质量具有重要而深远的意义。因此虚拟人已经成为国内外计算机科学中主要的研究方向之一,具有广阔的应用背景,在未来的教育,生活,科研中必将发挥巨大的作用。1.2本论文的背景在虚拟环境中,利用虚拟人来模拟真实人的行为并对其性能进行评估,这在动画机械工程医学军事和空间探索等应用中变得越来越重要。随着虚拟人技术的日益成熟,虚拟人已被广泛的应用于工程,虚拟会议,交互,监控,虚拟环境,游戏,训练,教育,军事训练,产品的设计与维护等领域,随着虚拟现实技术的快速发展在虚拟环境中建立理想的,综合的虚拟人已经逐渐成为人体动画研究中的一个新的方向。在虚拟人的研究中,虚拟人的运动控制的研究是虚拟人研究中的一项十分重要的内容。本文通过对虚拟人运动模型的研究,结合图形学的相关知识在DIRECTX下实现了虚拟人的运动(行走)控制技术。第2章虚拟人运动控制的研究现状1.1概述在国外研究虚拟人运动控制的众多团体中,由蒙特利尔大学Magnenat-Thalmann和Thalmann所带领的研究团队比较著名。一支是由Magnenat-Thalmann带领的在日内瓦的MIRALab,MIRALab主要是以研究人脸的表情动画[2],手部的变形以及虚拟人的附属物例如服装,头发等为主。另外一支是由Thalmann带领的在洛桑的LIG实验室,LIG实验室只要从事人体建模及变形的研究,人的行走,抓取等动作的研究,以及运动控制系统,运动捕获,人体动画工具的开发,人体平衡控制的研究,碰撞检测技术和基于网络的虚拟人的研究等。另一个比较著名的研究团体是宾夕法尼亚大学由Badler领导的人体建模与仿真中心。他们的研究包括参数化的关键帧技术在基于关节虚拟人的模型中的应用,逆运动的应用,人体的平衡研究,脊骨的建模,行走模型的建立,运动捕获的研究,人的冲突检测和纠正以及智能运动规划问题的研究等。另Bruderlin和Calvert致力于研究虚拟人的动态行走模型Kunii和Sun致力于虚拟人的动力学方面的研究;Calvert等人在虚拟人的舞蹈方面也有所突破;Terzopoulos和Waters从事基于物理的人的面部表情的动画研究,而Essa和Pentland则从基于视觉的角度研究虚拟人的面部表情的动画;Animationlab的以Hodgins[3]等人为骨干主要从事动态仿真技术方面的研究,并成功的实现了很多体育运动的仿真(如跳水跳马自行车赛等)。国内在虚拟人的建模与运动控制方面,华中理工大学,北京航空航天大学,中国科学院,哈尔滨工业大学以及浙江大学等学校都做了大量的理论研究及实践工作。其中,在人机交互方面华中理工大学陈立平等人在基于人机功效学的人体建模和运动仿真方面进行了研究;北京航空航天大学的袁修干等人主要在人机系统仿真中的三维人体建模的方面进行了研究。在人体建模方面,中国科学院计算机技术研究所CAD开放实验室的詹永照等人,给出了以多面体组合建立粗略的人体,用多面体细分割来逼近真实人体曲面的方法,并在建模中考虑了人体的动态特性,为建立人体动画模型创造了条件。在虚拟人的实时运动控制方面,哈尔滨工业大学的贺怀清等人致力于研究虚拟人的实时运动控制,并实现了虚拟人的步行与跑步运动方式;中国科学院的王兆其等人在人体行为交互方面做了大量的研究,并且应用虚拟人合成技术实现了人体行为交互的主要工作,并将其研究成果应用在聋人手语交互等方面的应用;浙江大学庄越挺等人在人体动画方面,提出了一种基于紧身衣和相机定标的新的人体动画技术。在虚拟人的面部行为方面,中国科学院的高文等主要研究与意识行为有关的虚拟人面部图像合成技术。2.2虚拟人运动模型人体模型中各肢体之间存在一定的运动连带关系,将关节看成点,将关节之间的骨骼看成是链,就可以按照运动关系将各肢体链接起来。本文用树结构来表达人体模型的层次结构,如图2-1所示。图SEQ图\*ARABIC2-1基于关节的运动层次结构为了描述人体骨架模型中各关节之间的相对位置和姿态(简称位姿),在每个关节上固定一个局部坐标系,取关节轴线方向为x轴正方向,取上一关节和该关节的连线方向为y轴正方向,这样就可以用齐次坐标变换矩阵来描述这些坐标系之间的相对位置和方向。对于某一任务,运动的限定可用下述运动结构方程给出:公式2-1运动结构方程其中,表示从关节i的坐标系到关节i-1的坐标系的变换矩阵,是世界坐标系到基坐标系的变换矩阵,是目标坐标系到世界坐标系的变换矩阵。故人体的运动学设计问题可转化为求解关节模型的运动方程问题。基于人体运动生物力学和物理学的基础,可以从人体运动学和动力学两方面对虚拟人运动进行描述。基于运动系学的模型:人体运动学是描述人体运动的学科。它只讨论运动本身的细节,而不涉及产生运动的原因(内力和外力)。所谓基于运动学的模型是指物体的运动独立于产生运动的力,其参数包括物体的位置,速度和加速度。例如在H-Anim标准中,使用三类节点(Node)表示一个虚拟人体模型:分别是人体重心(Humanoin)人体关节(Joint)和人体骨骼段(Segment)并把整个人分成1个人体重心77个关节和47个骨骼段。在基于运动学的模型中,任何一个人体骨骼段的完整的运动学参数共需15个随时间变化的参量来形容,这些运动学参数主要包括人体骨骼段的体心位置,人体骨骼段的体心速度,人体骨骼段的体心加速度,人体骨骼段的角度,人体骨骼段角速度,人体骨骼段角加速度等。因此,人体运动参数是很复杂的,为了降低研究的复杂度,通常我们在对具体运动进行描述时,对其进行合理的简化,这样就可以只使用诸多运动参数的一小部分即可完成对此运动的描述了。目前,很多软件中关于虚拟人的运动模型都是基于运动学的,利用这些软件实现虚拟人的动画的过程中,需要用户交互设置一些关键参数,并通过插值这些关键参数来生成和控制物体的运动变化,并且这些参数的变化只涉及到各时刻各参数值的大小及其变化速度。通过以上分析,可以发现在基于运动学模型的虚拟人的动画技术中,只考虑了物体的运动学特性而没有考虑物体的动力学特性,并且代之以由用户交互确定一些关键参数来生成其运动,因此,可以说这种基于运动学模型的动画技术生成的运动是虚拟的,它并不能完全反映物体的真实运动,除非用户给定的关键参数及所采取的插值模式恰好符合物体的动力学特性。基于动力学的模型:人体动力学是对产生人体运动的力的研究。例如对于整个身体来说,其主要受到重力,地面反作用力或外力,肌肉力以及关节反作用力及骨与骨之间的作用力。所谓基于动力学的模型则是指物体的运动由它所受的力控制,有关运动参数完全由动力学方程决定。在现实世界中,物体的运动变化是由于其受力均衡状态被打破而形成的,因而,物体的运动与它和周围的环境的相互作用及外界对它施加的外力有关。事实上,物体的真实运动决定于其受力情况。基于动力学的模型的虚拟人动画技术是在建立虚拟人的动画模型时引入了物理规律,其目的是提高计算机动画的逼真性。与基于运动学的模型恰恰相反,从上述分析我们可以看出,基于动力学的模型有很多优势,其最主要的优势就是可以按照动画设计者的要求而运动。然而,基于动力学的模型的应用也存在很多的局限性。例如动力学方程的求解问题,通常我们无法得到动力学方程的封闭解析解,只能采用数值求解技术,而且尽管目前在数值计算领域已有众多的求解微分方程的数值计算方法,但找到适当的求解方法并不是一件容易的事。2.3虚拟人运动关键技术人体具有200个以上的自由度和非常复杂的运动,如何模拟这种运动一直是虚拟人研究中需要解决的重要课题之一。为了使虚拟人的动画更加自然,真实,在计算机动画中,已经发展了很多技术来实现。其中比较传统的运动控制方法有参数化关键帧技术,过程动画技术,另外比较常用的有基于物理的仿真技术以及目前在商业产品中比较流行的运动捕获技术,运动合成技术等。(1)参数关键帧:关键帧方法是控制虚拟人运动细节的传统方法。关键帧(keyframe)的概念来源于传统的卡通动画片制作。在早期的WaltDiseney的制作室,熟练的动画师设计卡通片中的关键画面,也就是所谓的关键帧,然后由一般的动画师设计中间帧。在3D计算机动画中,中间帧的生成由计算机来完成,插值代替了设计中间帧的动画师。所有影响画面图像的参数都可谓关键帧的参数,如位置、旋转角度等。从原理上讲,关键帧插值问题可归结为参数插值问题,传统的插值方法都可应用到关键帧方法中,但关键帧插值又与纯数学的插值不同,有其特殊性。为了很好地解决插值过程中的时间控制问题,Steketee等提出了用双插值的方法来控制运动参数,其中之一为位置样条,它是位置对关键帧的函数;另一条为运动样条,它是关键帧对时间的函数。关键帧插值系统中要解决的另一个问题是物体朝向的插值问题。物体的朝向一般可由Euler角来表示,因此朝向的插值问题可简单地转化为3个Euler角的插值问题,但Euler角又有其局限性,因为旋转矩阵是不可交换的,Euler角的旋转一定要按某个特定的次序进行;等量的Euler角变化不一定引起等量的旋转变化,而是导致了旋转的不均匀性;Euler角还有可能导致自由度的丧失。Shoemake[4]为了解决因采用Euler角表示引起的麻烦,最早把四元数引入到动画中,并提出了用单位四元数空间上的Bezier样条来插值四元数。Barr,Kim等人对该方法进行了应用。关键帧技术要求设计者除具有设计关键帧的技能外,还要特别清楚运动对象关于时间的行为。在应用参数关键帧技术产生虚拟人的运动时,应注意所插值的参数,否则会产生不恰当的运动。由于关键帧插值不考虑人体的物理属性以及参数之间的相互关系,因此插值得到的运动不一定是合理的,通常需要设计者对运动进行仔细的调整。尽管如此,由于关键帧技术的使用简便,因此仍然是最常用的动画生成方法。在技术上主要采用了插补算法和逆运动法。(2)过程动画技术:过程动画(ProceduralMethods)指的是用一个过程去控制物体的动画。过程动画技术在解决一些特殊类型的运动例如行走跑步等是十分有效的,通过使用这种方法,动画师只需要明确一小部分的参数例如速度行走的步长等,通过一个具体的过程就可以计算出每一时刻的姿势,过程动画技术较关键帧技术的优越性主要体现在两个方面:首先,可以很容易的生成一系列的相似的运动;其次,过程动画技术可以应用在一些用关键帧动画实现起来非常复杂的系统例如粒子系统。过程动画技术也可以产生群体运动,例如我们可以应用群体行为的算法来获得一群飞鸟的动画,当然也可以获得一群人的运动。在迪斯尼的一些动画片中,大多数的群体场景都使用了过程动画技术。过程动画技术的优点就是它具有生成交互性行为的潜力。例如在视频游戏中,可以预测在每种情况下的游戏者的动作反应,尽管关键帧技术也可以根据游戏者做出不同的反应,但是游戏者的反应是局限在一个反应库中。当然,过程动画技术也有一定的局限性:首先,利用过程动画很难定义一般,它只适用于某些特定类型的运动。其次,由于自动的本质决定了动画师不能在动画中进行很好的细节上的控制,因此也导致了角色动画运动缺乏表情或独特性。(3)基于物理的仿真技术:与关键帧技术不同,基于物理的仿真技术是利用动力学,生物力学等物理定律产生运动的。包括正向和逆向动力学原理(如图2-2)。我们通常采用有关节的基于动力学的模型来实现动态仿真,即构建角色的动力学模型,通过仿真计算它们的运动。这就意味着物体的运动受物理规律的支配,以便创作自然逼真的动画。基于物理的仿真技术优越于其它运动控制技术的优点主要表现在:首先,利用基于物理的仿真技术可以生成用关键帧技术无法实现的完全符合物理特性的理想的运动。基于物理的仿真技术在体育训练方面的应用最为广泛;其次,在与用户的交互方面,基于物理的仿真技术能实现比关键帧或是运动捕获技术更精确的交互。当然这种技术也有其不足之处,庞大的计算量是制约动态仿真技术发展的一个主要因素。通常,为了实现一个很好的仿真,需要使用多处理器且大虚拟内存及物理内存的计算机才能实现。另外,对于动画师来说,一方面由于采用基于物理的仿真技术产生的运动是通过计算机的仿真过程自动合成的,因此可以将动画师从许多低层次的运动细节和制作中解放出来;另一方面,由于操纵用动态仿真技术产生的虚拟人的运动没有利用其它技术产生的虚拟人的运动容易,因此,动态仿真技术对虚拟人的行为也有一定的限制。在技术上分为基于约束的方法和运动合成的方法。图2-2正向和逆向动力学原理(4)运动捕获技术:如图2-3所示,它是利用传感器以三维的形式记录人类主体的动作,然后计算机根据所记录的数据驱动屏幕上的虚拟人。这种方法的最大优点是能够捕捉到人类真实运动的数据,由于生成的运动基本上是主体人运动的复制品,因而效果非常逼真,且能生成许多复杂的运动。运动捕获技术也是目前在商业产品中比较常用的一种用来生成运动的技术。运动捕获技术是通过使用称为跟踪器的专门的传感器来记录运动者的运动信息,然后,我们就可以利用所记录下来的数据来产生动画运动。作为一种选择,我们也可以使用一种带有关节传感器的木偶来代替真人。运动捕获技术是目前相当流行的一种技术,这主要是因为它可以很容易的获得许多人体运动的数据。然而,也存在很多问题制约着这一技术成为一种理想的方法来解决所有的应用。首先,在运动捕获技术中,所获得的人体运动数据由于附着在运动者皮肤或是衣服上的跟踪器在运动者运动时会产生一定程序的移位,这就造成了所获得的运动数据有一定的冗余,在某些情况下,还会引起虚拟人的运动的一定程度的失真。例如,我们要捕获一个人将胳膊放在桌子上的动作,由于捕获数据的冗余,可能会导致计算机生成的虚拟人的手臂并没有放在桌子上而是悬浮于空中或是手臂穿透桌子等严重失真的情况。其次,由于一些用于捕获运动的技术本身的局限性导致一些运动不能被捕获。一类传感器是磁的,而且金属会对捕获的数据产生一定的干扰。还有一些传感器要求被捕获者连到计算机上,因此限制了被捕获者的运动。另外一类传感器是光学的,这类传感器在使用时,容易使被捕获者身体的运动数据混淆。尽管运动捕获技术中还存在一些不足,但是鉴于运动捕获技术可以自动的捕获人体运动的细节,因此,这项技术仍然得到了广泛的应用,举个例子来说明这项技术优越于其它技术的地方,我们用运动捕获技术捕获几个不同的人走路姿势,当用计算机处理后,我们可以很容易的分辨出虚拟人的走路姿势是属于哪个人的。图2-3用运动捕获技术控制虚拟人的运动(5)运动编辑:从本世纪90年代开始,运动的存储和重利用问题引起了普遍的关注。运动编辑技术主要解决利用motioncapture等技术所捕获的运动的重利用问题。应用以上的运动控制技术,可以生成大量逼真的运动片段,如何存储这些不同的运动片断并将它们重利用,是目前研究的重点。由于人体运动复杂性,导致了运动的方式也千变万化。在已存储的运动的基础上,生成更为复杂的虚拟人运动,是应用运动编辑技术的目的。2.4小结本章主要介绍了国内和国外对于虚拟人研究技术的现状,介绍了虚拟人运动模型的概要内容,并对现今虚拟人控制技术作了一个总的介绍,并对各项技术的优缺点作了分析。第3章DIRECTX技术3.1概述MICROSOFT公司的DIRECTX包含了编制高级计算机游戏和多媒体应用程序的最新技术和工具,提供了一整套应用程序接口API,包括:通过支持访问平台现实内存中位图的软硬件加速技术,可利用硬件的位块传输和缓冲区翻转功能快速直接存取的DIRECTDRAW,软硬件声音混合和录音再生功能的DIRECTSOUND,使动画在调制解调器和网络之间的连接更加简单方便的DIRECTPLAY,实现一个完全的三维图形系统的高级保留模式和使程序控制着色管道的低级立即模式DIRECT3D,基于WINDOWS的图形图象,游戏输入的API和驱动程序,不仅支持目前的键盘,鼠标和操纵杆,也支持WINDOWS将来的输入设备的DIRECTINPUT,提供DIRECTX的安装过程的DIRECTSETUP等六个组件。利用DIRECTX可以获得硬件独立性的优点,可以直接访问硬件,又可以不考虑添加新硬件带来的识别问题。同时,DIRECTX在硬件而后应用之间提供了一致的接口以减少安装和配置的复杂性,通过DIRECTX可以容易地获得硬件的能力。另外,随着4D加速芯片的发展,各芯片生产商纷纷宣布DIRECTX的全面支持与优化。因此,DIRECTX是WINDOWS环境下开发高性能三维应用程序的较为理想的工具。DIRECTX结构如图3-1所示,其硬件抽象层(HAL)紧紧包围了硬件层,而硬件模拟层(HEL)则给开发人员提供了一组必要的,相互独立的接口。有了DIRECTX可对显卡硬件直接进行操作,利用显卡的硬件功能来完成对屏幕的采样并对显存中的数据进行实时处理,这样可以获得最小的延迟。图3-1DIRECTXHAL/HEL结构3.2DIRECTX3D对象及设备3.2.1DIRECTX对象(D3DObject)1.关于D3D对象微软DIRECTX是基于COM的对象和接口的,Direct3D编程的第一步必须建立这个对象。而且程序结束后,必须最后释放该对象。2.建立D3D对象在DirectX8.0中,你可以用如下代码建立一个D3D对象:#include<d3dx8.h>//必须包含的头文件#include<mmsystem.h>LPDIRECT3D8g_lpD3D=NULL;//D3D对象指针,以后经常用到if(NULL==(g_lpD3D=Direct3Dcreate8(D3D_SDK_VERSION)))//D3D_SDK_VERSION确保该对象建立正确的头文件上,目前只能用该值returnE_FAIL;3.2.2DIRECTX设备(D3DDEVICE)1.D3D设备的定义一个D3D设备接口可以简单的认为是本机一块显卡的抽象,它包含了显卡所有的硬件参数及状态值,比如说,显卡显存的数量和起始的线性地址,是否支持深度缓冲(DepthBuffer),雾化(Fog),纹理(Texture)及MipMap等。2.D3D设备的功能在D3D编程中,一个D3D设备接口主要能完成以下的功能模块:a.转换功能(Transformation):主要完成对3D模型数据的转换,例如,世界转换(Worldtransformation),视转换(Viewtransformation),投影转换(Projectiontransformation)。b.灯光照明功能:完成对场景的灯光渲染,例如,设置环境光,方向光等。c.光栅化显示功能:根据设置的一些3D状态参数和当前屏幕显示模式以及剪切等情况,将3D图形在屏幕上显示出来。3.D3D设备的类型在DirectX8.0中,支持三种类型的D3D设备:硬件抽象层设备,参比设备,软件模拟设备,每一种设备可以认为是一种独立的3D驱动程序,但也各有用途和优势,分为:a.硬件抽象层设备(HALDevice):D3D中最主要的设备类型,基于显卡的硬件功能,具有很快的3D硬件加速功能,能执行硬件或软件的顶点数据处理。缺点是必须有3D显卡支持,而且,并不是每种显卡都支持所有的3D功能,所以在使用该设备时,必须经常查询显卡支持的功能,对不支持的用软件设备来模拟。b.软件模拟设备(SoftwareDevice):顾名思义,是用软件的方法来模拟3D的一些功能。依赖于一些特殊的CPU指令集(比如,AMD3D-Now,IntelMMX指令集),软件模拟设备也能获得较高的3D性能。而且软件模拟设备具有硬件抽象层设备一样的函数接口,使用方便。缺点是大量占用CPU资源,运行速度较慢,只适合同硬件抽象层设备配合使用。c.参比设备(ReferenceDevice):是微软Direct3D支持的一种附加设别类型,它也依赖于特殊的CPU指令集,但同软件模拟设备相比,它更注重模拟的精确性,而不是速度方面。所以它一般应用于对3D硬件的测试和硬件功能的演示上。4.建立D3D设备在DirectX8.0中,建立一个D3D设备需要到用IDirect3D8接口中的CreateDevice函数,该函数原型如下HRESULTCreateDevice(UINTAdapter,D3DDEVTYPEDeviceType,HWNDhFocusWindow,DWORDBehaviorFlags,D3DPRESENT_PARAMETERS*pPresentationParameters,IDirect3DDevice8**ppReturnedDeviceInterface);//该段代码建立一个基于Window窗口程序的D3D硬件抽象层设备,采用软件的顶点数据处理,并使用16Bits的深度缓冲区。D3DDISPLAYMODEd3ddm;HRESULThr=0;hr=g_pD3D->GetAdapterDisplayMode(D3DADAPTER_DEFAULT,&d3ddm);if(FAILED(hr))returnE_FAIL;D3DPRESENT_PARAMETERSd3dpp;ZeroMemory(&d3dpp,sizeof(d3dpp));d3dpp.Windowed=TRUE;//指明是窗口模式,而非全局独占模式d3dpp.SwapEffect=D3DSWAPEFFECT_DISCARD;//无需交换链d3dpp.BackBufferFormat=d3ddm.Format;//后备缓冲区颜色格式d3dpp.EnableAutoDepthStencil=TRUE;//使深度缓冲区有效d3dpp.AutoDepthStencilFormat=D3DFMT_D16;//深度缓冲区颜色格式//CreatetheD3DDevicehr=g_pD3D->CreateDevice(D3DADAPTER_DEFAULT,//使用当前显卡作注设备D3DDEVTYPE_HEL,//设备类型hWnd,//该程序所在的窗口句柄D3DCREATE_SOFTWARE_VERTEXPROCESSING,//用软件的方法处理顶点数据&d3dpp,//指向上面的结构&g_pd3dDevice)))//指向3D设备的指针if(FAILED(hr)){returnE_FAIL;}3.3矩阵(Matrices)3.3.13D迪卡尔坐标系统和矩阵定义1.3D迪卡尔坐标系统2D坐标系统只有x轴与y轴,因为它是平面的。而在3D空间里,两个轴显然不够用了,所以,有了第三个轴:z轴。图3-2演示了左手3D迪卡尔坐标系统是如何工作的。图3-2左手3D笛卡尔坐标系统2.矩阵的定义由m×n个数排成m行n列,并括以方括弧(或圆括弧)的数称为m行n列矩阵,简称m×n矩阵。简要概括的讲,矩阵就像是一个表格,有一定数目的行与列;每个格子中都一个数字或表达式。通过特定的矩阵,我们可以对3D对象中的顶点坐标进行运算,来实现类似移动、旋转、缩放这样的操作。在DirectX中,矩阵就是4X4的数表。3.3.2矩阵变换要改变一个顶点的x,y与z值,你应该把它们与某个矩阵相乘。图3-3演示了顶点是怎样与矩阵相乘的。图3-3顶点通过矩阵变换这其实是一种简单的计算,只需要将x,y和z值分别与每列上的数相乘再相加,每列上得出的数都是新顶点的一个坐标值,这在上图中是显而易见的。你可能已经注意到我们上面的图例中在当前顶点(currentvertex)的z值后面还有一个“1”,那是为了给矩阵的运算提供可行性和方便性的(最好参看一下相关的数学资料)。需要同样数表来完成矩阵变换。所以,我们只需操作矩阵就能完成这些类似旋转、缩放或移动的变幻。幸运的是,DirectX给我们提供了一些函数能方便地生成一些通常的矩阵。那末,如何完成即缩放又旋转(复合变换)的变幻呢?首先,我们需要两个矩阵:一个用来旋转的一个用来缩放的;然后,我们把两个矩阵相乘,得出一个新的复合矩阵,即缩放又旋转的矩阵;然后利用这个新的矩阵来变幻顶点。应该注意的是,矩阵相乘并不是普通的乘法,而且,也不满足交换率:矩阵AX矩阵B和矩阵BX矩阵A是不相等的。下面的图3-4演示了怎样把两个矩阵相乘:图3-4矩阵相乘要把两个矩阵相乘,需要把第一个矩阵的每一行和第二个矩阵的每一列都相乘。在上面的例子中,我们把第一个矩阵的第一行的每个元素与第二个矩阵的第一列的对应元素相乘,然后把得出的四个结果相加,按此方法,我们得出了新矩阵的第一行的四个元素(Column1-4),其它元素的计算方法依此类推。这可能看起来有些复杂,不过,DirectX提供了一些矩阵操作的函数,所以不要对此担心。3.3.3场景变换矩阵1.WorldMatrix(世界矩阵)我们可以利用世界矩阵在3D空间(世界空间)里通过修改对象的坐标来完成它们的旋转、缩放或平移操作。所有这些操作(变换)都是关于原点(0,0,0)的。单一的变幻(例如平移或缩放等)可以组合起来,形成更复杂的变幻;但要注意各种变幻的顺序很重要,矩阵1X矩阵2和矩阵2X矩阵1是不同的。还有,当你完成了一项世界变幻的矩阵操作时,矩阵跟着将转变所有的顶点。要旋转两个对象,一个关于x轴,一个关于y轴,你应该先完成x轴的变幻,然后渲染第一个对象;再完成y轴的变幻,然后渲染第二个对象。世界矩阵有时候需要自己填写,根据各种变换需要来填写一个D3DXMATRIX结构体。之后通过调用IDirect3DDevice9::SetTransform(D3DTRANSFORMSTATETYPEState,CONSTD3DMATRIX*pMatrix)设置世界矩阵为填好的那个。其中参数意义如下:D3DTRANSFORMSTATETYPEState代表你要设置的变换类型。D3DTS_WORLD,D3DTS_VIEW,D3DTS_PROJECTION分别表示世界,视图,投影三种变换。CONSTD3DMATRIX*pMatrix指向一个矩阵结构的指针,即所要用到的矩阵。后面的两个矩阵也要通过此函数设置。D3D中,三个矩阵是要存放在固定位置的,D3D依次从这三个位置读取矩阵信息,并乘以所有的点,得到新的点的坐标,这个过程是不用我们操心的。我们调用SetTransform()就是要把填充好的矩阵放进这三个位置中的某一个,第一个参数表示了哪一个。2.ViewMatrix(视图矩阵)视图矩阵就是摄像机(或眼睛)。摄像机在世界空间中有一个位置,还有一个观察点。例如,你可以把摄像机悬置于某个对象的上面(摄像机位置),把镜头对准那个对象的中心(观察点)。你也可以指定哪面是上面,在我们下面的例子中,我们指定了y轴的正方向是上面。在设置视图矩阵时,先要很清楚地建立好“视图坐标系”。这个坐标系以观察着为原点,沿着视线方向(观察者—注视点方向)为纵深方向(也就是Z轴方向)。仅有两个点还不足以确定一个三维坐标系,我们还需要一个参考点,能与另两个点构成某一个坐标平面。这样的坐标系构件起来后,就可以根据两个坐标系的变换填充视矩阵了。D3D提供了函数:D3DXMATRIX*D3DXMatrixLookAtLH(D3DXMATRIX*pOut,CONSTD3DXVECTOR3*pEye,CONSTD3DXVECTOR3*pAt,CONSTD3DXVECTOR3*pUp);或D3DXMATRIX*D3DXMatrixLookAtLH(参数同),区别仅在于前者用于左手系而后者用于右手系。该函数自动填充一个矩阵,参数依次是将要填充的矩阵以及上面说到的三个点,这里三个点构成视坐标系的YOZ平面。然后再调用SetTransform()把这个矩阵交给D3D。经过上一步被统一了坐标的各个顶点将被这个矩阵转到视图坐标中。3.ProjectionMatrix(投影矩阵)投影矩阵可以被想象成摄像机的镜头,它指定了视界(fieldofview)和前、后裁剪平面。这个矩阵将越近的点放得越大。填充这个矩阵我们用函数:D3DXMATRIX*D3DXMatrixPerspectiveFovLH(D3DXMATRIX*pOut,FLOATfovY,FLOATAspect,FLOATzn,FLOATzf);或D3DXMATRIX*D3DXMatrixPerspectiveFovLH(参数相同),区别同上面一样。第一个参数仍然是输出矩阵。第二个描述了在Y轴上的视角,弧度制表示,可以想象,视角越大,近端被拽拉的比例就越大。下一个参数是视图区的长宽比。后面两个参数就是最近视平面和最远视平面的位置,用它们的Z坐标(Z坐标的值在投影变换前后是不变的)表示。3.4在DIRECTX3D中使用网格模型复杂的几何模型通常是由3D建模软体创建并保存到文件中。例如.x文件就是这样的一种格式,MicrosoftDirect3D使用的网格模型都是载入这些文件中的对象。即使模型有些复杂,但在MicrosoftDirect3D中包含的函数建立使用它是非常容易,在这里介绍一下网格模型如何载入渲染,得到我们所需的效果,并且如何对其进行释放。这里将分为载入,渲染和释放三个步骤。3.4.1载入一个网格模型对象一个MicrosoftDirect3D的应用程式在使用网格模型对象之前必须进行初始化,在这里调用InitGeometry函数用于载入一个网格模型,这是一个应用程式定义的函数,在载入必要的Direct3D对象(系统初始化)后调用。一个网格模型需要材质缓冲,将存储要使用的材质以及纹理。函数在开始先声明一个材质缓冲如同以下的代码片段:LPD3DXBUFFERpD3DXMtrlBuffer;下面这部分使用D3DXLoadMeshFromX的方法来载入网格模型://从指定文件中导入.X文件if(FAILED(D3DXLoadMeshFromX("tiger.x",D3DXMESH_SYSTEMMEM,g_pd3dDevice,NULL,&pD3DXMtrlBuffer,&g_dwNumMaterials,&g_pMesh)))returnE_FAIL;第一个参数D3DXLoadMeshFromX从一个指向字符串的指针获得需要MicrosoftDirectX载入的文件名。第二个参数告诉Direct3D如何创建网格模型。这里使用了D3DXMESH_SYSTEMMEM标记,相当于指定了D3DXMESH_VB_SYSTEMMEM和D3DXMESH_IB_SYSTEMMEM这两个。这两个标记告诉Direct3D将网格模型的索引缓冲(indexbuffer)和顶点缓冲(vertexbuffer)存放于系统存储器。第三个参数是一个指针,指向Direct3D设备,这也是将用于模型渲染。第四个参数是指向一个ID3DXBuffer对象的指针,这个对象将填满关于相邻每一个面的信息。这里设置为NULL。第五个参数也同样指向一个ID3DXBuffer对象,在这个函数完成之后,这个对象将填满模型的D3DXMATERIAL结构数据。第六个参数指向一个整形变量,当函式返回时保存D3DXMATERIAL结构的数量于ppMaterials列队中。第七个参数返回一个指向网格模型对象的地址,返回所载入的模型数据。在载入模型对象和材质信息后,需要从材质缓冲中筛选出材质属性和纹理名称。首先,取得指向材质缓冲,下面的代码展示了如何取得指针数据:D3DXMATERIAL*d3dxMaterials=(D3DXMATERIAL*)pD3DXMtrlBuffer->GetBufferPointer();下面的代码创建新的模型和根据材质中模型所统计的纹理对象:g_pMeshMaterials=newD3DMATERIAL8[g_dwNumMaterials];g_pMeshTextures=newLPDIRECT3DTEXTURE8[g_dwNumMaterials];为模型中每一个材质执行下面的步骤:第一步,拷贝材质,代码如下:g_pMeshMaterials[i]=d3dxMaterials[i].MatD3D;第二步,为材质设置环境颜色,代码如下:g_pMeshMaterials[i].Ambient=g_pMeshMaterials[i].Diffuse;最后一步,为材质创建纹理贴图,代码如下://创建纹理if(FAILED(D3DXCreateTextureFromFile(g_pd3dDevice,d3dxMaterials[i].pTextureFilename,&g_pMeshTextures[i])))g_pMeshTextures[i]=NULL;}在载入每一个材质之后,完成材质缓冲并需要释放它的调用Release()。pD3DXMtrlBuffer->Release();3.4.2渲染一个网格模型对象在第一步里,模型已经载入并准备好用于渲染,模型载入后,它是以每一个材质分开存放在一个子集中,需要对每个子集进行渲染,模型是在一个循环中渲染。第一步,在循环里为子集设置材质,参看下面代码片段:g_pd3dDevice->SetMaterial(&g_pMeshMaterials[i]);第二步,在循环里为子集设置纹理,参看下面代码片段:g_pd3dDevice->SetTexture(0,g_pMeshTextures[i]);在设置好材质和纹理后,子集通过调用ID3DXBaseMesh::DrawSubset函数的方法来绘制,参看下面代码片段:g_pMesh->DrawSubset(i);DrawSubset函数方法通过一个DWORD参数指定哪个子集用于模型绘制,本例中使用一个增加的变量在每一个时间里循环执行。使用模型之后,完全释放模型所使用的内存是很重要的,这是第三步要做的事情。3.4.3释放一个网格模型对象在所有MicrosoftDirectX程式完成后,需要查找所有的DirectX对象指针是在使用中还是无效,在本例中模型对象同样也需要如此,当程式接收到WM_DESTROY消息,这里调用Cleanup函式,这是一个应用程式定义的函数。下面的代码用来释放材质列表:if(g_pMeshMaterials)delete[]g_pMeshMaterials;下面的代码分别将每一个纹理进行释放并删除纹理列表:if(g_pMeshTextures){for(DWORDi=0;i<g_dwNumMaterials;i++){if(g_pMeshTextures[i])g_pMeshTextures[i]->Release();}delete[]g_pMeshTextures;}下面的代码片段检测并释放模型对象://删除网格对象if(g_pMesh)g_pMesh->Release();3.5DIRECTINPUT由于涉及到对虚拟人的控制问题,这里还需要介绍一下DIRECTINPUT技术中的键盘编程问题。首先,必须创建一个DirectInput8对象,就像这样:LPDIRECTINPUT8pInput;DirectInput8Create(GetModuleHandle(NULL),DIRECTINPUT_VERSION,IID_IDirectInput8,(void**)&pInput,NULL);然后,需要创建一个DirectInput设备:LPDIRECTINPUTDEVICE8pDev; pInput->CreateDevice(GUID_SysKeyboard,&pDev,NULL);设置好它的数据格式:pDev->SetDataFormat(&c_dfDIKeyboard);设置它的协作级,这里设为独占设备+前台:pDev->SetCooperativeLevel(hwnd,DISCL_EXCLUSIVE|DISCL_FOREGROUND);获取设备:pDev->Acquire();像上面那样初始化后,Windows对键盘的控制权就被剥夺了,以后的键盘消息将不会被送入消息循环,我们可以把消息循环中处理键盘消息的语句拿掉了。当然,这时我们需要在程序的适当地方,比如说在刷新游戏时,加入对键盘数据进行读取和处理的语句,就像下面的一段程序:#defineKEYDOWN(key)(buffer[key]&0x80)//定义一个宏,方便处理键盘数据charbuffer[256];//键盘数据pDev->GetDeviceState(sizeof(buffer),(LPVOID)&buffer);//得到键盘数据if(KEYDOWN(DIK_XXX))//如果XXX键被按下…(请参阅附录二){ ……//处理之} ……//处理其它键3.6小结在这一章里主要通过代码的形式介绍了一些DIRECTX常用的技术和方法,包括3D空间的坐标问题,矩阵的变换,.X模型的导入和基本的DIRECTINPUT控制技术,在最后讲述了一些DIRECTINPUT的键盘编程方法,这些为以后的程序作一个基础。第4章用DIRECTX设计实现虚拟人运动控制4.1虚拟人造型4.1.1用3DMAX建模3DSMAX是Autodesk公司开发的高性能三维动画制作软件,具有强大的三维图形造型能力和动画制作能力。3DSMAX有20种基本的3D对象,包括标准几何体(standardprimitives)和扩展几何体(extendedprimitives),另外还可以利用2D图形创造复杂的3D模型,并且可以对这些3D模型进行各种变形(如连接、分散、布尔运算等)以组合成更为复杂的三维图形。3DSMAX可以指定物体的运动路径,变形方式实现动画效果,但其生成的动画只能按预先设定好的方式变化,在此过程中无法干预,即不能实现实时控制。所用的虚拟人通过3DSMAX建模,生成.3ds文件,如图4-1所示:图4-1虚拟人建模4.1.2虚拟人数据导出通过3DSMAX建模之后,需要解决的是模型导出问题,可以通过conv3ds软件来将.3ds文件转化为.x文件,这里通过命令行的方式来运行conv3ds,转换如图4-2:图4-2.3ds文件转换为.x文件4.1.3虚拟人数据结构1.X文件简介在D3D中,X文件主要是用来存储网格数据的,当然不光是网格数据,它还用来存储有关纹理,动画及用户定义的对象的一些数据X文件是模板驱动(Template-Driven)[5]的,也就是说它存储数据的格式是基于模板的.这使得这种文件格式具有结构自由,内容丰富,易应用,可移植性高等优点。2.X文件中的模板(Template)模板定义了数据流是怎样被格式化的,也就是告诉你对于一个3D模型的各种数据,它们是以什么格式存放在数据流中的(这里指文件)。a.模板的格式在X文件中,一般会有如下所示的格式:template<template-name>{//模板名<UUID>//一个全局唯一ID,用来唯一标识该模板<member1>;//成员变量1...<membern>;//成员变量n[restrictions]//模板约束,下面会提到}b.模板约束根据模板约束的不同形式,可将模板分成以下三类:(a).开放式模板(OpenTamplate)开放式模板指除了模板本身定义的成员变量外,还可以向模板中添加其他的成员变量,来达到定制模板的目的。下面是一个开放式模板实例:templateMesh{<3D82AB44-62DA-11cf-AB39-0020AF71E433>DWORDnVertices;arrayVectorvertices[nVertices];DWORDnFaces;arrayMeshFacefaces[nFaces];[...]//该字符串表明该模板为开放式模板}(b).约束模板(RestrictedTamplate)与开放式模板相比,只能向约束模板中添加有限几种类型的数据成员,这些数据类型由模板枚举出来,下面是一个开约束模板实例:templateFileSystem{<UUID>STRINGname;[Directory<UUID>,File<UUID>]//表明为约束模板}(c).封闭式模板(ClosedTamplate)与上面两种类型的模板相比,封闭式模板的数据成员是固定的,不能向里面添加另外的成员。下面是一个封闭式模板实例:templateVector{<3D82AB5E-62DA-11cf-AB39-0020AF71E433>FLOATx;FLOATy;FLOATz;}//封闭式模板c.模板类型//标题模板,给出一些附加的X文件信息,如版本信息。templateHeader{//标题模板,给出一些附加的X文件信息,如版本信息。<3D82AB43-62DA-11cf-AB39-0020AF71E433>WORDmajor;//大版本号WORDminor;//小版本号DWORDflags;}//向量模板,定义一个向量(x,y,z)templateVector{<3D82AB5E-62DA-11cf-AB39-0020AF71E433>FLOATx;FLOATy;FLOATz;}//颜色模板,定义一带alpha的颜色值templateColorRGBA{<35FF44E0-6C7C-11cf-8F52-0040333594AFLOATred;FLOATgreen;FLOATblue;FLOATalpha;}//颜色模板,定义一不带alpha的颜色值templateColorRGB{<D3E16E81-7835-11cf-8F52-0040333594A3>FLOATred;FLOATgreen;FLOATblue;}//材质模板,定义材质属性templateMaterial{<3D82AB4D-62DA-11cf-AB39-0020AF71E433>ColorRGBAfaceColor;//材质颜色FLOATpower;//高亮光强度ColorRGBspecularColor;//高亮光颜色ColorRGBemissiveColor;//发散光颜色[...]//可添加其他成员}//网格面模板,定义网格中的一个面(即图元,还记得网格的概念吗)templateMeshFace{<3D82AB5F-62DA-11cf-AB39-0020AF71E433>DWORDnFaceVertexIndices;//该面包含的定点数arrayDWORDfaceVertexIndices[nFaceVertexIndices];//面的顶点数据索引列表}//网格模板,定义网格数据格式templateMesh{<3D82AB44-62DA-11cf-AB39-0020AF71E433>DWORDnVertices;//网格顶点数arrayVectorvertices[nVertices];//网格顶点数据列表DWORDnFaces;//网格面数arrayMeshFacefaces[nFaces];//网格面的数据列表[...]//可添加其他成员}3.X文件格式D3D的X文件拥有自己的一套完整的语法规则,以下是一个完整X文件,它存储了一个正方形网格的数据。该正方形有两个面,一面为红色,一面为蓝色。1xof0302txt0064234567Header8{91;100;111;12}1314MaterialFace1Material//Material115{161.0;0.0;0.0;1.0;;//红色170.0;180.0;0.0;0.0;0.0;;190.0;0.0;0.0;0.0;;2021}2223MaterialFace2Material//Material224{250.0;0.0;1.0;1.0;;//蓝色260.0;270.0;0.0;0.0;0.0;;280.0;0.0;0.0;0.0;;2930}3132MeshFace33{344;//该网格包含四个顶点35-1.0;-1.0;0.0;,//顶点0坐标36-1.0;1.0;0.0;,//顶点1坐标371.0;1.0;0.0;,//顶点2坐标381.0;-1.0;0.0;;//顶点3坐标39402;//该网格包含两个面414;0,1,2,3;,//网格正面,4表示该面有四个顶点,后面是顶点数据的索引424;3,2,1,0;;//网格反面4344MeshMaterialList//材质列表,为每个面分配一个材质45{462;472;480,1;;49{Face1Material}50{Face2Material}51}5253}a.第1行,x文件的标题xof表明该文件类型是X文件0302表明该文件大版本号为03,小版本号为02,该版本号一般不会变txt表明该文件为文本文件,同样"bin"为二进制文件,"tzip"为压缩文本文件,"bzip"为压缩二进制文件。0064表明使用64位的浮点数。同样,0032表示使用32位的浮点数。注意:该标题字符串必须放在X文件的第一行。b.第3-4行,注释在X文件中,符号"//"或"#"用来表示注释。c.第7-12行,该文件的标题模板数据该模板数据同最前的标题字符串相对应,用来说明该文件的一些信息。d.第14-30行,定义了两个材质,分别具有红色和蓝色属性。在模板的数据中,要注意逗号和分号的使用。这方面的内容可查SDK的文档。e.第32-53行,给出了该网格的模板数据,可参见注释。4.2使用DIRECTX实现虚拟运动控制4.2.1关键帧的设计关键帧法是对人体模型的关节参数进行插值计算,考虑到运动控制的实时需要,这里主要用前一帧和后一帧直线连接的方法。对于参数插值来说,运动主体的状态变量是一组“参数”,其运动的规律也是由插值计算得到的,即运动是由关键帧来说明的。每一个关键帧都有一系列的控制点对应于其它关键帧的控制点。本系统中插值法的应用主要是对运动链上各关节的初始位姿与利用逆运动学所得的关节的旋转角进行插补,形成中间画面。例如:对人体胳膊的动作可用它在某个时刻上的角度a来描述。如起始是a=10度;1秒钟后,a=20度;5秒钟后,a=45度;8秒钟后,a=100度。对角度参数a进行线性插值计算每隔1/30秒的a角。当t=1/30,a=10+(20-10)/2*1/30=10.1666。关键帧设计如图4-3:图4-3虚拟人24幅关键帧4.2.2平移实现行走在这里介绍一下计算机图形学的平移公式,设Tx,Ty,Tz是物体在三个坐标方向上的移动量,则有公式:x′=x+Txy′=y+Tyz′=z+Tz公式4-1平移公式矩阵运算表达为:[x′y′z′1]=[xyz1]与此相对应,DIRECT3D提供了D3DXMatrixTranslation函数来实现坐标的平移变换,函数原型下:D3DXMATRIX*D3DXMatrixTranslation(D3DXMATRIX*pOut,FLOATx,FLOATy,FLOATz,);其中参数一是平移操作矩阵的指针,剩下的三个参数分别是相对当前坐标x,y,z的偏移量。通过对虚拟人物体各个顶点的变换,就可以生成类似行走的效果。4.2.3旋转实现转弯旋转分为三种基本旋转:绕z轴旋转,绕x轴旋转,绕y轴旋转。在下述旋转变换公式中,设旋转的参考点在所绕的轴上,绕轴转θ角,方向是从轴所指处往原点看的逆时针方向。1.绕z轴旋转的公式为:x′=xcosθ-ysinθy′=xsinθ+ycosθz′=z公式4-2绕Z轴旋转公式矩阵运算的表达为:[x′y′z1]=[xyz1]在DIRECT3D中,使用D3DXMatrixRotationZ进行Z轴的旋转,原型如下:D3DXMATRIX*D3DXMatrixRotationZ(D3DXMATRIX*pOut,floatangle);其中参数一是旋转矩阵的指针,下一个参数为绕Z轴旋转角度。2.绕X轴旋转的公式为:x′=xy′=ycosθ-zsinθz′=ysinθ+zcosθ公式4-3绕X轴旋转公式矩阵运算的表达为:[x′y′z′1]=[xyz1]与绕Z轴相似,在DIRECT3D中用D3DXMatrixRotationX进行X轴的旋转。原型如下:D3DXMATRIX*D3DXMatrixRotationX(D3DXMATRIX*pOut,floatangle);参数一与上相同,参数二为绕X轴的旋转角度。3.绕y轴旋转的公式为:x′=zsinθ+xcosθy′=yz′=zcosθ-xsinθ公式4-4绕Y轴旋转公式矩阵的运算表达式为:[x′y′z′1]=[xyz1]D3D中使用D3DXMatrixRotationY进行绕Y轴的旋转。原型如下:D3DXMATRIX*D3DXMatrixRotationY(D3DXMATRIX*pOut,floatangle);参数二为绕Y轴的旋转角度,参数一与上相同。基于这几种基本的旋转变换,通过矩阵的相乘,可以实现更为复杂的旋转。对于虚拟人来说,即是通过对人本身坐标轴的旋转来达到使虚拟人转弯的目的。在D3D中,也提供了矩阵相乘的方法D3DXMATRIX*D3DXMatrixMultiply(D3DXMATRIX*pOut,CONSTD3DXMATRIX*pM1,CONSTD3DXMATRIX*pM2);其中参数一是最终输出矩阵的指针,参数二,三为相乘矩阵,这里要注意的是矩阵相乘要注意顺序。4.2.4程序的构造和流程为了读取数据,需要使用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。函数D3DXLoadSkinMeshFromXof将读取skinmesh与所有的余下的数据。仅给它一个指向IDirectXFileData接口的指针并且它将做余下的工作。函数D3DXLoadSkinMeshFromXof将返回一个指向ID3DXSkinMesh对象的指针。这个对象包含skinmesh。在内部,这个对象包含mesh数据作为组(group)。每个组(group)被一个不同骨架的设置变换。函数将也返回一个材质数据由skinmesh使用。D3DXLoadSkinMeshFromXof返回一个缓冲区包含影响mesh的所有骨架的名字。它也给予其它缓冲区包含它们的变换。这里将使用名字为指定的骨架查遍我们的框架分层结构。骨架变换有点让人混乱。假定变换不在这里被包含在框架里。事实上,这个变换是骨架偏移(boneoffset)。那么骨架偏移又是什么呢?重要的知道skinmesh的所有顶点是被存储在相对于一个原点,它是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对象。这个对象在它的原型里包含skinmesh。这个对象为渲染skinmesh没有任何机能。因此,需要首先转换mesh进入一个ID3DXMesh对象。函数ConvertToBlendedMesh将做这工作。虽然它是相同的对象被用于渲染静态mesh,ID3DXMesh获得从ConvertToBlendedMesh里有区别它的顶点包含混合权,因此所需要做的是启用顶点混合并且在调用ID3DXMesh的DrawSubset方法以前设置我们的骨架矩阵。象前面提到的一样,mesh将被分裂进入组或子对象。每个子对象应该与一个指定的材质和一个指定的骨架设置一起被渲染。结构D3DXBONECOMBINATION指定材质和骨架被用于一个mesh的单个子对象。结构的数组也从ConvertToBlendedMesh函数里获得。然后要做的是循环通过这个数组,设置材质与骨架然后调用ID3DXMesh的DrawSubset方法给予它在数据里的下标。动画在X文件里不是为skinmesh特定使用的;它们能被应用于在X文件里的任何框架。X文件存储关键帧框架并且应用程序应该产生在框架使用线性插值中间。动画关键帧有四种类型,旋转,缩放,位置,和矩阵关键帧。旋转是被存储作为四元法(quaternions)并且能被球状线性插值(sphericallinearinterpolation)进行插值运算。函数D3DXQuaternionSlerp由D3DX提供实现球状线性插值。为了在skinmesh里实现动画,我们需要添加一个新的类。我们把这个类命名为CAnimationNode。这个类将包含动画关键帧和一个指向目标框架的指针一起。这个类也包含一个用从动画关键帧里在新的时间值上获得的矩阵来更新目标框架的变换矩阵的SetTime函数。CAnimationNode的每个实例将包含动画模版的单个实例的数据。程序流程图如下所示:CobjectAttachChild()DetachChild()GetNextSibling()CmeshNodeGenerateBlendedMesh()FindBones()Render()CframeNodeLoad()Update()FindBones()Render()MeshesCanimationNodeLoad()SetTime()FindBone()pTargetFrameCskinMeshCreate()FindBones()Render()RootFrameAnimation大略代码如下:CSkinMesh::Create()BeginInitializeXfileAPIRegisterD3DRMtemplatesOpentheXfileForeverytopleveltemplateintheXfileBeginRetrievetheXfiledataobjectPassthedataobjecttoRootFrame.LoadEndLinkthebonestotheskinmesh(es)LinkthebonestotheanimationsEndCFrameNode::Load()BeginCheckthetypeofthedataobjectIfthetypeisMeshBeginCreatenewCMeshNodeobjectAttachthenewobjecttothe

温馨提示

  • 1. 本站所有资源如无特殊说明,都需要本地电脑安装OFFICE2007和PDF阅读器。图纸软件为CAD,CAXA,PROE,UG,SolidWorks等.压缩文件请下载最新的WinRAR软件解压。
  • 2. 本站的文档不包含任何第三方提供的附件图纸等,如果需要附件,请联系上传者。文件的所有权益归上传用户所有。
  • 3. 本站RAR压缩包中若带图纸,网页内容里面会有图纸预览,若没有图纸预览就没有图纸。
  • 4. 未经权益所有人同意不得将文件中的内容挪作商业或盈利用途。
  • 5. 人人文库网仅提供信息存储空间,仅对用户上传内容的表现方式做保护处理,对用户上传分享的文档内容本身不做任何修改或编辑,并不能对任何下载内容负责。
  • 6. 下载文件中如有侵权或不适当内容,请与我们联系,我们立即纠正。
  • 7. 本站不保证下载资源的准确性、安全性和完整性, 同时也不承担用户因使用这些下载资源对自己和他人造成任何形式的伤害或损失。

评论

0/150

提交评论