Программирование графических процессоров с использованием Direct3D и HLSL


Файлы эффектов


В состав библиотеки Direct3D входит набор средств, которые предоставляют некий оберточный механизм для работы с вершинными и пиксельными шейдерами, установкой текстурных состояний и константами. Данная возможность реализуется с помощью интерфейса ID3DXEffect. Данный "оберточный" интерфейс инкапсулирует в себе следующие особенности:

  • Содержат глобальные переменные, которые можно устанавливать из приложения;
  • Позволяют манипулировать (управлять) состоянием механизма воспроизведения;
  • Управляют текстурными состояниями и состояниями семплеров (определяют файлы текстур, инициализируют текстурные уровни и их настройки);
  • Управляют механизмом визуализации с помощью шейдеров;

Рассмотрим пример использования файлов эффектов, написанных на языке HLSL. Ниже представлен простейший пример файла эффектов.

float4x4 WorldViewProj; float4x4 World; float4 Light;

texture Tex0 < string name = "texture.bmp"; >;

struct VS_INPUT { float4 position : POSITION; float3 normal : NORMAL; float2 texcoord : TEXCOORD0; };

struct VS_OUTPUT { float4 position : POSITION; float4 color : COLOR0; float2 texcoord : TEXCOORD0; };

VS_OUTPUT main_vs( VS_INPUT In ) { VS_OUTPUT Out; Out.position = mul( In.position, WorldViewProj ); float3 pos = mul( In.position, World ); float3 light = normalize(vecLight-pos); float3 normal = normalize(mul( In.normal, World )); float4 green = {0.0f, 1.0f, 0.0f, 1.0f}; Out.texcoord = In.texcoord; Out.color = green*dot(light, normal); return Out; }

sampler Sampler = sampler_state { Texture = (Tex0); MipFilter = LINEAR; MinFilter = LINEAR; MagFilter = LINEAR; };

struct PS_INPUT { float2 texcoord : TEXCOORD0; float4 color : COLOR0; };

float4 main_ps( PS_INPUT In ) : COLOR0 { return tex2D(Sampler, In.texcoord ) * In.color; }

technique tec0 { pass p0 { VertexShader = compile vs_1_1 main_vs(); PixelShader = compile ps_1_1 main_ps(); } }

Пример 6.2.

Как видно из представленного примера, файлы эффектов объединяют в себе вершинный, пиксельный шейдеры, а также различные настройки режима воспроизведения.



Кроме того, файлы эффектов позволяют объединить ряд вариантов воспроизведения в одном файле. Такая модульность открывает широкие возможности по использованию одной программы на различных аппаратных решениях (компьютерах с различными техническими возможностями). Каждый файл эффектов может содержать один и более разделов technique, которые как раз и предназначены для различных способов реализации алгоритма воспроизведения. Каждый раздел techniques может содержать внутри себя один и более разделов rendering pass, которые объединяют в себе состояния устройства вывода, текстурные уровни, шейдеры. Следует заметить, что файлы эффектов не ограничены в использовании только программируемых элементов графического конвейера (шейдеров). Они также могут использоваться и в фиксированном конвейере для управления состояниями устройства вывода, источниками света, материала ми и текстурами. Применение нескольких разделов rendering pass позволяют получить различные эффекты визуализации, например, двухпроходный алгоритм построения тени с использованием буфера трафарета. Ниже представлен шаблон файла эффектов, в котором присутствует два раздела technique, плюс к этому второй раздел содержит два подраздела rendering pass.

technique tec0 { pass p0 // первый и единственный раздел rendering pass { // состояние устройства вывода, шейдеры, семплеры } }

technique tec1 { pass p0 // первый rendering pass { // состояние устройства вывода, шейдеры, семплеры }

pass p1 // второй раздел rendering pass { // состояние устройства вывода, шейдеры, семплеры } }

Для управления файлами эффектов из приложения необходимо воспользоваться методами интерфейса ID3DXEffect. Вначале необходимо объявить переменную интерфейсного типа ID3DXEffect, и возможно переменную для буфера ошибок.

C++

LPD3DXEFFECT Effect = NULL; LPD3DXBUFFER BufferErrors = NULL;
Pascal

var Effect: ID3DXEffect; BufferErrors: ID3DXBuffer;
Для загрузки и компиляции файла эффектов предназначена функция D3DXCreateEffectFromFile(), которая имеет следующие параметры:



  • Ссылка на устройство вывода;
  • Имя файла эффекта;
  • Набор макро определений (может быть пустым);
  • Указатель на интерфейс ID3DXInclude для обработки включений в файле эффекта (может быть пустым);
  • Набор флагов компиляции (может быть нулем);
  • Указатель на интерфейс ID3DXEffectPool для обработки общих параметров в эффекте (может быть пустым);
  • Указатель на полученный результат;
  • Указатель на буфер ошибок.
C++

D3DXCreateEffectFromFile( device, "effect.fx", NULL, NULL, 0, NULL, &Effect, &BufferErrors)
Pascal

D3DXCreateEffectFromFile(device, ' effect.fx ', nil, nil, 0, nil, Effect, BufferErrors);
Следующим шагом является установка активного раздела technique. Это реализуется с помощью вызова метода SetTechnique интерфейса ID3DXEffect, где в качестве параметра передается название раздела technique.

C++Effect->SetTechnique("tec0");
PascalEffect.SetTechnique('tec0');
Затем необходимо определить количество рендер проходов (разделов rendering pass), которые будут выполняться. Делается это при помощи вызова метода Begin интерфейса ID3DXEffect, который имеет два параметра: первый параметр – возвращаемое значение количества разделов pass и второй параметр – флаг, указывающий на необходимость сохранения состояния режимов воспроизведения (значение ноль). И заключительный шаг состоит в организации цикла по всех разделам rendering pass с активацией текущего на каждом шаге. На каждой итерации вызывается необходимый код вывода примитива.

C++

unsigned int numPasses = 0;

Effect->Begin(&numPasses, 0); for(unsigned int pass = 0; pass < numPasses; pass++) { Effect->BeginPass(pass); device->DrawPrimitive(...); Effect->EndPass(); } Effect->End();
Pascal

var numPasses: DWord; pass: DWord; ... Effect._Begin(@numPasses, 0); for pass:=0 to numPasses-1 do begin Effect.BeginPass(pass); Device.DrawPrimitive(...); Effect.EndPass; end; Effect._End;
Также как и в программах, написанных на языке HLSL, в файлы эффектов можно передавать параметры. Установка значений параметров осуществляется через вызов методов SetXXX интерфейса ID3DXEffect.Ниже представлены основные методы передачи параметров в файл эффектов:

SetBool() SetInt() SetMatrix() SetString() SetTexture() SetVector()

Следует отметить еще одно достоинство файлов эффектов. Для работы с ними существует программа EffectEdit, которая поставляет вместе с DirectX SDK. Эта программа позволяет загружать файлы эффектов и осуществлять рендеринг сцены при установленных настройках графического конвейера (шейдеров, текстур, состоянийустройства воспроизведения и др.). Кроме того, утилита EffectEdit может быть использована в качестве отладочного механизма ваших шейдерных программ.


Содержание раздела