Интерфейсы и классы в эффектах

В эффектах 11 существует множество способов использования классов и интерфейсов. Сведения об интерфейсе и синтаксисе классов см. в разделе Интерфейсы и классы.

В следующих разделах подробно описано, как указать экземпляры класса для шейдера, использующего интерфейсы. В примерах мы будем использовать следующий интерфейс и классы:

interface IColor
{
  float4 GetColor();
};

class CRed : IColor
{
  float4 GetColor() { return float4(1,0,0,1); }
};
class CGreen : IColor
{
  float4 GetColor() { return float4(0,1,0,1); }
};

CRed pRed;
CGreen pGreen;
IColor pIColor;
IColor pIColor2 = pRed;

Обратите внимание, что экземпляры интерфейса можно инициализировать в экземпляры класса . Массивы экземпляров класса и интерфейса также поддерживаются и их можно инициализировать, как показано в следующем примере:

CRed pRedArray[2];
IColor pIColor3 = pRedArray[1];
IColor pIColorArray[2] = {pRed, pGreen};
IColor pIColorArray2[2] = pRedArray;

Универсальные параметры интерфейса

Как и другие универсальные типы данных, в вызове CompileShader необходимо указать параметры универсального интерфейса. Параметры интерфейса можно назначить экземплярам глобального интерфейса или экземплярам глобального класса. При назначении экземпляру глобального интерфейса шейдер будет иметь зависимость от экземпляра интерфейса, что означает, что ему необходимо задать экземпляр класса . При назначении экземплярам глобального класса компилятор специализирует шейдер (как и другие универсальные типы данных) для использования этого класса. Это важно для двух сценариев:

  1. Шейдеры с целевым объектом 4_x могут использовать параметры интерфейса, если эти параметры являются однородными и назначены экземплярам глобального класса (поэтому динамическая компоновка не используется).
  2. Пользователи могут принимать решение о наличии большого количества скомпилированных специализированных шейдеров без динамической компоновки или нескольких скомпилированных шейдеров с динамической компоновкой.
float4 PSUniform( uniform IColor color ) : SV_Target
{
  return color;
}

technique11
{
  pass
  {
    SetPixelShader( CompileShader( ps_4_0, PSUniform(pRed) ) );
  }
  pass
  {
    SetPixelShader( CompileShader( ps_5_0, PSUniform(pIColor2) ) );
  }
}

Если pIColor2 остается без изменений через API, то два предыдущих прохода функционально эквивалентны, но первый использует ps_4_0 статический шейдер, а второй использует ps_5_0 шейдер с динамической компоновкой. Если pIColor2 изменяется с помощью API эффектов (см. раздел Настройка экземпляров классов ниже), поведение пиксельного шейдера во втором проходе может измениться.

Неоднородные параметры интерфейса

Неоднородные параметры интерфейса создают зависимости интерфейса для шейдеров. При применении шейдера с параметрами интерфейса эти параметры необходимо назначить в с помощью вызова BindInterfaces. Экземпляры глобального интерфейса и экземпляры глобального класса можно указать в вызове BindInterfaces.

float4 PSAbstract( IColor color ) : SV_Target
{
  return color;
}

PixelShader pPSAbstract = CompileShader( ps_5_0, PSAbstract(pRed) );

technique11
{
  pass
  {
    SetPixelShader( BindInterfaces( pPSAbstract, pRed ) );
  }
  pass
  {
    SetPixelShader( BindInterfaces( pPSAbstract, pIColor2 ) );
  }
}

Если pIColor2 остается неизменным с помощью API, то предыдущие два прохода функционально эквивалентны и используют динамическую компоновку. Если pIColor2 изменяется с помощью API эффектов (см. раздел Настройка экземпляров классов ниже), поведение пиксельного шейдера во втором проходе может измениться.

Задание экземпляров класса

При настройке шейдера с динамической компоновкой шейдера для устройства Direct3D 11 также необходимо указать экземпляры классов. Установка такого шейдера с экземпляром класса NULL является ошибкой. Поэтому все экземпляры интерфейса, на которые ссылается шейдер, должны иметь связанный экземпляр класса.

В следующем примере показано, как получить переменную экземпляра класса из эффекта и задать для нее переменную интерфейса:

ID3DX11EffectPass* pPass = pEffect->GetTechniqueByIndex(0)->GetPassByIndex(1);

ID3DX11EffectInterfaceVariable* pIface = pEffect->GetVariableByName( "pIColor2" )->AsInterface();
ID3DX11EffectClassInstanceVariable* pCI = pEffect->GetVariableByName( "pGreen" )->AsClassInstance();
pIface->SetClassInstance( pCI );
pPass->Apply( 0, pDeviceContext );

// Apply the same pass with a different class instance
pCI = pEffect->GetVariableByName( "pRedArray" )->GetElement(1)->AsClassInstance();
pIface->SetClassInstance( pCI );
pPass->Apply( 0, pDeviceContext );

Эффекты (Direct3D 11)