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


Настройка состояния эффекта (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). Другими словами, каждый из этих вызовов CompilShader компилирует связанную функцию шейдера и возвращает указатель на скомпилированный шейдер.

Обратите внимание, что не все состояния шейдера должны быть заданы. Этот проход не включает вызовы 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)