(版本:TGEA1.0.3)
1. 基本概念
在materials中介绍过了,TGEA有两种方式来支持shader:引擎生成(Procedural Shader Generation)与用户自行开发(Specifying Hand Written Shaders)。shaderGen模块的功能即是负责生成shader。此模块根据材质对象中定义的各种属性,生成相应的shader代码(写入相应的hlsl文件,保存于example/shaders/procedural)。
2. 核心类
2.1. ShaderComponent
Shader由好几个部分组成,ShaderComponent表示生成的shader中的各种的数据结构和main函数的函数头。
ShaderComponent有三个子类:ConnectorStruct、VertexMainDef、PixelMainDef。
ConnectorStruct是指着着器的输入与输出结构。
VertexMainDef是指vertex shader的main函数函数头,包括参数表。
PixelMainDef是指pixel shader的main函数函数头,包括参数表。
参一个shader的例子:
struct Appdata
{
float4 position : POSITION;
......
};
struct Conn
{
float4 HPOS : POSITION;
......
};
Conn main( Appdata In,
uniform float4x4 modelview : register(VC_WORLD_PROJ),
......
)
{
Conn Out;
Out.HPOS = mul(modelview, In.position);
Out.TEX0 = In.baseTex;
Out.outLightVec.w = step( 0.0, dot( -inLightVec, In.normal ) );
.......
return Out;
}
其中的输入结构 Appdata与输出结构 Conn指的是ConnectorStruct。
Conn main( Appdata In,
uniform float4x4 modelview : register(VC_WORLD_PROJ),
......)
这一段即是VertexMainDef。
ShaderComponent及其子类的UML图如下:
图3-6 ShaderComponent UML图
成员函数:
l virtual void print( Stream &stream ){}
输出这个ShaderComponent的相应代码。
2.2. LangElement
LangElement表示的是shader代码的基础。Shader代码由ShaderComponent与LangElement组成。LangElement表示的是shader代码中非数据结构的部分,即具体的shader语句,包括赋值语句、运算运句、变量定义等。
LangElement是一个结构体,UML图如下:
图3-7 LangElement UML图
成员函数:
l virtual void print( Stream &stream ){}
输出这个LangElement的相应代码。
2.3. ShaderGen
为此模块最重要的类,负现生成shader。UML图如下:
图3-8 ShaerGen UML图
数据成员:
l GFXShaderFeatureData mFeatureData
存储要生成的shader的feature。
l Vector< ShaderComponent *> mComponents
存储了这个ShaderGen要生成的shader文件的所有ShaderComponent。枚举量Components指定了这个向量的各个元素存储的ShaderComponent的类型。
enum Components
{
C_VERT_STRUCT = 0,
C_CONNECTOR,
C_VERT_MAIN,
C_PIX_MAIN,};
C_VERT_STRUCT指VS中的输入结构。
C_CONNECTOR指VS中的输出结构与PS中的输入结构。
C_VERT_MAIN指VS的main()函数头。
C_PIX_MAIN指PS的main()函数头。
成员函数:
l void ShaderGen::generateShader( const GFXShaderFeatureData &featureData,
char *vertFile,
char *pixFile,
F32 *pixVersion,
GFXVertexFlags flags )
此函数依据传递进来的shader feature来生成相应的shader,并写入vertFile,pixFile指定的文件中。重要代码如下:
mFeatureData = featureData;
processVertFeatures();
printVertShader( *s );
processPixFeatures();
printPixShader( *s );
mFeatureData = featureDatae用传递进来的shader feature来给ShaderGen的mFeatureData属性赋值。
processVertFeatures()函数生成相应的顶点着色器代码,printVertShader()函数将生成的的代码输出到stream中。
processPixFeatures()与printPixShader( *s )类似。
l void processVertFeatures()
根据mFeatureData的信息来生成相应的shader,重要代码如下:
for( U32 i=0; i<GFXShaderFeatureData::NumFeatures; i++ )
{
if( mFeatureData.features[i] )
{
gFeatureMgr.get(i)->processVert( mComponents, mFeatureData );
}
}
ConnectorStruct *connect =
dynamic_cast<ConnectorStruct *>( mComponents[C_CONNECTOR] );
在for循环中,对mFeatureData的中feature生成相应的shader代码,包括ShaderComponent与LangElement。
ConnectorStruct *connect = 生成顶点着色器的顶点输出结构。
l void processPixFeatures()
与processVertFeatures()函数类似。
l void printVertShader( Stream &stream )
将processVertFeatures()函数中生成的vertex shader输出到stream中。主要代码如下:
mComponents[C_VERT_STRUCT]->print( stream )输出VS输入结构的定义。
mComponents[C_CONNECTOR]->print( stream )输出VS输出结构的定义。
mComponents[C_VERT_MAIN]->print( stream )输出main()函数头。
printFeatures( stream )输出各个shader feature的相应代码。
l void printPixShader( Stream &stream )
与printVertShader()函数类似。
3. 流程
由前所述。使用shader有两种方法,分别是引擎生成(Procedural Shader Generation)与用户自行开发(Specifying Hand Written Shaders),对应的流程如下:
3.1. Specifying Hand Written Shaders
当用这种方式使用shader时,使用CustomMaterials指定相应的ShaderData,再在ShaderData中指定相应的shader(hlsl文件)。具体参见第3,8章。
当引擎载入脚本代码执行时,对脚本对象会调用引擎中相应对象的onAdd函数,ShaderData对象引起的流程如下:
在materials/ ShaderData.cpp中:
ShaderData::onAdd()
àShaderData::initShader()
à GFXDevice::createShader( (char*)DXVertexShaderName,
(char*)DXPixelShaderName,
pixver );
最终调用GFX层来从hlsl文件中加载shader代码。具体参见第7章。
3.2. Procedural Shader Generation
当使用这种方式时,依据在材质对象中指定的属性来生成shader。流程接着materials模块:
在materials/material.cpp中:
MatInstance::addPass()
à GFXDevice::createShader( rpd.fData, mVertFlags )
à GFXD3DShaderMgr::getShader( GFXShaderFeatureData &dat,
GFXVertexFlags flags )
à ShaderGen::generateShader( const GFXShaderFeatureData &featureData,
char *vertFile,
char *pixFile,
F32 *pixVersion,
GFXVertexFlags flags )
从这里开始进入ShaderGen模块,依据传递进来的shaderfeature来生成ShaderGen。