(版本: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有三个子类:ConnectorStructVertexMainDefPixelMainDef

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图如下:

TGEA渲染部分源代码分析--ShaderGen模块

图3-6 ShaderComponent UML图

成员函数:

virtual void print( Stream &stream ){}

输出这个ShaderComponent的相应代码。

2.2. LangElement

LangElement表示的是shader代码的基础。Shader代码由ShaderComponent与LangElement组成。LangElement表示的是shader代码中非数据结构的部分,即具体的shader语句,包括赋值语句、运算运句、变量定义等。

LangElement是一个结构体,UML图如下:
TGEA渲染部分源代码分析--ShaderGen模块

图3-7 LangElement UML

成员函数:

virtual void print( Stream &stream ){}

输出这个LangElement的相应代码。

2.3. ShaderGen

为此模块最重要的类,负现生成shader。UML图如下:

TGEA渲染部分源代码分析--ShaderGen模块

图3-8 ShaerGen UML图

数据成员:

GFXShaderFeatureData mFeatureData

存储要生成的shader的feature。

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()函数头。

成员函数:

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 )类似。

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代码,包括ShaderComponentLangElement

ConnectorStruct *connect = 生成顶点着色器的顶点输出结构。

void processPixFeatures()

processVertFeatures()函数类似。

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的相应代码。

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。

相关文章:

  • 2021-12-30
  • 2021-11-27
  • 2022-12-23
  • 2022-12-23
  • 2021-11-22
  • 2021-11-09
猜你喜欢
  • 2021-12-11
  • 2021-12-05
  • 2021-06-08
  • 2022-12-23
  • 2021-11-23
  • 2021-10-04
  • 2021-08-19
相关资源
相似解决方案