终于完成了结构最复杂的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部分终于告一段落,下面终于可以进入材质节点系统的进一步完善了