我們以渲染 一個 簡單的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工程