Введение в программирование трехмерных игр с DX9

         

Альфа-канал



7.3.1. Альфа-канал

Вместо того, чтобы вычислять альфа-компоненту при затенении, можно получать ее значение из альфа-канала (alpha channel) текстуры. Альфа-каналом называется дополнительный набор битов, резервируемых для каждого текселя, в которых кранится альфа-компонент. Когда текстура накладывается на примитив также накладываются и альфа-компоненты из альфа-канала и они становятся значениями альфа-компоненты пикселей текстурированного примитива. На Рисунок  7.3 представлено изображение 8-разрядного альфа-канала.

Прозрачность


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

Альфа-компонента в основном используется для задания степени прозрачности пикселя. Предположим, что для альфа-компоненты каждого пикселя выделено 8 бит. Тогда диапазон значений альфа-компоненты будет [0,255], где [0, 255] соответствует [0%, 100%] непрозрачности. Черный пиксель альфа-канала (со значением 0) полностью прозрачен, серый пиксель альфа-канала (со значением 128) прозрачен на 50%, а белый пиксель альфа-канала (со значением 255) полностью непрозрачен.

Чтобы альфа-компонента задавала уровень прозрачности пикселей, мы должны присвоить коэффициенту смешивания источника значение D3DBLEND_SRCALPHA а коэффициенту смешивания приемника значение D3DBLEND_INVSRCALPHA. Эти значения являются устанавливаемыми по умолчанию коэффициентами смешивания.



Прозрачный чайник



Рисунок 7.2. Прозрачный чайник


Как выполнить это? Поскольку мы растеризуем образующие чайник треугольники поверх изображения ящика, мы должны комбинировать цвета пикселей чайника с цветами пикселей ящика таким образом, чтобы ящик был виден сквозь чайник. Комбинирование значений рисуемых в данный момент пикселей (пиксели источника) со значениями ранее записанных пикселей (пиксели приемника) и называется смешиванием. Обратите внимание, что реализуемые с помощью смешивания эффекты не ограничиваются обычной иммитацией прозрачности стеклянных объектов. Мы можем указать ряд параметров, определяющих как будет выполняться смешивание. Эти параметры рассматриваются в разделе 7.2.

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




Формулы смешивания


Взгляните на Рисунок 7.1, где красный чайник изображен поверх фоновой картинки с текстурой деревянного ящика.



Смешивание


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

Цели

Понять, как работает смешивание и как его можно использовать.

Изучить различные режимы смешивания, поддерживаемые Direct3D.

Посмотреть как альфа-составляющая используется для управления прозрачностью примитивов.





смешивание позволяет комбинировать пиксель растеризуемого


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

Изменение формата текстуры



Рисунок 7.5. Изменение формата текстуры


В результате будет создано изображение с 32-разрядной глубиной цвета, где у каждого пикселя 8 бит отведено под альфа-канал, 8 бит для красного цвета, 8 бит для зеленого и 8 бит для синего. Следующая задача — загрузить данные в альфа-канал. Мы будем загружать в альфа-канал 8-разрядную карту оттенков серого, изображенную на Рисунок  7.3. Раскройте меню File и выберите пункт Open Onto Alpha Channel Of This Texture. На экран будет выведено диалоговое окно, предлагающее выбрать файл изображения, содержащий данные, которые вы хотите загрузить в альфа-канал. Выберите файл alphachannel.bmp расположенный в папке примера к этой главе texAlpha. На Рисунок  7.6 показано окно программы после загрузки данных альфа-канала.



Коэффициеты смешивания


Задавая различные комбинации коэффициентов смешивания источника и приемника вы можете реализовать десятки различных эффектов. Поэкспериментируйте с различными комбинациями, чтобы увидеть что они делают. Чтобы установить коэффициент смешивания источника и коэффициент смешивания приемника надо задать значения режимов визуализации D3DRS_SRCBLEND и D3DRS_DESTBLEND соответственно. Например, мы можем написать:

Device->SetRenderState(D3DRS_SRCBLEND, Source); Device->SetRenderState(D3DRS_DESTBLEND, Destination);

где Source и Destination могут принимать значения одного из следующих коэффициентов смешивания:

D3DBLEND_ZERO — коэффициент смешивания = (0, 0, 0, 0)

D3DBLEND_ONE — коэффициент смешивания = (1, 1, 1, 1)

D3DBLEND_SRCCOLOR — коэффициент смешивания = (rs, gs, bs, as)

D3DBLEND_INVSRCCOLOR — коэффициент смешивания = (1 – rs, 1 – gs, 1 – bs, 1 – as)

D3DBLEND_SRCALPHA — коэффициент смешивания = (as, as, as, as)

D3DBLEND_INVSRCALPHA — коэффициент смешивания = (1 – as, 1 – as, 1 – as, 1 – as)

D3DBLEND_DESTALPHA — коэффициент смешивания = (ad, ad, ad, ad)

D3DBLEND_INVDESTALPHA — коэффициент смешивания = (1 – ad, 1 – ad, 1 – ad, 1 – ad)

D3DBLEND_DESTCOLOR — коэффициент смешивания = (rd, gd, bd, ad)

D3DBLEND_INVDESTCOLOR — коэффициент смешивания = (1 – rd, 1 – gd, 1 – bd, 1 – ad)

D3DBLEND_SRCALPHASAT — коэффициент смешивания = (f, f, f, 1), где f = min(as, 1 – ad)

D3DBLEND_BOTHINVSRCALPHA — Этот режим смешивания устанавливает коэффициент смешивания источника равным (1 – as, 1 – as, 1 – as, 1 – as), а коэффициент смешивания приемника равным (as, as, as, as). Его можно указывать только для режима визуализации D3DRS_SRCBLEND.

Значениями по умолчанию для коэффициента смешивания источника и коэффициента смешивания приемника являются D3DBLEND_SRCALPHA и D3DBLEND_INVSRCALPHA соответственно.



Непрозрачный чайник



Рисунок 7.1. Непрозрачный чайник


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



Полученная текстура с альфа-каналом



Рисунок 7.6. Полученная текстура с альфа-каналом


Теперь можно сохранить текстуру в файле; мы выбрали для файла имя cratewalpha.dds.



Пример приложения: прозрачный чайник


Пример приложения, который мы будем рассматривать, рисует прозрачный чайник поверх фоновой текстуры с изображением ящика, как показано на Рисунок  7.2. Данные альфа-компоненты в этом примере берутся из материала. Приложение позволяет увеличивать и уменьшать значение альфа-компоненты нажатием на клавиши A и S. Нажатие на клавишу A увеличивает значение альфа-компоненты; нажатие на клавишу S — уменьшает его.

Чтобы использовать смешивание необходимо выполнить следующие действия:

Установить коэффициенты смешивания D3DRS_SRCBLEND и D3DRS_DESTBLEND.

Если используется альфа-компонента, указать ее источник (материал или альфа-канал текстуры).

Установить режим визуализации с альфа-смешиванием.

В примере мы объявляем несколько самодокументируемых глобальных переменных:

ID3DXMesh* Teapot = 0; // чайник D3DMATERIAL9 TeapotMtrl; // материал чайника

IDirect3DVertexBuffer9* BkGndQuad = 0; // квадрат фона IDirect3DTexture9* BkGndTex = 0; // текстура ящика D3DMATERIAL9 BkGndMtrl; // материал фона

Метод Setup делает много вещей, но мы опустим большую часть кода, которая не относится к рассматриваемой в этой главе теме. Что касается смешивания, метод Setup задает источник из которого будут браться значения альфа-компонент. В рассматриваемом примере мы указываем, что значения альфа-компонент будут браться из соответствующей компоненты материала. Обратите внимание, что для материала чайника мы задаем значение альфа-компоненты равное 0.5, а это значит, что чайник будет визуализирован с 50% прозрачностью. Помимо вышеперечисленных действий мы также задаем коэффициенты смешивания. Обратите внимание, что в этом методе мы не разрешаем альфа-смешивание. Дело в том, что альфа-смешивание — это ресурсоемкая операция, которая должна включаться только при визуализации тех объектов, для которых она нужна. Например, в рассматриваемой программе визуализация с альфа-смешиванием нужна только для чайника и не требуется для квадрата с фоновой текстурой. Поэтому мы разрешаем альфа-смешивание в функции Display.


bool Setup() { TeapotMtrl = d3d::RED_MTRL; TeapotMtrl.Diffuse.a = 0.5f; // 50% прозрачность BkGndMtrl = d3d::WHITE_MTRL;
D3DXCreateTeapot(Device, &Teapot, 0);
...// Код создания квадрата фона опущен
...// Код установки освещения и текстур опущен
// В качестве источника альфа-компоненты используем параметры материала Device->SetTextureStageState(0, D3DTSS_ALPHAARG1, D3DTA_DIFFUSE); Device->SetTextureStageState(0, D3DTSS_ALPHAOP, D3DTOP_SELECTARG1);
// Устанавливаем коэффициенты смешивания таким образом, // чтобы альфа-компонента определяла прозрачность Device->SetRenderState(D3DRS_SRCBLEND, D3DBLEND_SRCALPHA); Device->SetRenderState(D3DRS_DESTBLEND, D3DBLEND_INVSRCALPHA);
...// установка матриц проекции/вида опущена
return true; }
В функции Display мы проверяем нажаты ли клавиши A или S и, если да, то соответственно увеличиваем или уменьшаем значение альфа-компоненты материала. Обратите внимание, что метод гарантирует, что значение альфа-компоненты не выйдет за пределы диапазона [0, 1]. Затем мы разрешаем альфа-смешивание, визуализируем чайник с включенным альфа-смешиванием, после чего выключаем альфа-смешивание.
bool Display(float timeDelta) { if(Device) { // // Обновление //
// Увеличение/уменьшение альфа-компоненты с помощью клавиатуры if(::GetAsyncKeyState('A') & 0x8000f ) TeapotMtrl.Diffuse.a += 0.01f; if( ::GetAsyncKeyState('S') & 0x8000f ) TeapotMtrl.Diffuse.a -= 0.01f;
// Проверяем не вышло ли значение за интервал [0, 1] if(TeapotMtrl.Diffuse.a > 1.0f) TeapotMtrl.Diffuse.a = 1.0f; if(TeapotMtrl.Diffuse.a < 0.0f) TeapotMtrl.Diffuse.a = 0.0f;
// // Визуализация //
Device->Clear(0, 0, D3DCLEAR_TARGET | D3DCLEAR_ZBUFFER, 0xffffffff, 1.0f, 0); Device->BeginScene();
// Рисуем фон D3DXMATRIX W; D3DXMatrixIdentity(&W); Device->SetTransform(D3DTS_WORLD, &W); Device->SetFVF(Vertex::FVF); Device->SetStreamSource(0, BkGndQuad, 0, sizeof(Vertex)); Device->SetMaterial(&BkGndMtrl); Device->SetTexture(0, BkGndTex); Device->DrawPrimitive(D3DPT_TRIANGLELIST, 0, 2);

// Рисуем чайник Device->SetRenderState(D3DRS_ALPHABLENDENABLE, true);
D3DXMatrixScaling(&W, 1.5f, 1.5f, 1.5f); Device->SetTransform(D3DTS_WORLD, &W); Device->SetMaterial(&TeapotMtrl); Device->SetTexture(0, 0); Teapot->DrawSubset(0);
Device->SetRenderState(D3DRS_ALPHABLENDENABLE, false);
Device->EndScene(); Device->Present(0, 0, 0, 0); } return true; }
ПРИМЕЧАНИЕ
На веб- сайте этой книги есть еще один пример к данной главе, texAlpha, который демонстрирует использование альфа-канала текстуры. Единственное отлтчие кода этого примера от рассмотренного выше заключается в том, что мы указываем в качестве источника альфа-компоненты не материал, а альфа-канал текстуры.
// Использовать альфа-канал в качестве источника альфа-компонент Device->SetTextureStageState(0, D3DTSS_ALPHAARG1, D3DTA_TEXTURE); Device->SetTextureStageState(0, D3DTSS_ALPHAOP, D3DTOP_SELECTARG1);
Приложение загружает файл DDS, содержащий альфа-канал, созданный с помощью утилиты DX Tex Tool, рассмотренной в разделе 7.4.

ПРАВИЛО Сперва рисуйте объекты, которые не используют смешивание. Затем отсортируйте объекты, которые используют смешивание, по расстоянию от камеры; наиболее эффективно эта операция выполняется, если объекты находятся в пространстве вида — в этом случае достаточно отсортировать их по значению координаты Z. После этого рисуйте использующие смешивание объекты начиная от самых дальних и заканчивая самыми близкими.


При смешивании значений двух пикселей используется следующая формула:

ИтоговыйПиксель = ПиксельИсточника 

 КоэффициентСмешиванияИсточника + ПиксельПриемника
 КоэффициентСмешиванияПриемника

Каждая из переменных в этой формуле является четырехмерным цветовым вектором (r, g, b, a), а символ

означает операцию перемножения компонент.

ИтоговыйПиксель — Пиксель, получаемый в результате смешивания.

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

КоэффициентСмешиванияИсточника — Значение в диапазоне [0, 1], определяющее какой процент пикселя источника участвует в смешивании.

Пиксель приемника — Пиксель, находящийся во вторичном буфере.

КоэффициентСмешиванияПриемника — Значение в диапазоне [0, 1], определяющее какой процент пикселя приемника участвует в смешивании.

Благодаря коэффициентам смешивания источника и приемника можно различными способами модифицировать исходные пиксели источника и приемника, что позволяет реализовать различные эффекты. В разделе 7.2 описаны предопределенные значения, которые можно использовать.

По умолчанию смешивание запрещено; чтобы разрешить его, присвойте режиму визуализации D3DRS_ALPHABLENDENABLE значение true:

Device->SetRenderState(D3DRS_ALPHABLENDENABLE, true);

СОВЕТ

Смешивание — достаточно сложная и ресурсоемкая операция и ее надо разрешать только для тех объектов, которым она необходима. Закончив визуализацию этих объектов, смешивание следует выключить. Также попытайтесь объединить все треугольники, для которых необходимо смешивание и визуализировать их за один раз, чтобы избежать многократных включений и выключений смешивания в одном кадре.

Разрядная карта оттенков серого, представляющая альфа-канал текстуры



Рисунок 7.3. 8-разрядная карта оттенков серого, представляющая альфа-канал текстуры

На Рисунок 7.4 показан результат визуализации текстурированного квадрата с альфа-каналом, определяющим какие части будут прозрачными.



Создание альфа-канала с помощью утилиты DirectX Texture Tool


Большинство распространенных форматов графических файлов не хранят информацию альфа-компонент. В этом разделе мы покажем вам как создать файл формата DDS с альфа-каналом используя утилиту DirectX Texture Tool. DDS— это формат графических файлов специально разработанный для приложений и текстур DirectX. Файлы DDS могут быть загружены в объект текстуры с помощью функции D3DXCreateTextureFromFile точно так же как файлы BMP и JPG. Утилита DirectX Texture Tool находится в папке \Bin\DXUtils корневого каталога DXSDK.

Запустите утилиту DirectX Texture Tool и откройте файл crate.jpg, находящийся на сопроводительном компакт-диске в папке с примерами программ к данной главе. Изображение ящика автоматически загружается как 24-разрядная RGB-текстура, в которой у каждого пикселя 8 бит отведено под красный цвет, 8 бит — под зеленый и 8 бит — под синий. Нам надо преобразовать эту текстуру в 32-разрядную ARGB-текстуру, зарезервировав дополнительные 8 бит для альфа-канала. Выберите в меню Format команду Change Surface Format. Будет выведено диалоговое окно, показанное на Рисунок  7.5. Выберите формат A8 R8 G8 B8 и щелкните по кнопке OK.



Текстурированный квадрат, у которого альфа-канал задает прозрачность отдельных частей



Рисунок 7.4. Текстурированный квадрат, у которого альфа-канал задает прозрачность отдельных частей




Указание источника альфа-компоненты



7.3.2. Указание источника альфа-компоненты

Если у используемой в данный момент текстуры есть альфа-канал, то по умолчанию значения альфа-компоненты пикселей берутся из него. Если альфа-канала нет, значения альфа-компонент отдельных пикселей вычисляются на основании значений альфа-компонент вершин. В то же время с помощью показанных ниже режимов визуализации вы сами можете указать, какой источник альфа компоненты использовать (цвета вершин или альфа-канал):

// Вычисляем альфа-компоненту при затенении на основании цветов вершин Device->SetTextureStageState(0, D3DTSS_ALPHAARG1, D3DTA_DIFFUSE); Device->SetTextureStageState(0, D3DTSS_ALPHAOP, D3DTOP_SELECTARG1);

// Берем значение альфа-компоненты из альфа-канала Device->SetTextureStageState(0, D3DTSS_ALPHAARG1, D3DTA_TEXTURE); Device->SetTextureStageState(0, D3DTSS_ALPHAOP, D3DTOP_SELECTARG1);