Bagikan melalui


Antarmuka dan kelas

Linkage shader dinamis menggunakan antarmuka dan kelas bahasa shader tingkat tinggi (HLSL) yang secara sintaksis mirip dengan rekan-rekan C++mereka. Ini memungkinkan shader untuk mereferensikan instans antarmuka abstrak pada waktu kompilasi dan meninggalkan resolusi instans tersebut ke kelas konkret untuk aplikasi saat runtime.

Bagian berikut merinci cara menyiapkan shader untuk menggunakan antarmuka dan kelas dan cara menginisialisasi instans antarmuka dalam kode aplikasi.

Mendeklarasikan antarmuka

Antarmuka berfungsi dengan cara yang sama dengan kelas dasar abstrak di C++. Antarmuka dideklarasikan dalam shader menggunakan kata kunci antarmuka dan hanya berisi deklarasi metode. Metode yang dideklarasikan dalam antarmuka semuanya akan menjadi metode virtual di kelas apa pun yang berasal dari antarmuka. Kelas turunan harus mengimplementasikan semua metode yang dideklarasikan dalam antarmuka. Perhatikan bahwa antarmuka adalah satu-satunya cara untuk mendeklarasikan metode virtual, tidak ada kata kunci virtual seperti dalam C++, dan kelas connot mendeklarasikan metode virtual.

Contoh kode shader berikut mendeklarasikan dua antarmuka.

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();

};
      

Mendeklarasikan Kelas

Kelas beraksi dengan cara yang sama dengan kelas di C++. Kelas dideklarasikan dengan kata kunci kelas dan dapat berisi variabel dan metode anggota. Kelas dapat mewarisi dari nol atau satu kelas dan nol atau lebih antarmuka. Kelas harus menerapkan atau mewarisi implementasi untuk semua antarmuka dalam rantai pewarisannya atau kelas tidak dapat dibuat instansnya.

Contoh kode shader berikut mengilustrasikan turunan kelas dari antarmuka dan dari kelas lain.

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);
};        
      

Deklarasi Instans Antarmuka dalam Shader

Instans antarmuka bertindak sebagai tempat penampung untuk instans kelas yang menyediakan implementasi metode antarmuka. Menggunakan instans antarmuka memungkinkan kode shader untuk memanggil metode tanpa mengetahui implementasi metode mana yang akan dipanggil. Kode shader mendeklarasikan satu atau beberapa instans untuk setiap antarmuka yang ditentukannya. Instans ini digunakan dalam kode shader dengan cara yang sama dengan pointer kelas dasar C++.

Contoh kode shader berikut mengilustrasikan mendeklarasikan beberapa instans antarmuka dan menggunakannya dalam kode shader.

// 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); 
}

Deklarasi Instans Kelas dalam Shader

Setiap kelas yang akan digunakan sebagai pengganti instans antarmuka harus dinyatakan sebagai variabel dalam buffer konstanta atau dibuat oleh aplikasi saat runtime menggunakan metode ID3D11ClassLinkage::CreateClassInstance . Instans antarmuka akan diacak ke instans kelas dalam kode aplikasi. Instans kelas dapat dirujuk dalam kode shader seperti variabel lain, tetapi kelas yang berasal dari antarmuka biasanya hanya akan digunakan dengan instans antarmuka dan tidak akan dirujuk oleh kode shader secara langsung.

Contoh kode shader berikut mengilustrasikan mendeklarasikan beberapa instans kelas.

cbuffer cbPerFrame : register( b0 )
{
   cAmbientLight     g_ambientLight;
   cHemiAmbientLight g_hemiAmbientLight;
   cDirectionalLight g_directionalLight;
   cEnvironmentLight g_environmentLight;
   float4            g_vEyeDir;   
};        
      

Menginisialisasi Instans Antarmuka dalam Aplikasi

Instans antarmuka diinisialisasi dalam kode aplikasi dengan meneruskan array tautan dinamis yang berisi penetapan antarmuka ke salah satu metode ID3D11DeviceContext SetShader.

Untuk membuat array tautan dinamis, gunakan langkah-langkah berikut

  1. Buat objek tautan kelas menggunakan CreateClassLinkage.

    ID3D11ClassLinkage* g_pPSClassLinkage = NULL;            
    pd3dDevice->CreateClassLinkage( &g_pPSClassLinkage );
    
    
  2. Buat shader yang akan menggunakan penautan kelas dinamis, meneruskan objek tautan kelas sebagai parameter ke fungsi buat shader.

    pd3dDevice->CreatePixelShader( pPixelShaderBuffer->GetBufferPointer(),
        pPixelShaderBuffer->GetBufferSize(), g_pPSClassLinkage, &g_pPixelShader ) );            
    
    
  3. Buat objek ID3D11ShaderReflection menggunakan fungsi D3DReflect .

    ID3D11ShaderReflection* pReflector = NULL; 
    D3DReflect( pPixelShaderBuffer->GetBufferPointer(),                  
        pPixelShaderBuffer->GetBufferSize(), 
        IID_ID3D11ShaderReflection, (void**) &pReflector) );            
    
    
  4. Gunakan objek refleksi shader untuk mendapatkan jumlah instans antarmuka di shader menggunakan metode ID3D11ShaderReflection::GetNumInterfaceSlots .

    g_iNumPSInterfaces = pReflector->GetNumInterfaceSlots();             
    
    
  5. Buat array yang cukup besar untuk menahan jumlah instans antarmuka di shader.

    ID3D11ClassInstance** g_dynamicLinkageArray = NULL;            
    g_dynamicLinkageArray = 
        (ID3D11ClassInstance**) malloc( sizeof(ID3D11ClassInstance*) * g_iNumPSInterfaces );            
    
    
  6. Tentukan indeks dalam array yang sesuai dengan setiap instans antarmuka menggunakan ID3D11ShaderReflection::GetVariableByName dan ID3D11ShaderReflectionVariable::GetInterfaceSlot.

    ID3D11ShaderReflectionVariable* pAmbientLightingVar = 
        pReflector->GetVariableByName("g_abstractAmbientLighting");
        g_iAmbientLightingOffset = pAmbientLightingVar->GetInterfaceSlot(0);            
    
    
  7. Dapatkan instans kelas untuk setiap objek kelas yang berasal dari antarmuka di shader menggunakan ID3D11ClassLinkage::GetClassInstance.

    g_pPSClassLinkage->GetClassInstance( "g_hemiAmbientLight", 0, 
        &g_pHemiAmbientLightClass );            
    
    
  8. Atur instans antarmuka ke instans kelas dengan mengatur entri yang sesuai dalam array tautan dinamis.

    g_dynamicLinkageArray[g_iAmbientLightingOffset] = g_pHemiAmbientLightClass;            
    
    
  9. Teruskan array tautan dinamis sebagai parameter ke panggilan SetShader.

    pd3dImmediateContext->PSSetShader( g_pPixelShader, g_dynamicLinkageArray, g_iNumPSInterfaces );            
    
    

Penautan Dinamis