Текстурирование
До сих пор выводимые на экран примитивы строились только с помощью синтетических цветов. Для того чтобы придать им большей реалистичности можно прибегнуть к помощи текстур. Текстура представляет собой двумерное растровое изображение, которое накладывается (натягивается) на поверхность объекта, например на плоский треугольник. Текстуры, как правило, хранятся в графических файлах форматов bmp, jpeg, tiff, tga, gif. Библиотека Direct3D содержит богатый набор функций для работы с текстурами. Процесс наложения текстуры на объект называют текстурированием. Текстуры накладываются на объект с помощью так называемых текстурных координат. Текстурные координаты представляют собой пару чисел (u,v), изменяющихся в пределах от 0 до 1, и определяются в своей системе координат. Ось u направлена горизонтально вправо, ось v - вертикально вниз. Пара величин (u,v) однозначно указывает на элемент текстуры, называемый текселем.
Для каждой вершины треугольника мы должны определить текстурные координаты, тем самым, привязав его к некоторой треугольной области на текстуре.
Как уже стало ясным, текстурные координаты изменяют формат вершины. Поэтому данный факт может быть отражен в программе следующим образом.
C++ | struct MYVERTEX { FLOAT x, y, z, rhw; FLOAT u, v; // текстурные координаты };
#define MY_FVF (D3DFVF_XYZRHW|D3DFVF_TEX1) |
Pascal | type MyVertex = packed record x, y, z, rhw: Single; u,v: Single; // текстурные координаты end;
const MY_FVF = D3DFVF_XYZRHW or D3DFVF_TEX1; |
Теперь при заполнении данных о вершинах необходимо также указывать и текстурные координаты для каждой вершины текстурируемого примитива. Работа с текстурами в Direct3D осуществляется с помощью интерфейса IDirect3DTexture9. Для этого нужно объявить соответствующую переменную.
C++ | LPDIRECT3DTEXTURE9 tex = NULL; |
Pascal |
var tex: IDirect3DTexture9; |
Следующий шаг заключается в загрузке текстуры из графического файла. Чтобы воспользоваться функцией загрузки текстуры необходимо вначале подключить нужные модули и библиотеки.
C++ | #include <d3dx9.h> |
Pascal | uses …, D3DX9,… |
C++ | D3DXCreateTextureFromFile( device, "texture.bmp", &tex ) |
Pascal | D3DXCreateTextureFromFile( device, 'texture.bmp', tex ); |
C++ | device->SetTexture ( 0, tex ); |
Pascal | device.SetTexture( 0, tex ); |
SetTexture ( 0, tex1 ); drawObject1();
SetTexture ( 0, tex2 ); drawObject2();
Для деактивации текстуры в некотором текстурном уровне достаточно вызвать метод SetTexture с нулевым (пустым) значением второго параметра.
C++ | device->SetTexture ( 0, 0 ); |
Pascal | device.SetTexture( 0, nil ); |
Фильтрация текстур – это механизм, с помощью которого библиотека Direct3D производит наложение текстуры на полигоны отличающегося размера. Наиболее распространенными по использованию являются следующие типы фильтрации текстур:
- точечная фильтрация (используется по умолчанию) – самая быстрая по скорости, но самая низкая по качеству;
- линейная фильтрация – приемлемое качество и скорость;
- анизотропная – самая медленная, но самая качественная.
Программно установить тот или ной тип фильтрации можно с помощью вызова метода SetSamplerState интерфейса IDirect3DDevice9:
SetSamplerState( 0, D3DSAMP_MINFILTER, <тип фильтрации> ) SetSamplerState( 0, D3DSAMP_MAGFILTER, <тип фильтрации> ),
где <тип фильтрации> – одна из следующих констант:
D3DTEXF_POINT – точечная фильтрация,
D3DTEXF_LINEAR – линейная фильтрация,
D3DTEXF_ANISOTROPIC – анизотропная фильтрация;
константы D3DSAMP_MAGFILTER и D3DSAMP_MINFILTER указывают на то, что размер текстуры меньше и больше размеров полигона соответственно.
Как правило, функции установки типа фильтрации для двух упомянутых выше случаев вызывают совместно. Ниже приведен пример фильтрации текстур с точечной и линейной интерполяцией.
D3DTEXF_POINT | D3DTEXF_LINEAR |
- wrap
- border color
- clamp
- mirror
Разберем на примерах результат работы каждого типа. Пусть у нас имеется исходная текстура и квадрат, на который мы хотим наложить ее, причем вершины квадрата имеют текстурные координаты, показанные ниже:
В таблице представлены способы установки различных режимов адресации текстур, а также показан результат их действий.
SetSamplerState( 0, D3DSAMP_ADDRESSU, D3DTADDRESS_WRAP ); SetSamplerState( 0, D3DSAMP_ADDRESSV, D3DTADDRESS_WRAP ); |
SetSamplerState( 0, D3DSAMP_ADDRESSU, D3DTADDRESS_BORDER ); SetSamplerState( 0, D3DSAMP_ADDRESSV, D3DTADDRESS_BORDER ); SetSamplerState( 0, D3DSAMP_BORDERCOLOR, D3DCOLOR_XRGB(64,64,0) ); |
SetSamplerState( 0, D3DSAMP_ADDRESSU, D3DTADDRESS_CLAMP ); SetSamplerState( 0, D3DSAMP_ADDRESSV, D3DTADDRESS_CLAMP ); |
SetSamplerState( 0, D3DSAMP_ADDRESSU, D3DTADDRESS_MIRROR ); SetSamplerState( 0, D3DSAMP_ADDRESSV, D3DTADDRESS_MIRROR ); |
Вершина полигона может содержать одновременно и цвет и текстурные координаты. В этом случае итоговое значение каждого пикселя будет определяться как средневзвешенная сумма соответствующего пикселя и текселя текстуры.
C++ | struct CUSTOMVERTEX { FLOAT x, y, z, rhw; // координаты вершины DWORD color; // цвет вершин FLOAT tu, tv; // текстурные координаты }; #define MY_FVF (D3DFVF_XYZRHW | D3DFVF_ DIFFUSE | D3DFVF_TEX1) |
Pascal | type MyVertex = packed record x, y, z, rhw: Single; // координаты вершины color: DWORD; // цвет вершин u,v: Single; // текстурные координаты end; const MY_FVF = D3DFVF_XYZRHW or D3DFVF_DIFFUSE or D3DFVF_TEX1; |
Вообще говоря, правила взаимодействия, по которым два пикселя будут формировать результирующий цвет, можно явно указывать с помощью состояний текстурных уровней. Каждый текстурный уровень принимает на вход два цветовых аргумента и определяет правило (операцию) по которому будут смешиваться эти цвета. Программно это реализуется с помощью вызова метода SetTextureStageState интерфейса IDirect3DDevice9.
Первый аргумент указывает номер текстурного уровня, второй аргумент задает название изменяемого параметра, а третий – его значение. Определить значения двух цветовых аргументов для нулевого текстурного уровня можно следующим образом:
SetTextureStageState( 0, D3DTSS_COLORARG{1,2}, <значение> ),
где <значение> в нашем случае может быть константой D3DTA_DIFFUSE либо D3DTA_TEXTURE. Определить операцию взаимодействия двух цветовых аргументов позволит следующий вызов:
SetTextureStageState( 0, D3DTSS_COLOROP, <операция> ),
где <операция> может принимать следующие значения:
D3DTOP_SELECTARG1 | выбор в качестве результата первого цветового аргумента, при этом значение второго аргумента в рассмотрение не берется |
D3DTOP_SELECTARG2 | выбор в качестве результата второго цветового аргумента, при этом значение первого аргумента в рассмотрение не берется |
D3DTOP_MODULATE | покомпонентное перемножение первого и второго цветового аргумента |
D3DTOP_MODULATE2X | покомпонентное перемножение первого и второго цветового аргумента и битовый сдвиг на 1 бит влево (умножение на 2) |
D3DTOP_MODULATE4X | покомпонентное перемножение первого и второго цветового аргумента и битовый сдвиг на 2 бита влево (умножение на 4) |
D3DTOP_ADD | покомпонентное сложение первого и второго цветового аргумента |
D3DTOP_SUBTRACT | покомпонентное вычитание из первого цветового аргумента второго |
Сам процесс смешивания цветов может быть описан следующей блок-схемой.
Следует отметить, что все цветовые операции над пикселями производятся покомпонентно для каждого оттенка. Отдельно для красного, зеленого и синего цветов, причем диапазон принимаемых значений каждого цветового канала ограничен в пределах [0,1]. Пусть формат вершины содержит цвет и текстурные координаты. Ниже показаны примеры смешивания цветовой и текстурной составляющей вершины при использовании только нулевого текстурного уровня.
D3DTSS_COLORARG1 = D3DTA_TEXTURE D3DTSS_COLORARG2 = D3DTA_DIFFUSE D3DTSS_COLOROP = D3DTOP_SELECTARG1 | |
D3DTSS_COLORARG1 = D3DTA_TEXTURE D3DTSS_COLORARG2 = D3DTA_DIFFUSE D3DTSS_COLOROP = D3DTOP_SELECTARG2 | |
D3DTSS_COLORARG1 = D3DTA_TEXTURE D3DTSS_COLORARG2 = D3DTA_DIFFUSE D3DTSS_COLOROP = D3DTOP_MODULATE | |
D3DTSS_COLORARG1 = D3DTA_TEXTURE D3DTSS_COLORARG2 = D3DTA_DIFFUSE D3DTSS_COLOROP = D3DTOP_MODULATE2X | |
D3DTSS_COLORARG1 = D3DTA_TEXTURE D3DTSS_COLORARG2 = D3DTA_DIFFUSE D3DTSS_COLOROP = D3DTOP_MODULATE4X | |
D3DTSS_COLORARG1 = D3DTA_TEXTURE D3DTSS_COLORARG2 = D3DTA_DIFFUSE D3DTSS_COLOROP = D3DTOP_ADD | |
D3DTSS_COLORARG1 = D3DTA_TEXTURE D3DTSS_COLORARG2 = D3DTA_DIFFUSE D3DTSS_COLOROP = D3DTOP_SUBTRACT | |
D3DTSS_COLORARG1 = D3DTA_DIFFUSE D3DTSS_COLORARG2 = D3DTA_TEXTURE D3DTSS_COLOROP = D3DTOP_SUBTRACT |
D3DTSS_COLORARG1 = D3DTA_DIFFUSE (белый) D3DTSS_COLORARG2 = D3DTA_TEXTURE D3DTSS_COLOROP = D3DTOP_SUBTRACT |