3D引擎:Horde3D:Shader類裏的 結構體,以及渲染一個 Logo的簡單流程(三)

首先是 ShaderCombination結構體
參數有:
1  uint32          combMask 
     這個變量主要用來  表示#define的位,每一位表示一個 #define如在 shader文件中 有這樣的語句:
 ...  
#ifdef _F03_ParallaxMapping
     #define _F02_NormalMapping
#endif
...
#ifdef _F02_NormalMapping
     uniform sampler2D normalMap;
#endif
....


這裏面 _F03_, _F02_中的 03, 02 就是一個#define標識, 它會被 ShaderResource類的 cacCombMask 分別計算成爲 num = 0*10 + 3 , num =  0*10 + 2
  然後  與 combMask 進行  |= 1<<(num-1);

2  uint32      shaderObj
   這個變量是  glCreateProgram創建 shader工程的句柄

3  就是 引擎裏需要的 一些 uniform名字的句柄, 即 通過 glGetUniformLocation返回的句柄

其次 是 ShaderContext 結構體
  在上一帖中,我們講過  Shader文件 分爲 3個部分,FX部分, VS_*和 FS_*部分。

  ShaderContext結構體主要是用來存儲 FX部分的一些信息

  假如 shader文件 有這樣的語句:
  
 context ATTRIBPASS
{
     VertexShader = compile GLSL VS_GENERAL;
     PixelShader = compile GLSL FS_ATTRIBPASS;
}

   像Map結構一樣,每個name對應一個value; 每個context都對應一個名字
   1 std::string                      id
   它就是 context 對應的名字  如 ATTRIBPASS
  
  2  形如 blendMode這樣的宏 或者 depthTest這樣的bool值
     它們對應的 就是 context裏 
    ZWriteEnable = false;
     BlendMode = Add;
     這樣的語句
 
  3  int vertCodeIdx, fragCodeIdx
       這兩個 是  存入到 shaderResource類  _codeSections裏  CodeResource的 標識/句柄
      即 VS_*部分或 FS_*的 CodeResource在  _codeSections裏 的 位置 
     由於 每一個 context對應一個 VS_*, FS_*,在 ShaderResource類的 ParseFXSection函數裏 
    會依次 存儲 VS_*, FS_*到 _codeSections裏,並 設置其位置 爲 vertCodeIdx或 fragCodeIdx

   4  std::vector<ShaderCombination>  shaderCombs
    參見上面 ShaderCombination結構體

  5    flagMask
     它是 CodeResource類在解析 VS_*, FS_*這部分內容時,會將 其中 #define的標識,計算出一個 類似 combMask的值,用來統計 shader文件裏的 #define


Shader文件中,一個 context對應一個 ShaderContext及一個 ShaderCombination
像Logo這種簡單的Shader文件,可能只有一個 context。
有的比較複雜的場景,可能同時又 場景,精靈,燈光,就需要多個 context

我們以渲染 一個 簡單的Logo 爲 例,來展示 Horde3D 如何一步一步解釋 Shader類的工作原理:

首先,需要 以下文件
    logo.material.xml 
    內容:
      <Material>
           <Shader source = "shaders/overlay.shader"/>
           <ShaderFlag  name = "_F01_TEST"/>
           <ShaderFlag  name = "_F02_TEST"/>
       </Material>
   這裏面,我們省去了 圖片 Sampler類的加載,而添加了 一個 ShaderFlag用於解釋 flagMask 和 combMask的用法
  
   overlay.shader 存在 shaders文件夾下 其內容爲:
    
[[FX]]

     context OVERLAY
    {
        VertexShader = compile GLSL VS_OVERLAY;
         PixelShader = compile GLSL FS_OVERLAY;

          ZWriteEnable =  false;
          BlendMode = Blend;
    }

    [[VS_OVERLAY]]
     uniform mat4 projMat;
     attribute vec2 vertPos;
   
     void main(void)
    {
         gl_Position = projMat*vec4(vertPos.x, vertPos.y, 1, 1);
    }

   [[FS_OVERLAY]]
   #ifdef _F01_TEST
      uniform sampler2D albedoMap;
   #endif

   #ifdef_F02_TEST
   uniform vec4 olayColor;
   #endif
   
  void main(void)
   {
     .....
   }


首先,將 創建 一個 MaterialResource資源類,
然後將 上述  logo.material.xml 裏的 文本讀取到 char *data 裏,並調用 該MaterialResource 資源類的 load方法
利用 rapidxml對 其解析, 將 ShaderFlag的 值 _F01_TEST存到 _shaderFlags 裏

根據 Shader 的值 即其Shader文件的路徑名,添加一個ShaderResource類
   
然後  調用 ShaderResource的 calcCombMask 來計算出 _combMask, 
 calcCombMask 接收 _shaderFlags 作爲其參數
   
logo.material.xml裏的 ShaderFlag 有 _F01_TEST 和 _F02_TEST兩個
   那麼,  combMask的值 爲 11,即  將 _F01_TEST的 01   
   num =  0*10 +1 = 1;
  然後  1<<(1-1) 就爲  個位的1
   將 _F02_TEST的02
    num = 0*10 +2 = 2;
   然後 1<<(2-1)  就爲  十位的 1
  依此類推

  其中 01, 02爲 ShaderContext結構體中的flagMask的值, combMask即爲 ShaderCombination中 combMask的值, combMask可以理解爲  shader文件中 用戶定義的#define的 集合

  
之後,調用 ShaderResource的 preLoadCombiantion(_combMask)
   爲什麼叫 preLoad呢,因爲在Material資源類處於加載的過程中, 調用的ShaderResource類的load方法還沒有被調用,_combMask 是要與 。所以這裏只是預先將 _combMask存儲在 ShaderResource類的 _preLoadList裏.   
 
最後,調用ShaderResource類的load方法
   在這個裏面解析 shader文件的數據,然後調用compileContexts()方法
    context.flagMask可以理解爲  shader文件中 #define的集合, 將 _preLoadList的 combMask  與 context.flagMask進行與,可以理解爲取  用戶定義的 且 shader文件裏有的 #define

 調用compileCombiantion, 將 VS_*, FS_*的內容前面加上宏定義,然後交給 底層的渲染類去 compile和 link成shader工程

至此,除了CodeResource類,整個從加載Material類,到 讀取Shader內容 給 RendererBase類就 全部走通了。

CodeResource類也只是簡單的講 VS_*, FS_*的內容進行解析, 並交給 compileCombianation來執行。





發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章