動的シェーダー リンケージでは、高度なシェーダー言語 (HLSL) インターフェイスと、対応する C++ と構文的に似たクラスが使用されます。 これにより、シェーダーはコンパイル時に抽象インターフェイス インスタンスを参照し、実行時にそれらのインスタンスの解決をアプリケーションの具象クラスに残すことができます。
次のセクションでは、インターフェイスとクラスを使用するようにシェーダーを設定する方法と、アプリケーション コードでインターフェイス インスタンスを初期化する方法について詳しく説明します。
- インターフェイス を宣言する
- クラス を宣言する
- シェーダー でのインターフェイス インスタンス宣言の
- シェーダー でのクラス インスタンス宣言の
- アプリケーション でのインターフェイス インスタンスの初期化の
- 関連トピック
インターフェイスの宣言
インターフェイスは、C++ の抽象基底クラスと同様の方法で関数します。 インターフェイスは、interface キーワードを使用してシェーダーで宣言され、メソッド宣言のみが含まれます。 インターフェイスで宣言されたメソッドはすべて、インターフェイスから派生したすべてのクラスの仮想メソッドになります。 派生クラスは、インターフェイスで宣言されているすべてのメソッドを実装する必要があります。 インターフェイスは仮想メソッドを宣言する唯一の方法であり、C++ のように仮想キーワードはなく、クラスは仮想メソッドを宣言しません。
次のシェーダー コード例では、2 つのインターフェイスを宣言しています。
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();
};
クラスの宣言
クラスは、C++ のクラスと同様の方法で動作します。 クラスはクラス キーワードを使用して宣言され、メンバー変数とメソッドを含めることができます。 1 つのクラスは、0 個または 1 つのクラスと 0 個以上のインターフェイスから継承できます。 クラスは、継承チェーン内のすべてのインターフェイスの実装を実装または継承する必要があります。または、クラスをインスタンス化できません。
次のシェーダー コード例は、インターフェイスと別のクラスからクラスを派生する方法を示しています。
class cAmbientLight : iBaseLight
{
float3 m_vLightColor;
bool m_bEnable;
float3 IlluminateAmbient(float3 vNormal);
float3 IlluminateDiffuse(float3 vNormal);
float3 IlluminateSpecular(float3 vNormal, int specularPower );
};
class cHemiAmbientLight : cAmbientLight
{
float4 m_vGroundColor;
float4 m_vDirUp;
float3 IlluminateAmbient(float3 vNormal);
};
シェーダーのインターフェイス インスタンス宣言
インターフェイス インスタンスは、インターフェイスのメソッドの実装を提供するクラス インスタンスのプレース ホルダーとして機能します。 インターフェイスのインスタンスを使用すると、呼び出されるメソッドの実装を知らなくても、シェーダー コードでメソッドを呼び出すことができます。 シェーダー コードは、定義するインターフェイスごとに 1 つ以上のインスタンスを宣言します。 これらのインスタンスは、C++ 基本クラス ポインターと同様の方法でシェーダー コードで使用されます。
次のシェーダー コード例は、複数のインターフェイス インスタンスを宣言し、シェーダー コードで使用する方法を示しています。
// Declare interface instances
iBaseLight g_abstractAmbientLighting;
iBaseLight g_abstractDirectLighting;
iBaseMaterial g_abstractMaterial;
struct PS_INPUT
{
float4 vPosition : SV_POSITION;
float3 vNormal : NORMAL;
float2 vTexcoord : TEXCOORD0;
};
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() );
float3 Lighting = saturate( Ambient + Diffuse + Specular );
return float4(Lighting,1.0f);
}
シェーダーでのクラス インスタンス宣言
インターフェイス インスタンスの代わりに使用される各クラスは、定数バッファー内の変数として宣言するか、ID3D11ClassLinkage::CreateClassInstance メソッドを使用して実行時にアプリケーションによって作成される必要があります。 インターフェイス インスタンスは、アプリケーション コード内のクラス インスタンスを指します。 クラス インスタンスは他の変数と同様にシェーダー コードで参照できますが、通常、インターフェイスから派生したクラスはインターフェイス インスタンスでのみ使用され、シェーダー コードによって直接参照されることはありません。
次のシェーダー コード例は、複数のクラス インスタンスの宣言を示しています。
cbuffer cbPerFrame : register( b0 )
{
cAmbientLight g_ambientLight;
cHemiAmbientLight g_hemiAmbientLight;
cDirectionalLight g_directionalLight;
cEnvironmentLight g_environmentLight;
float4 g_vEyeDir;
};
アプリケーションでのインターフェイス インスタンスの初期化
インターフェイス インスタンスは、ID3D11DeviceContext SetShader メソッドのいずれかにインターフェイス割り当てを含む動的リンケージ配列を渡すことによって、アプリケーション コードで初期化されます。
動的リンケージ配列を作成するには、次の手順に従います。
CreateClassLinkageを使用してクラス リンケージ オブジェクト作成します。
ID3D11ClassLinkage* g_pPSClassLinkage = NULL; pd3dDevice->CreateClassLinkage( &g_pPSClassLinkage );
動的クラス リンクを使用するシェーダーを作成し、クラス リンケージ オブジェクトをシェーダーの create 関数にパラメーターとして渡します。
pd3dDevice->CreatePixelShader( pPixelShaderBuffer->GetBufferPointer(), pPixelShaderBuffer->GetBufferSize(), g_pPSClassLinkage, &g_pPixelShader ) );
D3DReflect 関数を使用して、ID3D11ShaderReflection オブジェクトを作成します。
ID3D11ShaderReflection* pReflector = NULL; D3DReflect( pPixelShaderBuffer->GetBufferPointer(), pPixelShaderBuffer->GetBufferSize(), IID_ID3D11ShaderReflection, (void**) &pReflector) );
シェーダー リフレクション オブジェクトを使用して、ID3D11ShaderReflection::GetNumInterfaceSlots メソッドを使用してシェーダー内のインターフェイス インスタンスの数を取得します。
g_iNumPSInterfaces = pReflector->GetNumInterfaceSlots();
シェーダー内のインターフェイス インスタンスの数を保持するのに十分な大きさの配列を作成します。
ID3D11ClassInstance** g_dynamicLinkageArray = NULL; g_dynamicLinkageArray = (ID3D11ClassInstance**) malloc( sizeof(ID3D11ClassInstance*) * g_iNumPSInterfaces );
ID3D11ShaderReflection::GetVariableByName と ID3D11ShaderReflectionVariable::GetInterfaceSlotを使用して、各インターフェイス インスタンスに対応する配列内のインデックスを決定します。
ID3D11ShaderReflectionVariable* pAmbientLightingVar = pReflector->GetVariableByName("g_abstractAmbientLighting"); g_iAmbientLightingOffset = pAmbientLightingVar->GetInterfaceSlot(0);
ID3D11ClassLinkage::GetClassInstanceを使用して、シェーダー内のインターフェイスから派生した各クラス オブジェクトのクラス インスタンスを取得します。
g_pPSClassLinkage->GetClassInstance( "g_hemiAmbientLight", 0, &g_pHemiAmbientLightClass );
動的リンケージ配列の対応するエントリを設定して、インターフェイス インスタンスをクラス インスタンスに設定します。
g_dynamicLinkageArray[g_iAmbientLightingOffset] = g_pHemiAmbientLightClass;
動的リンケージ配列をパラメーターとして SetShader 呼び出しに渡します。
pd3dImmediateContext->PSSetShader( g_pPixelShader, g_dynamicLinkageArray, g_iNumPSInterfaces );
関連トピック
動的リンク の