(参照例子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 processingstatic 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 termfloat3 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 PowerD3DXVECTOR4 m_vObjectColorPlasticTextured; // Plastic -.w is Specular Power ...};// Material Dynamic Permutationenum 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 arrayID3D11ShaderReflection* 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 settingsfor( 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 Texturesmemcpy( &(pPSPerPrim->m_vObjectColorPlasticTextured.w), &iSpecPower, sizeof(int));...iSpecPower = 6;pPSPerPrim->m_vObjectColorRoughTextured = D3DXVECTOR4( 0, .5, 1, 0 ); // Rough Material with Texturesmemcpy( &(pPSPerPrim->m_vObjectColorRoughTextured.w), &iSpecPower, sizeof(int));...pd3dImmediateContext->Unmap( g_pcbPSPerPrim, 0 );pd3dImmediateContext->PSSetConstantBuffers( g_iCBPSPerPrimBind, 1, &g_pcbPSPerPrim );