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

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

Эффект инкапсулирует все состояния отрисовки, необходимые для выполнения прохода отрисовки. С точки зрения 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();

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

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

           
OnD3D10FrameRender()
{
    ...
    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 );
}

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

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

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

D3D10_SAMPLER_DESC sampler_desc;
ID3D10EffectVariable* l_pD3D10EffectVariable = NULL;
if( g_pEffect10 )
{
    l_pD3D10EffectVariable = g_pEffect10->GetVariableByName( "MeshTextureSampler" );
    if( l_pD3D10EffectVariable )
        hr = (l_pD3D10EffectVariable->AsSampler())->GetBackingStore( 0, 
            &sampler_desc );
}

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

ID3D10SamplerState* l_ppSamplerState = NULL;
D3D10_SAMPLER_DESC sampler_desc;
ID3D10EffectVariable* l_pD3D10EffectVariable = NULL;
if( g_pEffect10 )
{
    l_pD3D10EffectVariable = g_pEffect10->GetVariableByName( "MeshTextureSampler" );
    if( l_pD3D10EffectVariable )
    {
        hr = (l_pD3D10EffectVariable->AsSampler())->GetSampler( 0, 
            &l_ppSamplerState );
        if( l_ppSamplerState )
            l_ppSamplerState->GetDesc( &sampler_desc );
    }
}

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

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

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

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

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

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

Texture2D g_MeshTexture;            // Color texture for mesh

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

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

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

ID3D10EffectShaderResourceVariable* g_ptxDiffuse = NULL;

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

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

   
OnD3D10FrameRender()
{
  ID3D10ShaderResourceView* pDiffuseRV = NULL;

   ...
   pDiffuseRV = g_Mesh10.GetMaterial(pSubset->MaterialID)->pDiffuseRV10;
   g_ptxDiffuse->SetResource( pDiffuseRV );
   ...
}   

Дополнительные сведения о просмотре ресурсов см. в разделе Представления текстур (Direct3D 10).

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