当前位置: 首页 > 工具软件 > Horde3D > 使用案例 >

3D引擎:Horde3D:Shader类里的 结构体,以及渲染一个 Logo的简单流程(三)

缪升
2023-12-01
首先是 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来执行。





 类似资料: