【3D技术宅公社】XR数字艺术论坛  XR技术讨论 XR互动电影 定格动画

 找回密码
 立即注册

QQ登录

只需一步,快速开始

调查问卷
论坛即将给大家带来全新的技术服务,面向三围图形学、游戏、动画的全新服务论坛升级为UTF8版本后,中文用户名和用户密码中有中文的都无法登陆,请发邮件到324007255(at)QQ.com联系手动修改密码

3D技术论坛将以计算机图形学为核心,面向教育 推出国内的三维教育引擎该项目在持续研发当中,感谢大家的关注。

查看: 3298|回复: 3

[DirectX] [转帖]骨骼动画实现1 粗译

[复制链接]
发表于 2008-10-30 19:48:57 | 显示全部楼层 |阅读模式

多重动画

这个例子示范网格动画中使用HLSL实现多重动画的设制和DX动画的控制。这个动画的控制器把混合动画设置在一起,使动画从一个到另一个变化时确保能够平滑地变化.


概述

这个例子示范一个应用程序如何画3D动画,以及利用DX 动画的支持功能.DX有API类处理那些正在导入的网格的动画,和混合多重动画.动画的控制者支持有目的的动画追踪,而且允许动画从一个到另一个光滑地变换.这个例子分为两个部分:动画类库和应用程序.

动画的类库是一个通用的库,位于DX和应用程序之间.从一个.X文件导入到网格而且利用它的帧层为画图做准备,比如使用一个顶点渲染与调色矩阵为蒙皮索引画一个动态的网格.它具有可重性和可制定性.

在这个例子中,应用程序一部分只包含特定的代码,它使用动画的类库来创建TINY角色的实例,根据他们的执行的动作来实现这些实例的动画.每一个实例都能被用户或者例子本身所控制.在TINY实例中,应用程序这个一部分同样处理检测边界,超出边界的检测和实例程序控制下的行为管理.

应用程序.

它由两个部分组成.第一部分是CTiny class.在样本从X文件中导入后,它反馈已经过画过的网格状态.第二部分包括 CMYD3DApplication 和 通过DX应用程序范例的所有通用代码.

在该例子中,通过用户或应用程序(默认方式)来控制Tiny角色.当Tiny在应用程序控制下,以下的情况将发生:首先在地板上随机地定位和选定以及确定移动速度(跑或者走)。然后,Tiny角色转弯面向一个新的方向,以这个方向移动。在Tiny到达新的目标后,在其他Tiny对像将要移动的目标位置被选定之前,有一段简短的空闲时间,而且所有以上过程被重复。可以有多个Tiny这样的实例。“边界检测” 被用来检测对像实例,防止相互的运动。

CTiny 类有一个CAnimInstance 成员,是一个由动画库定义的。CTiny使用这个成员与它的动画控制器来执行所需要的动画任务。在这个例子中,Tiny有三个动画设制:闲逛 走和跑。Tiny动画控制器支持双动画通道。大多数的时间里,在两个通道之间,其中的一个通道是被动画设制为激活状态,当Tiny的动作要求改变动画(例如,从一个闲逛状态变为走路状态 或者从跑动中停止),将激活由新的动画设制的第二个通道,设定播发和设定一个过渡时间内来结束从第一个通道到第二通道的变换。在过渡时间结束后,第一个通道失效,第二个通道播发在Tiny中所看的那样的新的动画。

CTiny同样利用系统回调在相应实例动画中,播发脚步声。在初始化时,Ctiny设置一个数据结构CallbackDataTiny,包含传给回调过程的数据。该数据结构有三个成员:m_dwFoot 表示脚步是触发声音,m_pvCameraPos 指出摄像机的位置,当回调时,m_pvTinyPos指出Tiny世界空间坐标。这个数据通常用于确定哪一个声音要播放(右脚的声音 还是 左脚的声音),而且确定将怎么发声。例子定义一个类叫做检索发送了的数据做为CallbackDataTiny结构,然后依靠在这个结构中的值,以相应的音量播发DirectSound 缓冲中的数据。

在FrameMove中,例子的重复是通过CTiny实例数组和调用他们每一个动画来实现的。如果需要变化,这个更新过程将在所有实例实现。

应用程序的渲染代码是相当的简单。首先他设置一个观察和发射矩阵,依靠摄相机的位置和方向,然后它渲染一个网格对像为地板。接着,它通过Tiny 实例数组和调用 AdvanceTime和Draw在它们上面分别作画。AdvanceTime使动画控制器更新画面层的矩阵,然后Draw用更新的矩阵来渲染动画。最后,代码画出必要的字符信息。

动画的类库

该库由下列的结构和类组成。

CMultiAnim
CAnimInstance
CMultiAnimAllocateHierarchy
MultiAnimFrame Structure
MultiAnimMC Structure

 楼主| 发表于 2008-10-30 19:49:30 | 显示全部楼层
CMultiAnim
该类是类库的核心,它的功能是从X文件中导入形成包裹网格层。它也是创建动画网格的实例,它是CAnimInstance的类型,从.X文件共享网格层。这些实例与创建他的CMultiAnim对像有关系。

在这它的初始化方法中,CMultiAnim::setup,CMultiAnim 确定矩阵调色最大值,依靠当前顶点渲染的版本。它紧接着导入网格层从给定的X文件和创建的作用对像从给定的XF文件,包含顶点渲染,通过它来画网格对像。网格层的帧和动画控制器被创建在这个过程中。

在一个树结构组成的帧表示骨格的层次,比如网格对像。这个结构被分配所有关系的实例共享。

动画的控制器与网格层帧有关系。动画控制器CMultiAnim 并不用于保存动画。相反,当一个新的动画实例被创建,动画的控制器被新的实例复制而且也拥有新的动画控制器。应用程序使用一个实例自己的动画控制器来控制他的动画。因为每一个实例有它自己的动画控制器的拷贝,它能独于所有其他的实例进行播放动画。

当 动画控制器的AdvanceTime 方法在一个动画实例中被调用,在网格层中,动画控制器将为每个帧动画更新矩阵的变换。该帧然后画出该实例。

CAnimInstance

这个类代表一个动画的实体,或者动画的实例。每一个动画的实例有它自己的动画控制器,以允许实例独立地作画。每一个实例同样与CMultiAnim对像关联,保存所有相关实例共享的网格层。在作动画中,下面的方法列表是一些相当有趣的动画控制器,它们通常广泛地用于应用程序中。

方法名
描述
GetAnimController
为该实例返回动画控制器的ID3DXAnimationController 类型。通过动画控制器应用程序能设制动画过程,是否需要进行播发。
SetWorldTransform
为实例设置顶级的世界变换矩阵。当动画实时被更新时,在网格层每一帧动画是被递归变换的,依靠这个世界变换操作使它成为正确的世界空间坐标和方向。
AdvanceTime
通过可能回调过程为该实例更新当地的动画时间。时间更新导致动画控制器更新该实例的骨骼位置。如果按键事件被激发,动画控制器同样请求回调过程。

ResetTime
为实例重置当地的时间。
Draw
通过HLSL顶点工具来画这个实例。为了作画,帧被恰当地设置,这个通常在调用AdvanceTime以后。

当动画的实例被描画时,它使用它有关的CMultiAnim设置动画参数,包括顶点工具的有效对像。顶点工具功能是负责网格蒙皮,为屏幕空间变换位置,以及处理颜色。
通过VS_Skin的功能实现部分的蒙皮。这个功能在顶点工具文件中叫Skin.vsh。
该文件包括叫做amPalette 的4*3 浮点数组的矩阵调色板,通过它以及VS_Sin蒙皮函数,描绘网格皮肤。
其他顶点工具函数有目的地请求VS_Skin,因此一个应用程序能调用它自己的顶点工具函数来处理蒙皮过程。
VS_Skin 得到对像空间位置和法线,以及3个混合权(最后一个混合权由1减去其他的权来计算),以及四个矩阵索引调色板
这个函数紧接着用相应的矩阵,通过矩阵调色板和混合权,变换坐标和法线等于4倍的时间,把结果加起来标准化世界坐标与法线。

CMultiAnimAllocateHierarchy

该类从ID3DXAllocateHierarchy继承。它的目的是用于处理分配与解除分配系统资源,在导入与释放一个网格层时。
在这个范例中,CMultiAnimAllocateHierarchy初始化所有新帧和网格容器的成员,在网格层创建时CreateFrame和CreateMeshContainer被调用。
在DestroyFrame 和 DestroyMeshContainer 中,它释放所有系统资源并各自分配进DestroyFrame 和 DestroyMeshContainer 。
CreateMeshContainer 做稍微比一个简单的分配和拷贝多一点的工作。它也不得不做以下的工作:
Create all of the textures used by the mesh. 创建所有网格的纹理贴图。 Initialize the mesh container's bone offset array, given by pSkinInfo. 初始化网格容器的骨骼偏移数组,由pSkinInfo给出 Obtain the palette size that the mesh has to work with, and call ConvertToIndexedBlendedMesh to create a working mesh that is compatible with the palette size. 得到调色区的大小,网格将与用到它,然后调用ConvertToIndexedBlendedMesh来创建一个工作网格,它是与调色区一样大小。
 楼主| 发表于 2008-10-30 19:50:38 | 显示全部楼层

MultiAnimFrame 结构

该结构是一个源于MSITStore:F:%20Program%20Files%20Microsoft%20DirectX%20SDK%20(April%202006)%20Documentation%20DirectX9%20directx9_c.chm::/D3DXFRAME.htm">D3DXFRAME。在这个网格层里面它,表示一个单帧或一个骨骼。一个帧可能包括兄弟或者子体。整个网格层是树的一个相似结构。应用程序能在需要时,从D3DXFRAME添加成员到一个衍生结构。在这个例子中,没有添加需要的成员。

MultiAnimMC 结构

该结构是从D3DXMESHCONTAINER继承。它包括一个网格对像,把它放到网格层随同网格的相关数据。一个网格层能容纳任何网格容器成员。在该例子中,附加成员定义为下面的列表。

类型

名字

描述

MSITStore:F:%20Program%20Files%20Microsoft%20DirectX%20SDK%20(April%202006)%20Documentation%20DirectX9%20directx9_c.chm::/IDirect3DTexture9.htm">LPDIRECT3DTEXTURE9 *

m_apTextures

网格使用Direct3D纹理对像数组

MSITStore:F:%20Program%20Files%20Microsoft%20DirectX%20SDK%20(April%202006)%20Documentation%20DirectX9%20directx9_c.chm::/ID3DXMesh.htm">LPD3DXMESH

m_pWorkingMesh

通过矩阵调色区大小有效性,来判断网格拷贝的一致性。

MSITStore:F:%20Program%20Files%20Microsoft%20DirectX%20SDK%20(April%202006)%20Documentation%20DirectX9%20directx9_c.chm::/D3DXMATRIX.htm">D3DXMATRIX*

m_amxBoneOffsets

矩阵数组展现骨骼偏移。这个信息从pSkinInfo成员中获得,为便利拷贝到这里。

D3DXMATRIX**

m_apmxBonePointers

矩阵指针数组。它们指向网格层的各种帧。这个数组从骨骼索引矩阵提供一个简单的映射变换。

DWORD

m_dwNumPaletteEntries

当画这个网格时,使用到矩阵调色版的大小。这个大小不能超过调色版最大值,我们顶点工具应用于限制寄存器,而且它也不能比网格中的骨骼数目大。

DWORD

m_dwMaxNumFaceInfls

骨骼的最大数目,这可能影响一个简单的面。这个值是源于MSITStore:F:%20Program%20Files%20Microsoft%20DirectX%20SDK%20(April%202006)%20Documentation%20DirectX9%20directx9_c.chm::/ID3DXSkinInfo__ConvertToIndexedBlendedMesh.htm">ConvertToIndexedBlendedMesh

在画的时候,顶点工具需要这个值这是为了在计算时知道最后一个权重值。

DWORD

m_dwNumAttrGroups

ConvertToIndexedBlendedMesh.

在工作中的网格属性组的数目。一个属性组是一个网格的子集合,它能被一个简单动画调用来绘画。如果工作中的调色版大小不足以画一个网格的全部,它将需要中止并进入各自的属性组。这个过程由

ConvertToIndexedBlendedMesh.

实现

MSITStore:F:%20Program%20Files%20Microsoft%20DirectX%20SDK%20(April%202006)%20Documentation%20DirectX9%20directx9_c.chm::/ID3DXBuffer.htm">LPD3DXBUFFER

m_pBufBoneCombos

MSITStore:F:%20Program%20Files%20Microsoft%20DirectX%20SDK%20(April%202006)%20Documentation%20DirectX9%20directx9_c.chm::/D3DXBONECOMBINATION.htm">D3DXBONECOMBINATION结构数组的格式中,包含骨骼组合表。每一个属性组都有一个D3DXBONECOMBINATION 结构。

它识别网格的子集(顶点,面,骨骼),这些将在简单动画中调用。

 楼主| 发表于 2008-10-30 19:51:05 | 显示全部楼层

User's Guide 用户的手册

下面是一般控制在例子中的定义。

按键

动作

Q

向下移动摄像机

E

向上移动摄像机

W

向前移动摄像机

A

向左移动摄像机

S

向后移动摄像机

D

向右移动摄像机

N

另一个观察角度

P

前视 观察

R

重设摄像机

F2

显示D3D的设置菜单

Alt+Enter

触发全屏

Esc

退出

当你以正在观看一个特定网格实例模式时,下面的控制是有效的

按键

行为

C

得到控制权

W

向前移动

A,D

转向

W+Shift

保持在跑的模式

缺陷与可选的方法

这个例子所能做的是能通过不同的交替来实现不同的功能。因为所有Tiny角色实例同享共同一帧层的矩阵,例子必须在特定实例和在移动到另一实例前更新时间并描绘它。通常,这并不是当前的问题。然而,如果一个应用程序希望在描绘它之前,把所有实例更新,那么当他进行复制时就能使新的动画控制器指向一个不同的矩阵设置。每一个动画控制器通过这个方式运行,并都有它自己的矩阵设置,而且修改将不会发生在一个大多数内存被占用的情况下。矩阵调色版在蒙皮顶点工具下是一个矩阵数组这同样不值得,而且通常占据大量的内存。一个应用程序可能遇到因为被其它占用而内存不足的问题。当CMultiAnim中创建一个对像时,应用程序能通过设置MATRIX_PALETTE_SIZE_DEFAULT工具#define 一个很小的值。这个方法的缺点是网格可能包括更多的子集,它们需要逐个地描绘。注意这个例子明确示范描绘动态网格。它并不处理静态网格,虽然代码也能被扩充处理静态网格。在D3D设备被释放和重新创建时,例子仅做了一部分,另外的任务是动画控制器的状态保存的完成。在应用程序选择从HAL到REF设备,或者反之亦然,或者从D3D设备到其他双显示器系统,通常都会发生。 在MultiAnimation中,当D3D设备被释放,所有的动画控制器也被释放。当例子初始化新的D3D设备时,动画控制器随之重建。这个现在的一个问题,因为动画状态保存在动画控制器中都丢失了。例子的丢失的知识有动画每个通道正在播发内容,通道是可用的内容,和在旧设备被释放前的第一个通道的速度和权重值。要解决这个问题,应用程序必须在释放D3D对像的清除函数前(DeleteDeviceObjectsMultiAnimation ,检索动画控制器状态并保存到一个缓冲里面。接下来,在它重建动画控制器后,它需要从缓冲里面载入动画控制器的状态。每一个动画控制器,下列状态将被保存。

优先调配所有鼠标事件。通过调用MSITStore:F:%20Program%20Files%20Microsoft%20DirectX%20SDK%20(April%202006)%20Documentation%20DirectX9%20directx9_c.chm::/ID3DXAnimationController__GetUpcomingPriorityBlend.htm">GetUpcomingPriorityBlendGetEventDesc。这个处理所有事件就像处理追踪按键事件因为要简明的原因,MultiAnimation 不但保存它动画控制器的所有状态,而且它保存正在播放动画设置追踪。因此,如果D3D设备对象是被释放或者重建在动画变换期间,那么动画在变换后,将不再和以前一样出现;它将出现正如变换完成后的。另外,所有的按键事件将不被还原在重新初始化后.

您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

手机版|小黑屋|3D数字艺术论坛 ( 沪ICP备14023054号 )

GMT+8, 2025-2-6 07:10

Powered by Discuz! X3.4

Copyright © 2001-2020, Tencent Cloud.

快速回复 返回顶部 返回列表