終于完成了結構最復雜的Shader管理器,特性如下:
GlobalShader管理:
也就是傳統的手寫Shader,完成特殊的任務,例如線條繪制,2D繪制等等
class ElementPixelShader : public ShaderBinder
{
DECLARE_RTTIOBJECT( ElementPixelShader )
DECLARE_RTTISERIAL( ElementPixelShader )
DECLARE_SHADER_METAINFO(ST_PixelShader, L"Shader\\SimpleElementPixelShader.usf",L"Main")
public:
virtual void BindShaderParameter( eShaderType ShaderType, const ShaderParameterMap& ParameterMap )
{
mTexture.Bind( ParameterMap, "Texture" );
}
void SetTexture( RenderTexture* NewTexture )
{
mShaderRHI->SetTextureParameter( mTexture, NewTexture );
}
virtual void Serialize( BinarySerializer& Ser )
{
__super::Serialize( Ser );
Ser << mTexture;
}
private:
ShaderParameter mTexture;
};
IMPLEMENT_GLOBAL_SHADER( ElementPixelShader, 1);
管理器中,是一種類似單件存儲,通過類型可以直接取到實例
MaterialPixelShader管理
這種Shader通過材質節點生成的shader代碼來記錄每個Shader信息,每個MaterialVertexShader需要只做MaterialPixelShader需要的信息并在Shader代碼中傳送給它
MaterialVertexShader管理
這類Shader最復雜,其中的控制代碼生成的宏需要由材質提供,例如是否使用TangentSpace。還有一些參數就更頭疼了, 不是材質在制作時能決定的,例如:一個材質可以應用給地形,模型,甚至粒子,所以我把這部分參數叫做晚綁定參數(Later Bind Material Parameter)
MaterialVertexShader本身是抽象的,需要在材質應用到具體對象時,由對象提供其特殊的VertexShader處理Shader,同時根據特性設定晚綁定參數
晚綁定參數:
MaterialParameter Parameter;
Parameter.Set( MPT_UseSkin, mSkinned );
mMaterialInstance->SetVertexShaderProvider( RTTI_CLASS_INFO( ModelMaterialVertexShader),Parameter );
材質緩沖系統
Shader 動態編譯在很多游戲里都有應用,例如:戰地2。游戲第一次啟動時,就會編譯一次Shader。按照很多文章說的,編譯器會根據你顯卡及配置編譯出最優化的代碼。 我就納悶了, D3D編譯函數根本沒有傳入設備句柄,怎么可能根據機器配置編譯?我也嘗試過,不同機器上編譯出來根本就是一樣的。
在以后引擎啟動時,Shader系統就會自動從保存好的緩沖內讀取,不用再次編譯。
這里還要提一個微軟為D3DX做的升級Patch系統很惡心,類似于D3DXCompileShader及Shader相關的函數,在每次調用函數時,會載入一個D3DX9_xx.dll,調用完畢后又會卸載,極大的影響性能。 若不是因為這個,估計我不會寫緩沖系統的
動態編譯更新Shader
這個功能是很多引擎都有的,RenderMonkey也一樣,實現起來很簡單,就是一個文件時間戳比較問題,此功能完全是為以后編輯器做準備。
MaterialShader部分終于告一段落,下面終于可以進入材質節點系統的進一步完善了