Поделиться через


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

Существует множество способов использования классов и интерфейсов в Effects 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)