In the pixel shader, we first define base interfaces for different light and material types:

//--------------------------------------------------------------------------------------
   // Interfaces
   //--------------------------------------------------------------------------------------
   interface iBaseLight
   {
   float3 IlluminateAmbient(float3 vNormal);

   float3 IlluminateDiffuse(float3 vNormal);

   float3 IlluminateSpecular(float3 vNormal, int specularPower );

   };
   
   // ...
   interface iBaseMaterial
   {
   float3 GetAmbientColor(float2 vTexcoord);

   float3 GetDiffuseColor(float2 vTexcoord);

   int GetSpecularPower();

   };

   // ...

Next we build specialized classes based on these interfaces, adding to the functionality where needed:

//--------------------------------------------------------------------------------------
   // Classes
   //--------------------------------------------------------------------------------------
   class cAmbientLight : iBaseLight
   {
   float3	m_vLightColor;
   bool     m_bEnable;

   float3 IlluminateAmbient(float3 vNormal);

   float3 IlluminateDiffuse(float3 vNormal);

   float3 IlluminateSpecular(float3 vNormal, int specularPower );
   };

   // ...
   class cBaseMaterial : iBaseMaterial
   {
   float3	m_vColor;
   int      m_iSpecPower;

   float3 GetAmbientColor(float2 vTexcoord);

   float3 GetDiffuseColor(float2 vTexcoord);
   
   int GetSpecularPower();

   };
   // ....

The pixel shaders main function uses abstract instances of the interfaces for computation. These interfaces instances are made concrete by the application code at shader bind time:

/--------------------------------------------------------------------------------------
              // Abstract Interface Instances for dyamic linkage / permutation
              //--------------------------------------------------------------------------------------
              iBaseLight     g_abstractAmbientLighting;
              iBaseLight     g_abstractDirectLighting;
              iBaseMaterial  g_abstractMaterial;

              //--------------------------------------------------------------------------------------
              // Pixel Shader
              //--------------------------------------------------------------------------------------
              float4 PSMain( PS_INPUT Input ) : SV_TARGET
              {
                 // Compute the Ambient term
                 float3   Ambient = (float3)0.0f;

                 Ambient = g_abstractMaterial.GetAmbientColor( Input.vTexcoord ) * g_abstractAmbientLighting.IlluminateAmbient( Input.vNormal );

                 // Accumulate the Diffuse contribution
                 float3   Diffuse = (float3)0.0f;

                 Diffuse += g_abstractMaterial.GetDiffuseColor( Input.vTexcoord ) * g_abstractDirectLighting.IlluminateDiffuse( Input.vNormal );

                 // Compute the Specular contribution
                 float3   Specular = (float3)0.0f;
                 Specular += g_abstractDirectLighting.IlluminateSpecular( Input.vNormal, g_abstractMaterial.GetSpecularPower() );

                 // Accumulate the lighting with saturation
                 float3 Lighting = saturate( Ambient + Diffuse + Specular );

                 return float4(Lighting,1.0f);
                 }

// use shader reflection to get data locations for the interface array
ID3D11ShaderReflection* pReflector = NULL;
//ID3D11shaderReflection是访问shader信息的一个interface; V_RETURN( D3DReflect( pPixelShaderBuffer->GetBufferPointer(), pPixelShaderBuffer->GetBufferSize(),
//D3Dreflect函数用以create一个id3d11shaderreflection的interface; IID_ID3D11ShaderReflection, (void**) &pReflector) ); g_iNumPSInterfaces = pReflector->GetNumInterfaceSlots(); g_dynamicLinkageArray = (ID3D11ClassInstance**) malloc( sizeof(ID3D11ClassInstance*) * g_iNumPSInterfaces ); if (g_dynamicLinkageArray == NULL) return E_FAIL; ID3D11ShaderReflectionVariable* pAmbientLightingVar = pReflector->GetVariableByName("g_abstractAmbientLighting"); g_iAmbientLightingOffset = pAmbientLightingVar->GetInterfaceSlot(0); ID3D11ShaderReflectionVariable* pDirectLightingVar = pReflector->GetVariableByName("g_abstractDirectLighting"); g_iDirectLightingOffset = pDirectLightingVar->GetInterfaceSlot(0); ID3D11ShaderReflectionVariable* pMaterialVar = pReflector->GetVariableByName("g_abstractMaterial"); g_iMaterialOffset = pMaterialVar->GetInterfaceSlot(0); // ...

Next we enumerate all possible permutations of material object that exist in the shader:

// Material Dynamic Permutation
enum E_MATERIAL_TYPES
{
   MATERIAL_PLASTIC,
   MATERIAL_PLASTIC_TEXTURED,
   MATERIAL_PLASTIC_LIGHTING_ONLY,

   MATERIAL_ROUGH,
   MATERIAL_ROUGH_TEXTURED,
   MATERIAL_ROUGH_LIGHTING_ONLY,

   MATERIAL_TYPE_COUNT
};
char*  g_pMaterialClassNames[ MATERIAL_TYPE_COUNT ] =
{
   "g_plasticMaterial",             // cPlasticMaterial
   "g_plasticTexturedMaterial",     // cPlasticTexturedMaterial
   "g_plasticLightingOnlyMaterial", // cPlasticLightingOnlyMaterial
   "g_roughMaterial",               // cRoughMaterial
   "g_roughTexturedMaterial",       // cRoughTexturedMaterial
   "g_roughLightingOnlyMaterial"    // cRoughLightingOnlyMaterial
};
E_MATERIAL_TYPES            g_iMaterial = MATERIAL_PLASTIC_TEXTURED;


// ...

// Acquire the material Class Instances for all possible material settings
for( UINT i=0; i < MATERIAL_TYPE_COUNT; i++)
{
   g_pPSClassLinkage->GetClassInstance( g_pMaterialClassNames[i], 0, &g_pMaterialClasses[i] );
}

shader中(如果显卡不支持DX11,则STATIC_PERMUTE为True):

#if !defined( STATIC_PERMUTE ) iBaseLight g_abstractAmbientLighting; ... iBaseMaterial g_abstractMaterial; #else ... #define g_abstractAmbientLighting g_ambientLight #define g_abstractDirectLighting g_directionalLight #define g_abstractEnvironmentLighting g_environmentLight #define g_abstractMaterial g_plasticMaterial #endif

App中(D3DX11CompileFromFile的第二个参数就是D3D10_SHADER_MACRO *pDefines,预定义列表。显然预定义改变,需重新编译):

  1.    // Compile the shader using optional defines and an include handler for header processing static const D3D_SHADER_MACRO Shader_Macros[] = { "STATIC_PERMUTE", "1", NULL, NULL }; ID3DBlob* pErrorBlob; hr = D3DX11CompileFromFile( szFileName, &Shader_Macros[0], pIncludeHandler, szEntryPoint, szShaderModel, flags, 0, NULL, ppBlobOut, &pErrorBlob, NULL ); ...

  2. // Expand compressed vectors
    tmpNormal = R10G10B10A2_UNORM_TO_R32G32B32_FLOAT( Input.vNormal );

    float3 R10G10B10A2_UNORM_TO_R32G32B32_FLOAT( in float3 vVec )
    {
    vVec *= 2.0f;
    return vVec >= 1.0f ? ( vVec - 2.0f ) : vVec;
    }

 3.场景渲染时,动态指定父类指针实际子类实例。

shader:

 //interface

interface iBaseMaterial

{

float3 GetAmbientColor(float2 vTexcoord);

float3 GetDiffuseColor(float2 vTexcoord);

int GetSpecularPower();

};

//class

class cBaseMaterial:iBaseMaterial

{

float3 m_color;

int m_specularPower;

float3 GetAmbientColor(float2 vTexcoord){return m_color}

float3 GetDiffuseColor(float2 vTexcoord){return m_color}

int GetSpecularPower(){return m_specularPower}

};

//////////////////////////PlasticMaterial/////////////////////////////

class cPlasticMaterial:cBaseMaterial

{};

class cPlasticTextureMaterial:cPlasticMaterial

{

float3 GetAmbientColor(float2 vTexcoord);

float3 GetDiffuseColor(float2 vTexcoord);

}

class cPlasticLightingOnlyMaterial : cBaseMaterial

{
float3 GetAmbientColor(float2 vTexcoord)
{
return (float3)1.0f;
}

float3 GetDiffuseColor(float2 vTexcoord)
{
return (float3)1.0f;
}

};

//////////////////////////RoughMaterial//////////////////////

class cRoughMaterial : cBaseMaterial
{
int GetSpecularPower()
{
return m_iSpecPower;
}
};

class cRoughTexturedMaterial : cRoughMaterial
{
float3 GetAmbientColor(float2 vTexcoord);

float3 GetDiffuseColor(float2 vTexcoord);

};

class cRoughLightingOnlyMaterial : cRoughMaterial
{
float3 GetAmbientColor(float2 vTexcoord)
{
return (float3)1.0f;
}

float3 GetDiffuseColor(float2 vTexcoord)
{
return (float3)1.0f;
}

};

float4 PSMain( PS_INPUT Input ) : SV_TARGET
{
float3 Ambient = (float3)0.0f;
Ambient = g_abstractMaterial.GetAmbientColor( Input.vTexcoord ) * g_abstractAmbientLighting.IlluminateAmbient( Input.vNormal );

float3 Diffuse = (float3)0.0f;

Diffuse += g_abstractMaterial.GetDiffuseColor( Input.vTexcoord ) * g_abstractDirectLighting.IlluminateDiffuse( Input.vNormal );

float3 Specular = (float3)0.0f;
Specular += g_abstractDirectLighting.IlluminateSpecular( Input.vNormal, g_abstractMaterial.GetSpecularPower() );
Specular += g_abstractEnvironmentLighting.IlluminateSpecular( Input.vNormal, g_abstractMaterial.GetSpecularPower() );

float3 Lighting = saturate( Ambient + Diffuse + Specular );

return float4(Lighting,1.0f);
}

App中:
设置shader中声明的Interface的具体子类实例。

// 初始化阶段, 相当于初始化shader中各interface子类实例

ID3D11ClassLinkage* g_pPSClassLinkage= NULL;

truct CB_PS_PER_PRIMITIVE
{ D3DXVECTOR4 m_vObjectColorPlastic; // Plastic -.w is Specular Power

D3DXVECTOR4 m_vObjectColorPlasticTextured; // Plastic -.w is Specular Power 

D3DXVECTOR4 m_vObjectColorPlasticLightingOnly; // Plastic - Lighting Only

D3DXVECTOR4 m_vObjectColorRough; // Rough Material -.w is Specular Power
D3DXVECTOR4 m_vObjectColorRoughTextured; // Rough Material -.w is Specular Power
D3DXVECTOR4 m_vObjectColorRoughLightingOnly; // Rough Material -.w is Specular Power

};

enum E_MATERIAL_TYPES
{
MATERIAL_PLASTIC,
MATERIAL_PLASTIC_TEXTURED,
MATERIAL_PLASTIC_LIGHTING_ONLY,

MATERIAL_ROUGH,
MATERIAL_ROUGH_TEXTURED,
MATERIAL_ROUGH_LIGHTING_ONLY,

MATERIAL_TYPE_COUNT
};

char* g_pMaterialClassNames[ MATERIAL_TYPE_COUNT ] =
{
"g_plasticMaterial", // cPlasticMaterial
"g_plasticTexturedMaterial", // cPlasticTexturedMaterial
"g_plasticLightingOnlyMaterial", // cPlasticLightingOnlyMaterial
"g_roughMaterial", // cRoughMaterial
"g_roughTexturedMaterial", // cRoughTexturedMaterial
"g_roughLightingOnlyMaterial" // cRoughLightingOnlyMaterial
};

// use shader reflection to get data locations for the interface array

//shader中的metadata可以被reflection调用
ID3D11ShaderReflection* pReflector = NULL;
V_RETURN( D3DReflect( pPixelShaderBuffer
->GetBufferPointer(), pPixelShaderBuffer->GetBufferSize(), IID_ID3D11ShaderReflection, (void**) &pReflector) );
g_iNumPSInterfaces
= pReflector->GetNumInterfaceSlots();
// shader中所有的interface指针构成的列表
g_dynamicLinkageArray = (ID3D11ClassInstance**) malloc( sizeof(ID3D11ClassInstance*) * g_iNumPSInterfaces );
ID3D11ShaderReflectionVariable* pMaterialVar = pReflector->GetVariableByName("g_abstractMaterial");
int g_iMaterialOffset = pMaterialVar->GetInterfaceSlot(0);
for( UINT i=0; i < MATERIAL_TYPE_COUNT; i++) { g_pPSClassLinkage->GetClassInstance( g_pMaterialClassNames[i], 0, &g_pMaterialClasses[i] ); //声明shader中各ClassInstance 


相关文章:

  • 2021-11-16
  • 2021-08-21
  • 2021-11-16
  • 2022-12-23
  • 2021-09-11
  • 2021-06-21
  • 2022-02-23
  • 2022-01-21
猜你喜欢
  • 2021-07-28
  • 2021-08-02
  • 2021-07-10
  • 2021-12-06
  • 2021-08-20
  • 2021-11-16
  • 2021-11-16
相关资源
相似解决方案