首页>
技术资讯>
详情

half-life2的图形系统研究心得

2016-05-28 来源:CloudBest 阅读量: 145
关键词: 程序设计


  小T一边作自己的3D引擎,一边研究half-life2的图形引擎,留下点心得。
  
  整体上half-life2给小T的感觉一是庞大,二就是难读,com方式组织引擎,小T也不敢妄加评价,只是小T觉得整个引擎非常的难读。小T只有借助调试器才勉强对half-life2的图形引擎有个大致的了解,至于怎么编译half-life2,怎么运行,以及怎样调试,小T就不详细的描述了,到网上随便一搜索就能找到一大堆,这里只是简单的看看他的图形系统。
  
  当前的3D环境,想要提高渲染速度,一个最基本的方法就是要减少硬件的渲染状态的切换,今天小T就是讲hl2的渲染状态管理部分的。在hl2里面,渲染状态主要被放在了一个叫ShadowState_t的结构里面,这个结构对应了大多数的硬件渲染状态,渲染系统维护多个ShadowState_t结构,在必要的时候把ShadowState_t的内容真正的设置到硬件上面,从而减少硬件的状态切换。当然实际上却没有这么简单,上面只是个简单的介绍,下面开始详细的解释hl2怎么进行硬件状态管理。
  
  hl2里面渲染状态管理的一个比较重要的类就是CTransitionTable,从名字上面看,这个类描述的是一种转换,他其实就是描述了,渲染过程中硬件渲染状态的转换流程,hl2把硬件状态的管理也放在了这个里面,举个例子来说可能比较清楚。
  
  比如:整个场景里面有2个物品,第一个物品使用一组渲染状态,第二个物品使用另外一组渲染状态,我们先渲染第一个物品,设置成第一个物品的渲染状态,接着渲染第二个物品,设置第二个物品的渲染状态,这个就是正常的操作方式,如果第一个物品和第二个物品的渲染状态有相同的,那么有些设置renderstate的函数就不用调用,我们可以把渲染状态看作是一种状态机,从第一种状态转换到第二种状态,我们要作一些事情,如果我们能建立一张行动表,表里面记录状态转换的时候要执行的动作,那么我们就可以简化这种状态管理模型,这个就是CTransitionTable类完成的工作。
  
  对于场景里面的每个materila(顺便说一句,hl2也是按照material的方式组织渲染动作的),都对应了一种渲染状态,这些渲染状态都被CTransitionTable类记录下来,每一个渲染状态对应一个唯一的id,那么material只用记录他对应的渲染状态id就能完成自己的渲染了。比如我们要渲染一个物品,我们告诉渲染系统我们使用的渲染状态id,渲染系统自动完成渲染状态的设置,自动完成渲染状态切换的最小化任务,然后我们调用一个drawprimitive就ok。实际上的操作也没有这么简单,我们再看看实际一点的东西。
  
  hl2里面的渲染状态操作都被封装到了ShaderRenderState_t类里面
  struct ShaderRenderState_t
  {
  RenderPassList_t m_Snapshots[4];//代表了一种渲染方式,缓冲4种渲染方式0=默认,1=带color数据,2=带alpha数据,3=color+alpha
  int m_Flags;// 标志,
  VertexFormat_t m_VertexFormat;// 顶点格式
  int m_VertexUsage;
  };
  
  struct RenderPassList_t
  {
  int m_nPassCount; // 渲染pass的数目
  StateSnapshot_t m_Snapshot[MAX_RENDER_PASSES]; // 实际是一个short形式,就是渲染状态id
  };
  
  解释下RenderPass这个东西,一个material在hl2里面渲染方式分成了4种,每种都对应了一个RenderPassList_t的类,而ShaderRenderState_t把这4种渲染方式都缓存了,嗯,举个例子,比如我现在想要按照默认的方式渲染一种material,我传递一个ShaderRenderState_t的结构给渲染系统,渲染系统根据我要求的渲染方式索引到正确的RenderPassList_t元素,使用里面记录的StateSnapshot_t数组里面的某个正确的id来获取到正确的渲染状态。
  
  我们已经知道了渲染系统的客户端怎样要求渲染系统完成自己的渲染状态设置了,接下来看看渲染系统本身怎样完成这个工作,当渲染系统得到一个渲染状态id以后,就应该要获取到与之对应的渲染状态,并且正确的设置好这个状态,换句话说也就是要完成当前状态到新状态的切换,首先看看渲染系统怎么去找到正确的渲染状态,这就落在了IShaderAPI和CTransitionTable身上了,小T使用的是DX9的ShaderApi,所以这个任务是由CShaderAPIDX8这个类来完成了,在CShaderAPIDX8类里面有一个CTransitionTable类的数据成员m_TransitionTable,每当要获取到一个渲染状态id以后,ShaderApi就告诉m_TransitionTable要使用新的渲染状态了,并且传递新状态的id,到这里先停一下,一直小T都使用渲染状态这几个字在描述,那究竟hl2使用什么样子的数据结构来表示实际的渲染状态呢?ShadowState_t对应的是硬件状态,而还有一个东西对应了vs,ps的状态,他也是要在状态转换的时候进行设置的,渲染状态id对应的其实是SnapshotShaderState_t 结构:
  
  struct SnapshotShaderState_t
  {
  ShadowShaderState_t m_ShaderState;
  ShadowStateId_t m_ShadowStateId;
  };
  
  struct ShadowShaderState_t
   {
  // The vertex + pixel shader group to use...
  VertexShader_t m_VertexShader;
  PixelShader_t m_PixelShader;
  // The static vertex + pixel shader indices
  int m_nStaticVshIndex;
  int m_nStaticPshIndex;
  };
  
  ShaderApi获得了新的渲染状态id以后,和当前的渲染状态id比较,如果不相同,则获取到ShadowStateId,如果也不相同,那就要设置新的ShadowState了,这个操作下面讲解。然后,ShaderApi保存当前的渲染状态id,保存ShadowStateId,同时设置ShadowShaderState,这些都设置完成了,硬件的渲染状态也就设置完成了,然后的任务就是调用DrawPrimitive等等函数完成绘制的时候了,这个绘制是由各个vs,ps完成的,关于这个部分,小T留到下次讲解。
  
  现在我们来看看shaderapi,怎么设置新的ShadowState,基本的方式就是获得两个状态之间的转换表,执行表里面规定

热门推荐 查看更多