我们以渲染 一个 简单的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来执行。