<@毛驴:>[翻译]托管D3D:使用frame层次

 

托管D3D:使用frame层次

 

Tank

这篇文章假设我们的场景是从.x文件中导入。SDK中提供能支持导入此文件格式的类库。

原文出处:http://www.jkarlsson.com/Articles/loadframes.asp 转载请注明出处,模型及完整源代码请到原文处下载

 

Directx(.x) 文件

 

Code

整个.x文件比这个要多的多,但是以上是和框架这个议题相关的内容。让我们来看看它们的玄机。

 

Frame Body {}

它描述名为body的frame。再看看另两个frame,Turret和Gun,Gun嵌套于Turret中,而Turret嵌套与Body中,就这样组成了层次关系。

 

FrameTransformMatrix {}

当前frame的FrameTransformMatrix{}声明了frame的网格及其子frame的网格将以怎样的规则排列、移动、旋转、这样的话frame将得以与其它几何体以正确的方式放置。考虑以Turret为例,它应该被建模为一个圆柱并放置在车身表面。但如果不为它提供变换的方式,它将可能掉落于车身中。有了变换矩阵,我们就有了足够的信息去正确地放置Turret。

 

Mesh {}

包括了组成frame的顶点的坐标。和变换矩阵一起使用,我们就有了足够的信息将不同的frame放在一起正确地渲染。

 

 

载入Frame层次

 

让我们开始设计一个能够将对frame层次操作封装起来的类。我们由载入.x文件和在内存里创造实现frame的对象开始。内部存储的场景将被以一个AnimationRootFrame对象保存。它将frame层次保存在FrameHierarchy属性中。它也可以对frame结构完成其它的操作,但这里我们暂时忽略掉它。

我们需要额外写一些代码去提取.x文件,创造frame层次并把它存储在AnimationRootFrame对象中。我们使用静态方法Mesh.LoadHierarchyFromFile。这个方法需要我们通过编写类来实现部分对建立frame层次具有实际意义的操作。我们需要从AllocateHierarchy,Frame,MeshContainer这些抽象类中继承。这篇文章中,我们将重写的类命名为CustomAllocateHierarchy,CustomFrame,和CustomMeshContainer。

代码的第一部分。

Code

 

静态方法Mesh.LoadHierarchyFromFile 接受一个.x文件 并且返回一个AnimationRootFrame对象,文件中包含了一个frame层次。第一个参数是文件的物理地址。第二个参数决定了网格将以怎样的方式被创建。第三个参数是对渲染设备的引用。第四个参数是对派生类的引用。忽略第五个参数。
Mesh.LoadHierarchyFromFile 期望引用一个从抽象方法AllocateHierarchy派生的对象。类中必须定义CreateFrame方法,将被每一个从.x文件中被检测到的frame调用。这些方法返回的都是抽象类,frame对应CreateFrame方法,MeshContainer对应CreateMeshContainer对象,所以我们将派生这些类。


The AllocateHierarchy Class

CustomAllocateHierarchy类的声明如下。

Code

我们的CustomAllocateHierarchy保存了将会载入的.x文件的路径。在待会创建网格对象时将会使用它。马上我们将看到,使用CreateFrame方法创造的CustomFrame类的实例,使用CreateMeshContainer方法创造了CustomMeshContainer类的实例。

 

Frame类

Code

 

CustomFrame类为当前Frame定义了变换矩阵。它将用于定制frame层次中单独分支的变化。举个例子,对于坦克模型中的Turret。有了定义在.x文件中的Turretframe和其父frame的变换矩阵,我们就可以正确地渲染Turret。有了添加的定制的矩阵,我们还可以旋转Turrt和Gun。CustomTransform矩阵被初始化为标准矩阵。所以没有定义任何变换。我们将在以后的代码中看到它怎样被用在渲染中。

 

The MeshContainer Class
MeshContainer类的清单

Code

 

构造函数接受了相应的参数并将相应的属性赋值。我人为这比单独去设置每一个属性要简单。类公开了一个初始化方法,使用.x文件的信息载入网格的贴图。Initialize方法中的代码假设贴图存储在与.x文件相同的路径之中。这个类同时将textures公开为一个属性。这对我们接下来渲染场景是必要的。

以上是载入frame层次所需的全部代码,下面添加渲染代码。

 

渲染一个场景

 

我们由添加公共的渲染方法开始。在开始渲染之前,我们要给予所有对象的用户这样的可能性,是否单个frame的定制转换矩阵需要被调整以表现出动画效果。我选择用事件机制来实现。
这个事件的所有句柄将被在渲染对象开始之前通知。并且可能会调整对象相应的定制变换矩阵。

Code

Render方法将会调用受保护的RenderFrame方法,这个方法将递归地调用并设置变换矩阵和渲染它们,这个方法接受将被渲染的frame和他们的父frame作为参数。为root frame传入标准矩阵。

Code

 

 

对层次中的每个frame,RenderFrame方法首先对于所有兄弟frame,使用父frame的变换矩阵,递归地调用它自己。然后使之和父frame,当前frame,当前的frame定制的变换矩阵相关联。然后递归地处理子frame,使用当前的矩阵做参数。最后调用DoRender完成真正的渲染。

 

Code

 

Retrieving Frames


假如我们有可能使用到层次中单个frame的变换,我们需要一个方式去从层次中找到它。我们添加GetFrame方法。

Code


 

使用这个类

 

让我们看看我们刚刚创造的类将怎样为我们专门为tank模型所创造的类所使用。我们声明tank的position,bearing,roll和pitch的属性,也包括Turret的角度。

我们重载GraphicsObject类的Initialize方法并为SetupCustomTransform事件注册句柄。Tank_SetupCustomTransform事件句柄寻找body frame并从bearing,pitch,roll,和position属性中计算它的CustomTransform。然后找到Turret frame并计算指定角度的CustomTransform。

 

Code

 

posted on 2009-02-05 18:37  乌龟_毛驴  阅读(1799)  评论(13编辑  收藏  举报

导航