关于游戏中的材质系统

来源:互联网 发布:ppt其他用途知乎 编辑:程序博客网 时间:2024/04/30 11:20

材质,这个词有各行各业都有自己的解释。

美工把物体贴图和物体颜色,高光等统称为材质。D3D和OPENGL这样的图形接口则把物体表面贴图单独叫做纹理,而把漫反射,高光等叫做材质。

而在游戏引擎或图形引擎中提到的材质,则与此不同。 引擎中提到的材质不仅上面的的内容。 引擎中所谓的材质,是指物体在渲染时一系列的状态控制。 如,ALPHA混合开关以及ALPHA混合因子、纹理过虑方式,纹理通道状态、纹理矩阵、裁剪模式等,在D3D中,就是SetRenderState,SetTextureStageState,SetSamplerStateState等所控制的。在OPENGL中,则大多数由glEnable所控制。

我们所提到的材质系统,则是以此为基础展开的。 上面提到的这些因子,组成了我们的材质。 也是我们在渲染一个物体的时候,提交到设备的状态控制值。 一个物体的一次渲染,我们称作一个PASS。于是我们顺其自然地将这个渲染时的材质控制的最小单位命名为Pass,则:

struct TextureState

{

    void* Texture;

    int ColorOp;

    int ColorAgr1;

    int ColorAgr2;

    int AlphaOp;

    int AlphaAgr1;

    int AlphaAgr2;

.....//更多内容

};

class CPass

{

   CColor mAmbient;

   CColor mDiffuse;

   ....更多内容

    bool mAlphaEnable;

    int mScrBlend;

    int mDstBlend;

    int mCullMode;

   TextureState[4] mTextureStates;

  ...更多内容

};

当我们渲染一个物体的时候,只需要将这个类里面的状态应用到设备,即可完成对物体的绘制。

材质系统的基本内容就是这些,这也是最容易做到的事情。

但是,我们都知道,像D3D或OPENGL这样的图形接口每设置一次GPU状态的时候,都会有一定的开销(通过查看相关文档可以看到某些函数的具体开销值)。而为了保证我们的渲染流畅,我们不得不减少这样的开销。

很自然地,我们会想到,尽量减少切换。而如何减少切换呢。我们可以记录下自己的硬件状态,在设置下一个的时候,先判断当前硬件状态是否相同,如果相同。则不用再设置。 虽然某些图形接口在其层底做了类似的功能。但我们外部判断一下,也未尝不可。从D3D上来讲,外部判断比让其内部判断效率更佳。需要注意的是,由于我们在自己的程序里做了相同判断。因此,当有另一个程序也修改设备状态的时候,就会产生意想不到的效果。所以,我们应该适当的查询一下设备状态,并更新自己的状态记录表。至于这个查询间隔,就要根据自己的实际情况来测试了。

通过记录状态的方法来提升的效率是很不明显的,因此,我们需要对材质进行排序,至于怎么排序,这算法上的问题,在此先不作过多解释。 总之,我们将相似的材质排在一起。由于材质很相似,绘完一个再绘下一个的时候,减少了切换,从而大大提升了效率。

既然已经是涉及到设备了,我们总得考虑一下设备问题。 如果设备不支持我们当前给定的材质状态,怎么办? 返回FALSE不渲染。还是让程序DOWN掉?  对于一些重要的性能,设备不支持让程序DOWN掉是最好的做法,但是,对于像纹理混合通道不足的情况,让其DOWN掉就显得划不来了。毕竟我们设计的游戏程序是想让更多的玩家能玩不是? 这样就会涉及到PASS的拆分问题。

对于PASS的拆分,OGRE已经做得很好了。根据用户的设备性能,如果不满足,就一直拆分,拆到用户满足为止,最后让一个物体渲染多次,来实现多个纹理通道混合的效果。 而多PASS则是在渲染的时候不得不考虑的地方,毕竟有些物殊效果非得用多PASS不可。

对于多PASS的设计,我们可以参考OGRE的材质方法或是D3DX的效果框架。我们把完成一个最终效果的方案称作一个渲染技术 Technique ,一个技术可由多个Pass来完成。

class Technique

{

...更多内容

 vector<CPass*> mPasses;

};

这样就满足了我们的需求。  对于同一种效果,我们可以提供多种Technique供程序选择。 而这个选择的条件则可以是根据硬件性能,或是玩家手动选择的配置来实现。

最后结构如下:

class CMaterial

{

public:

...更多内容

vector<CTechnique*> mRenderTechs

};

乱七八糟地说了一通,希望没晕死人!!!