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


Мультитекстурирование


Библиотека Direct3D позволяет накладывать на один полигон не одну, а сразу несколько текстур. Наложение на грань нескольких текстур называется мультитекстурированием. На текущий момент поддерживается до 8 наложений (уровней) текстур на одну грань. Схему (принцип) мультитекстурирования можно описать следующим образом. Первый текстурный уровень (с индексом 0) принимает на вход два значения: цвет текселя и диффузный цвет вершины; производит с ними указанные операции и передает результат на следующий (нижний) уровень. Полученное на предыдущем уровне значение цвета используется в качестве одного из аргумента текущего уровня и т.д. Схематично данные шаги мультитекстурирования можно представить так:


Как уже стало ясно, при мультитекстурировании дело имеют уже с несколькими текстурами. При мультитекстурировании можно для каждого текстурного уровня назначить одни и те же текстурные координаты. В этом случае формат вершины и набор флагов FVF останутся неизмененными. Существует возможность указать, с какими текстурными координатами будет работать тот или иной текстурный уровень. Для этого можно воспользоваться следующими программными строками:

SetTextureStageState(<уровень>, D3DTSS_TEXCOORDINDEX, <номер координат>);

Так, например, чтобы указать, что второй уровень будет использовать текстурные координаты первого текстурного уровня, достаточно воспользоваться следующим вызовом метода: SetTextureStageState( 1, D3DTSS_TEXCOORDINDEX, 0 ). И затем нужно загрузить (установить) текстуры в соответствующие текстурные уровни.

SetTexture( 0, tex1 ); SetTexture( 1, tex2 );

Можно указать для каждого текстурного уровня свои собственные текстурные координаты. В этом случае должен корректно измениться формат вершины при описании и набор FVF флагов. Ниже приведен пример описания вершины и FVF флагов для мультитекстурирования с двумя уровнями (текстурами) и текстурными координатами.

C++struct CUSTOMVERTEX { FLOAT x, y, z, rhw; // координаты вершины FLOAT u1, v1; // текстурные координаты первого уровня FLOAT u2, v2; // текстурные координаты второго уровня };

#define MY_FVF (D3DFVF_XYZ | D3DFVF_TEX2)

Pascaltype MyVertex = packed record x, y, z, rhw: Single; // координаты вершины u1,v1: Single; // текстурные координаты первого уровня u2,v2: Single; // текстурные координаты второго уровня end;

const MY_FVF = D3DFVF_XYZRHW or D3DFVF_TEX2;

<
Вообще, число во флаге D3DFVF_TEX как раз и показывает, сколько текстурных уровней планируется задействовать при мультитекстурировании (D3DFVF_TEX1 … D3DFVF_TEX8). Для хранения второй и последующих текстур необходимо объявить соответствующее количество нужных переменных, произвести загрузку текстур с помощью функции D3DXCreateTextureFromFile() и установить текстуры в соответствующие текстурные уровни вызовов метода SetTexture (<номер уровня>, <текстура>). Ниже приведен пример возможного использования двух текстур при мультитекстурировании.

C++LPDIRECT3DTEXTURE9 tex, tex2; … D3DXCreateTextureFromFile( device, "texture.bmp", &tex ); D3DXCreateTextureFromFile( device, "texture2.bmp", &tex2 ); … device->SetTexture ( 0, tex ); device->SetTexture ( 1, tex2 );
Pascalvar tex, tex2: IDirect3DTexture9; … D3DXCreateTextureFromFile( device, 'texture.bmp', tex ); D3DXCreateTextureFromFile( device, 'texture2.bmp', tex2 ); … device.SetTexture( 0, tex ); device.SetTexture( 1, tex2 );

При такой каскадной схеме мультитекстурирования мы должны для каждого текстурного уровня задать два цветовых аргумента и операцию над ними с помощью вызова метода SetTextureStageState интерфейса IDirect3DDevice9:

SetTextureStageState( <номер уровня>, D3DTSS_COLORARG1, <значение> ), SetTextureStageState( <номер уровня>, D3DTSS_COLORARG2, <значение> ), SetTextureStageState( <номер уровня>, D3DTSS_COLOROP, <операция> ).

Помимо уже известных значений констант для цветовых аргументов в данном вызове может быть использована константа D3DTA_CURRENT, которая говорит, что в качестве значения будет браться цвет из предыдущего текстурного уровня.

Также мы можем указать требуемый тип фильтрации текстур для каждого в отдельности текстурного уровня, указав в качестве первого аргумента его номер и вызвав метод SetSamplerState интерфейса IDirect3DDevice9.

Вообще говоря, можно использовать даже одну текстуру для реализации механизма мультитекстурирования.


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

… points[0].u1 = 0.0f; points[0].v1 = 1.0f; points[0].u2 = 0.0f; points[0].v2 = 3.0f; … device->SetTexture( 0, tex ); device->SetTexture( 1, tex ); …

Ниже приведен пример мультитекстурирования с помощью одной текстуры и двух текстурных уровней.



device->SetTexture(0, tex); device->SetTextureStageState(0, D3DTSS_TEXCOORDINDEX, 0); device->SetTextureStageState(0, D3DTSS_COLORARG1, D3DTA_TEXTURE); device->SetTextureStageState(0, D3DTSS_COLOROP, D3DTOP_SELECTARG1); device->SetTexture(1, tex); device->SetTextureStageState(1, D3DTSS_TEXCOORDINDEX, 1); device->SetTextureStageState(1, D3DTSS_COLORARG2, D3DTA_TEXTURE); device->SetTextureStageState(1, D3DTSS_COLORARG1, D3DTA_CURRENT); device->SetTextureStageState(1, D3DTSS_COLOROP, <operation>);




operation = D3DTOP_MODULATE4X




operation = D3DTOP_ADD


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