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


Задать состояние эффекта (Direct3D 11)

Необходимо только инициализировать некоторые константы эффекта. После инициализации состояние эффекта устанавливается на устройство для всего цикла отрисовки. Другие переменные необходимо обновлять при каждом вызове цикла отрисовки. Ниже показан базовый код для задания переменных эффекта для каждого типа переменных.

Эффект инкапсулирует все состояние отрисовки, необходимое для выполнения прохода отрисовки. С точки зрения API существует три типа состояния, инкапсулированных в эффекте.

Константное состояние

Сначала объявите переменные в эффекте с помощью типов данных HLSL.

//--------------------------------------------------------------------------------------
// Global variables
//--------------------------------------------------------------------------------------
float4 g_MaterialAmbientColor;      // Material's ambient color
float4 g_MaterialDiffuseColor;      // Material's diffuse color
int g_nNumLights;

float3 g_LightDir[3];               // Light's direction in world space
float4 g_LightDiffuse[3];           // Light's diffuse color
float4 g_LightAmbient;              // Light's ambient color

Texture2D g_MeshTexture;            // Color texture for mesh

float    g_fTime;                   // App's time in seconds
float4x4 g_mWorld;                  // World matrix for object
float4x4 g_mWorldViewProjection;    // World * View * Projection matrix

Во-вторых, объявите в приложении переменные, которые могут быть заданы приложением, а затем обновит переменные эффекта.

           
    D3DXMATRIX  mWorldViewProjection;
    D3DXVECTOR3 vLightDir[MAX_LIGHTS];
    D3DXVECTOR4 vLightDiffuse[MAX_LIGHTS];
    D3DXMATRIX  mWorld;
    D3DXMATRIX  mView;
    D3DXMATRIX  mProj;

    // Get the projection and view matrix from the camera class
    mWorld = g_mCenterMesh * *g_Camera.GetWorldMatrix();
    mProj = *g_Camera.GetProjMatrix();
    mView = *g_Camera.GetViewMatrix();

    
OnD3D11CreateDevice()
{
  ...
    g_pLightDir = g_pEffect11->GetVariableByName( "g_LightDir" )->AsVector();
    g_pLightDiffuse = g_pEffect11->GetVariableByName( "g_LightDiffuse" )->AsVector();
    g_pmWorldViewProjection = g_pEffect11->GetVariableByName( 
        "g_mWorldViewProjection" )->AsMatrix();
    g_pmWorld = g_pEffect11->GetVariableByName( "g_mWorld" )->AsMatrix();
    g_pfTime = g_pEffect11->GetVariableByName( "g_fTime" )->AsScalar();
    g_pMaterialAmbientColor = g_pEffect11->GetVariableByName("g_MaterialAmbientColor")->AsVector();
    g_pMaterialDiffuseColor = g_pEffect11->GetVariableByName( 
        "g_MaterialDiffuseColor" )->AsVector();
    g_pnNumLights = g_pEffect11->GetVariableByName( "g_nNumLights" )->AsScalar();
}

В-третьих, используйте методы обновления, чтобы задать значение переменных в приложении в переменных эффекта.

           
OnD3D11FrameRender()
{
    ...
    g_pLightDir->SetRawValue( vLightDir, 0, sizeof(D3DXVECTOR3)*MAX_LIGHTS );
    g_pLightDiffuse->SetFloatVectorArray( (float*)vLightDiffuse, 0, MAX_LIGHTS );
    g_pmWorldViewProjection->SetMatrix( (float*)&mWorldViewProjection );
    g_pmWorld->SetMatrix( (float*)&mWorld );
    g_pfTime->SetFloat( (float)fTime );
    g_pnNumLights->SetInt( g_nNumActiveLights );
}

Два способа получения состояния в переменной эффекта

Существует два способа получить состояние, содержащееся в переменной эффекта. При использовании эффекта, загруженного в память.

Один из способов — получить состояние выборки из ID3DX11EffectVariable , который был приведен в качестве интерфейса выборки.

D3D11_SAMPLER_DESC sampler_desc;
ID3D11EffectSamplerVariable* l_pD3D11EffectVariable = NULL;
if( g_pEffect11 )
{
    l_pD3D11EffectVariable = g_pEffect11->GetVariableByName( "MeshTextureSampler" )->AsSampler();
    if( l_pD3D11EffectVariable->IsValid() )
        hr = (l_pD3D11EffectVariable->GetBackingStore( 0, 
            &sampler_desc );
}

Другой способ — получить состояние выборки из ID3D11SamplerState.

ID3D11SamplerState* l_ppSamplerState = NULL;
D3D11_SAMPLER_DESC sampler_desc;
ID3D11EffectSamplerVariable* l_pD3D11EffectVariable = NULL;
if( g_pEffect11 )
{
    l_pD3D11EffectVariable = g_pEffect11->GetVariableByName( "MeshTextureSampler" )->AsSampler();
    if( l_pD3D11EffectVariable->IsValid )
    {
        hr = l_pD3D11EffectVariable->GetSampler( 0, 
            &l_ppSamplerState );
        if( l_ppSamplerState )
            l_ppSamplerState->GetDesc( &sampler_desc );
    }
}

Состояние шейдера

Состояние шейдера объявляется и назначается в методе эффекта в пределах прохода.

VertexShader vsRenderScene = CompileShader( vs_4_0, RenderSceneVS( 1, true, true );  
technique10 RenderSceneWithTexture1Light
{
    pass P0
    {
        SetVertexShader( vsRenderScene );
        SetGeometryShader( NULL );
        SetPixelShader( CompileShader( ps_4_0, RenderScenePS( true ) ) );
    }
}

Это работает так же, как если бы вы не использовали эффект. Существует три вызова, по одному для каждого типа шейдера (вершина, геометрия и пиксель). Первый, SetVertexShader, вызывает ID3D11DeviceContext::VSSetShader. CompileShader — это функция специальных эффектов, которая принимает профиль шейдера (vs_4_0) и имя функции вершинного шейдера (RenderVS). Другими словами, каждый из этих вызовов CompileShader компилирует связанную функцию шейдера и возвращает указатель на скомпилированный шейдер.

Обратите внимание, что не все состояния шейдера должны быть заданы. Этот проход не включает вызовы SetHullShader или SetDomainShader, что означает, что привязанные в настоящее время шейдеры оболочки и предметной области будут без изменений.

Состояние текстуры

Состояние текстуры немного сложнее, чем задание переменной, так как данные текстуры не просто считываются как переменная, а извлекается из текстуры. Поэтому необходимо определить переменную текстуры (так же, как обычная переменная, за исключением того, что она использует тип текстуры) и условия выборки. Ниже приведен пример объявления переменной текстуры и соответствующего объявления состояния выборки.

Texture2D g_MeshTexture;            // Color texture for mesh

SamplerState MeshTextureSampler
{
    Filter = MIN_MAG_MIP_LINEAR;
    AddressU = Wrap;
    AddressV = Wrap;
};

Ниже приведен пример настройки текстуры из приложения. В этом примере текстура хранится в данных сетки, которые были загружены при создании эффекта.

Первый шаг — получение указателя на текстуру из эффекта (из сетки).

ID3D11EffectShaderResourceVariable* g_ptxDiffuse = NULL;

// Obtain variables
g_ptxDiffuse = g_pEffect11->GetVariableByName( "g_MeshTexture" )->AsShaderResource();

Второй шаг — указание представления для доступа к текстуре. Представление определяет общий способ доступа к данным из ресурса текстуры.

   
OnD3D11FrameRender()
{
  ID3D11ShaderResourceView* pDiffuseRV = NULL;

  ...
  pDiffuseRV = g_Mesh11.GetMaterial(pSubset->MaterialID)->pDiffuseRV11;
  g_ptxDiffuse->SetResource( pDiffuseRV );
  ...
}   

С точки зрения приложения неупорядоченные представления доступа обрабатываются аналогично представлениям ресурсов шейдера. Однако в функциях шейдера текстуры и шейдера вычислений неупорядоченные данные представления доступа считываются из или записываются напрямую. Вы не можете выполнить выборку из представления неупорядоченного доступа.

Дополнительные сведения о просмотре ресурсов см. в разделе Ресурсы.

Отрисовка эффекта (Direct3D 11)