real-time 3d terrain engines using C++ and DX9 翻译 5
资源基类
所有的引擎资源对象都是从cResourcePoolItem类中继承得到的。这个类提供了一个cResourcePoolManager类能够使用的函数的集合,用以创建,销毁,从磁盘保存和载入资源。cResourcePoolItem类对象也为每个资源对象维护一个核心的数据集合,包括定义资源类型的代码,一个资源管理器的接口和一个资源的cPoolHandle对象的索引。一个位标志同样背维护,记录着资源当前的状态。
cResourcePoolItem类提供一个通用的函数集合来重新找回资源的名字,查询资源的状态和重新得到资源数据池的句柄。然而,最重要的成员函数是一个用来维护资源本身的纯虚函数的集合。从cResourcePoolItem资源基类派生得到的引擎资源提供这些纯虚接口函数的实现。这些成员函数创造了可以被管理器对象用来操作资源的接口。清单4.4展示了这些成员函数。
使用这个简单接口函数集合,一个管理器能够完全的维护一个资源对象的集合。最值得注意的是,接口函数disableResource和restoreResource允许管理器从可变内存中清除或者重建资源。一个例子就是位于显存中的纹理。如果显示设备接口丢失,资源管理器将被通知去禁用所有的依赖资源。当重新获得显示设备,这些子资源能够很容易的通过调用合适的成员函数来重建。
使用D3DX,我们可以奢侈的使用微软提供的资源建立管理器。对我们的大多数视频依赖资源来说,我们将在设备暂时丢失后对视频依赖资源利用这一自动重获管理。以这种方式建立资源只需要简单的在创建Direct3d资源的时候指定D3DPOOL_MANAGED标志来支持自动内存管理。使用自动内存管理我们也得到一个额外的好处,能够根据需要在内存空间有限的情况下确保纹理被从显存中上载和删除。
这个不会应用与动态资源,例如那些我们经常需要重新计算的纹理和几何体。这些资源最好使用手动管理,因为我们明白什么时候和他们应该怎么背新的数据替代。我们的接口使我们能够有机会使用这两种方法,这取决我我们怎样为我们定义的每种资源类型重载虚函数。
纹理资源和表面材质
我们最简单的资源是cTexture对象。这个类实质上是一一种和我们的资源管理计划兼容的方式容纳一个IDirect3dTexture9对象的包装物体。我们在这里简单的提到这个类是因为我们将在渲染方法中经常使用到这个类。在我们管理包装之外,cTexture同样包含使用D3DX库提供的从磁盘中加载纹理文件的函数。
然而,表面材质是我们自己的创造,需要一点解释。D3DX作为一个向后兼容的偶像,怡然坚持标准的一个材质搭配一个纹理。这一点能够明显的从存储这些对象的一级结构D3DXMATERIAL中看出,这个结构只允许指定唯一一个材质。几年前,这是合适的,当对于当前的顶级显卡,这过时得可怕。
作为我们渲染的需要,我们提供一个更新的表面材质类,cSurfaceMaterial,它能容纳16个标准的标准的带有散射光,镜面光和自发光光照色调纹理。虽然16个纹理看起来会耗尽现今的可以每个过程(pass)使用4~8个纹理的显卡,但这使得我们有可能使用为多过程渲染同一个表面提供纹理。
例如,我们可能建立一个设计使用两个过程(pass)共同渲染的表面材质,每个过程(pass)使用4个不同的纹理。这8个纹理在我们的限制之内,并且提供独立的纹理索引给我们的HLSL着色器使用。我们也可以使用存储空间来存储不同版本的表面材质,比如每个纹理的冬天和夏天的版本。着色器可以在初始化是便秘啊选择合适的集合使用。考虑这些可能,可能16个纹理的限制都太有限了。
cSurfaceMaterials也包含一个位标志的集合,每个纹理位置一个标志。这16个位标志标明某个材质是否被载入到相应的纹理位置。就像我们过一会儿会看到的,这些让我们能够使用渲染方法来使表面材质生效。
渲染方法资源
cEffectFile类是我们ID3Deffect对象的容器。为了提供我们通常的管理和文件I/O函数集合,cEffectFile类使用引擎中设置的变量和常量解析编译后的效果(effect)。正如我们在第二章“Fundamental 3D Object”讨论的那样,Direct3D效果文件带有可以通过注释或者语义而被程序查找的全局变量。程序可以通过调用ID3Deffect类提供的接口函数设置这些变量的值,该类的基类是ID3DeffectBase类。
这些函数通过接受一个字符串或者一个句柄来确认这些变量正在被设置,这些函数在DirectX文档中有详细描述。通过句柄访问效果(effect)变量更高效,因为它不包括查找变量名的字符串比较开销。cEffectFile类通过在加载这些效果文件时预先解析他们来建立一个已知变量类型的句柄列表来利用这一特性。表4.1列出了一些cEffectFile类能够识别的变量类型
预解析这些语义得到句柄也使我们能够在内部设置一些位标志来表示那些变量出现在一个效果(effect)中。例如,我们为可以每个效果文件中找到的标号的纹理位置(texture slot)设置一个位标志。通过使用逻辑AND操作将这些纹理标志位痛一个cSurfaceMaterial资源比较,我们可以迅速的验证表面材质是包含一个给定的渲染方法所要求的材质数目。
cEffectFile对象的父资源是是cRenderMethod类。我们最终的引擎将在一个复合的,独特的阶段渲染场景。这些阶段的两个例子是光照和凹凸贴图阶段。为了渲染场景,我们允许物体包含多重效果文件,每个渲染过程一个。cRenderMethod类用于存储这些cEffectFile对象文件。cRenderMethod类只是一个到cEffectFile对象文件链接的集合,渲染过程的每个阶段一个。cRenderMethod类也有为每个阶段存储一个独立的cSurfaceMaterial的标志,是它能够描述一个完整的渲染过程。
现在,我们简单的为每个模型使用唯一一个cEffectFile对象。这能够是我们的引擎迅速的建立起来并且快速的运行而不会被凹凸贴图和其他渲染效果阻碍。我们将在本书的第三部分重新回到这个主题,那时我们开始为每个对象使用多个着色器来达到更好的效果。现在,即使我们的模型会包含一个cRenderMethod,这个集合只在“默认”的位置(slot)包含一个cEffectFile对象。