(参照例子DXSDK sample:DynamicShaderLinkage11)
一、preprocessor
实现shader静态分支的经典方法,代码示例如下
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,预定义列表。显然预定义改变,需重新编译):
-
... // 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 ); ...
二、Dynamic Shader Linkage
在shader实现OO框架,当场景渲染时,动态指定父类指针实际子类实例。
shader中:
//-------------------------------------------------------------------------------------- // Interfaces //-------------------------------------------------------------------------------------- interface iBaseMaterial { float3 GetAmbientColor(float2 vTexcoord); float3 GetDiffuseColor(float2 vTexcoord); int GetSpecularPower(); }; //-------------------------------------------------------------------------------------- // Classes //-------------------------------------------------------------------------------------- class cBaseMaterial : iBaseMaterial { float3 m_vColor; int m_iSpecPower; float3 GetAmbientColor(float2 vTexcoord) { return m_vColor; } float3 GetDiffuseColor(float2 vTexcoord) { return (float3)m_vColor; } int GetSpecularPower() { return m_iSpecPower; } }; class cPlasticMaterial : cBaseMaterial { }; class cPlasticTexturedMaterial : cPlasticMaterial { ... }; class cPlasticLightingOnlyMaterial : cBaseMaterial { ... } cbuffer cbPerPrimitive : register( b1 ) { cPlasticMaterial g_plasticMaterial; cPlasticTexturedMaterial g_plasticTexturedMaterial; ... }; ... 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 ); ... float3 Lighting = saturate( Ambient + Diffuse + Specular ); return float4(Lighting,1.0f); }
App中:
设置shader中声明的Interface的具体子类实例。// 初始化阶段, 相当于初始化shader中各interface子类实例 ID3D11ClassLinkage* g_pPSClassLinkage= NULL; struct CB_PS_PER_PRIMITIVE { D3DXVECTOR4 m_vObjectColorPlastic; // Plastic -.w is Specular Power D3DXVECTOR4 m_vObjectColorPlasticTextured; // Plastic -.w is Specular Power ... }; // Material Dynamic Permutation enum E_MATERIAL_TYPES { MATERIAL_PLASTIC, ... MATERIAL_ROUGH, ... MATERIAL_TYPE_COUNT }; char* g_pMaterialClassNames[ MATERIAL_TYPE_COUNT ] = { "g_plasticMaterial", // cPlasticMaterial "g_plasticTexturedMaterial", // cPlasticTexturedMaterial ... }; E_MATERIAL_TYPES g_iMaterial = MATERIAL_PLASTIC_TEXTURED; ID3D11ClassInstance* g_pMaterialClasses[ MATERIAL_TYPE_COUNT ] = { NULL }; UINT g_iMaterialOffset = 0; ID3D11ClassInstance** g_dynamicLinkageArray = NULL; V_RETURN( pd3dDevice->CreateClassLinkage( &g_pPSClassLinkage ) ); ... V_RETURN( pd3dDevice->CreatePixelShader( pPixelShaderBuffer->GetBufferPointer(), pPixelShaderBuffer->GetBufferSize(), g_pPSClassLinkage, &g_pPixelShader ) ); ... // use shader reflection to get data locations for the interface array 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 ); if (g_dynamicLinkageArray == NULL) return E_FAIL; ... ID3D11ShaderReflectionVariable* pMaterialVar = pReflector->GetVariableByName("g_abstractMaterial"); int g_iMaterialOffset = pMaterialVar->GetInterfaceSlot(0); ... // 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中各ClassInstance } ... // FrameRender阶段 switch( g_iMaterial ) { // 与界面控件绑定,指定interface指针实际子类实例 case MATERIAL_PLASTIC: case MATERIAL_PLASTIC_TEXTURED: { ... g_dynamicLinkageArray[g_iMaterialOffset] = g_pMaterialClasses[ g_iMaterial ] ; } case MATERIAL_ROUGH: case MATERIAL_ROUGH_TEXTURED: { ... g_dynamicLinkageArray[g_iMaterialOffset] = g_pMaterialClasses[ g_iMaterial ] ; } } ... // PS Per Prim。初始化各实例中的成员变量,每个实例成员变量大小为Float4,即shader中的 (float3 m_vColor; int m_iSpecPower) int iSpecPower = 128; V( pd3dImmediateContext->Map( g_pcbPSPerPrim, 0, D3D11_MAP_WRITE_DISCARD, 0, &MappedResource ) ); CB_PS_PER_PRIMITIVE* pPSPerPrim = ( CB_PS_PER_PRIMITIVE* )MappedResource.pData; ... pPSPerPrim->m_vObjectColorPlasticTextured = D3DXVECTOR4( 1, 0, 0.5, 0 ); // Shiny Plastic with Textures memcpy( &(pPSPerPrim->m_vObjectColorPlasticTextured.w), &iSpecPower, sizeof(int)); ... iSpecPower = 6; pPSPerPrim->m_vObjectColorRoughTextured = D3DXVECTOR4( 0, .5, 1, 0 ); // Rough Material with Textures memcpy( &(pPSPerPrim->m_vObjectColorRoughTextured.w), &iSpecPower, sizeof(int)); ... pd3dImmediateContext->Unmap( g_pcbPSPerPrim, 0 ); pd3dImmediateContext->PSSetConstantBuffers( g_iCBPSPerPrimBind, 1, &g_pcbPSPerPrim );