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

Обратите внимание на процедуру Setting, она вызывается из Sub Main непосредственно перед главным циклом. В этой процедуре мы будем тестировать различные варианты использования альфа-компоненты, пока она пустая. Альфа-компонента используется для имитации эффекта полупрозрачности предметов, так же, как и компоненты R, G и B, альфа – это байт в представлении цвета RGBA, либо значение от 0 до 1 в представлении DirectX. Наиболее распространенная формула для имитации эффекта полупрозрачности такая:
R = Arg1 ´ Alpha + Arg2 ´ (1 – Alpha)
Здесь R – это результирующий цвет, Arg1 и Arg2 – смешиваемые цвета. Альфа-компонента может применяться как «внутри» стадии текстурирования для работы с ее аргументами, так и к общему результату работы текстурирования для смешивания его с ранее нарисованным изображением. Рассмотрим сначала более простой первый вариант. Текстура к этому проекту сохранена в формате TGA и имеет в составе альфа-компоненту, также альфа-компоненту содержит и цвет вертексов, обратите внимание – все нижние вертексы в цилиндре имеют цвет &HFF0000FF, то есть:
Alpha = &HFF
R = &H0
G = &H0
B = &HFF

А верхние вертексы в цилиндре имеют цвет &HFF, то есть Alpha в них равна 0. Так же, как и другие компоненты цвета вертекса, альфа-компонента линейно интерполируется между вертексами. Впишите в процедуру Setting такие строки:

код на языке vb
 
  d3dDevice.SetTextureStageState 0, D3DTSS_COLOROP, D3DTOP_BLENDDIFFUSEALPHA
  d3dDevice.SetTextureStageState 0, D3DTSS_COLORARG1, D3DTA_TEXTURE
  d3dDevice.SetTextureStageState 0, D3DTSS_COLORARG2, D3DTA_DIFFUSE
 

D3DTOP_BLENDDIFFUSEALPHA для параметра D3DTSS_COLOROP обозначает, что используется альфа-компонента из DIFFUSE. Запускаем программу и видим, что цилиндр снизу покрыт текстурой, которая при подъеме постепенно переходит в DIFFUSE. Чтобы поменять местами TEXTURE и DIFFUSE, достаточно поменять местами COLORARG1 и COLORARG2:

код на языке vb
 
  d3dDevice.SetTextureStageState 0, D3DTSS_COLORARG1, D3DTA_DIFFUSE
  d3dDevice.SetTextureStageState 0, D3DTSS_COLORARG2, D3DTA_TEXTURE
 

Теперь попробуем использовать альфа-компоненту текстуры:

код на языке vb
 
  d3dDevice.SetTextureStageState 0, D3DTSS_COLOROP, D3DTOP_BLENDTEXTUREALPHA
 

Не правда ли, названия параметров говорят сами за себя? Так же, как и для цвета, для альфа-компоненты тоже предусмотрены оператор и аргументы, они применяются, если нужно каким-либо образом совместить альфа-компоненты нескольких аргументов. Рассмотрим такой вариант:

код на языке vb
 
  d3dDevice.SetTextureStageState 0, D3DTSS_COLOROP, D3DTOP_SELECTARG1
  d3dDevice.SetTextureStageState 0, D3DTSS_COLORARG1, D3DTA_TEXTURE
  d3dDevice.SetTextureStageState 0, D3DTSS_ALPHAOP, D3DTOP_MODULATE
  d3dDevice.SetTextureStageState 0, D3DTSS_ALPHAARG1, D3DTA_TEXTURE
  d3dDevice.SetTextureStageState 0, D3DTSS_ALPHAARG2, D3DTA_DIFFUSE
 
  d3dDevice.SetTextureStageState 1, D3DTSS_COLOROP, D3DTOP_BLENDCURRENTALPHA
  d3dDevice.SetTextureStageState 1, D3DTSS_COLORARG1, D3DTA_CURRENT
  d3dDevice.SetTextureStageState 1, D3DTSS_COLORARG2, D3DTA_DIFFUSE
 

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

Мы рассмотрели несколько примеров использования прозрачности, но цилиндр пока прозрачным не был. Чтобы сделать его прозрачным, нужно чтобы в альфа-смешении участвовали не только аргументы текстурирования, но и ранее отрисованное изображение, то есть то, что находится в BackBuffer. При этом в качестве аргументов альфа-смешения будут выступать значение цвета, взятое из BackBuffer, и значение, полученное в результате текстурирования. Эти аргументы нужно указать:

код на языке vb
 
  d3dDevice.SetRenderState D3DRS_SRCBLEND, D3DBLEND_SRCALPHA
  d3dDevice.SetRenderState D3DRS_DESTBLEND, D3DBLEND_INVSRCALPHA
  d3dDevice.SetRenderState D3DRS_BLENDOP, D3DBLENDOP_ADD
 

Это более гибкий подход, позволяющий большего достичь, но и более ресурсоемкий, так как производится чтение из BackBuffer. В этих строках указывается, что в качестве множителя для первого аргумента – D3DRS_SRCBLEND, выступает альфа-компонента первого аргумента – D3DBLEND_SRCALPHA, для второго аргумента в качестве множителя мы выбрали D3DBLEND_INVSRCALPHA, то есть 1 – D3DBLEND_SRCALPHA. Далее мы выбрали оператор, применяемый для смешения полученных произведений – D3DRS_BLENDOP, этот оператор – D3DBLENDOP_ADD, то есть сложение.
Использование такого типа альфа-смешения необходимо разрешить:

код на языке vb
 
  d3dDevice.SetRenderState D3DRS_ALPHABLENDENABLE, 1
 

Закрасим цилиндр текстурой, с использования альфа-компоненты из DIFFUSE:

код на языке vb
 
  d3dDevice.SetTextureStageState 0, D3DTSS_COLOROP, D3DTOP_SELECTARG1
  d3dDevice.SetTextureStageState 0, D3DTSS_COLORARG1, D3DTA_TEXTURE
  d3dDevice.SetTextureStageState 0, D3DTSS_ALPHAOP, D3DTOP_SELECTARG1
  d3dDevice.SetTextureStageState 0, D3DTSS_ALPHAARG1, D3DTA_DIFFUSE
 

Цилиндр действительно стал полупрозрачным, но явно видны недостатки – временами изображение правильное, но через ближнюю сторону цилиндра, вторая видна не всегда. Это результат работы ZBuffer, если ближняя сторона цилиндра рисуется раньше, то дальняя в этом месте уже не рисуется, это отлично работало и избавляло нас от упорядочивания треугольников, пока мы не использовали прозрачность. Отключим ZBuffer:

код на языке vb
 
  d3dDevice.SetRenderState D3DRS_ZENABLE, D3DZB_FALSE
 

Эта строка находится в процедуре Main.
Что ж, изображение улучшилось, но небольшие погрешности в изображении остались, результирующий цвет получается разным, в зависимости от того, какая сторона цилиндра рисуется раньше. Кроме того отключение ZBuffer приведет к тому, что прозрачные предметы будут рисоваться даже тогда, когда они закрыты непрозрачными. Для того, чтобы правильно отображать предметы, использующие такой тип прозрачности, во время их рисования отключают не ZBuffer, а запись в него:

код на языке vb
 
  d3dDevice.SetRenderState D3DRS_ZWRITEENABLE, 0
 

И прозрачные треугольники нужно упорядочивать так, чтобы они отображались от дальних к ближним. Упорядочивание – процесс весьма ресурсоемкий, ведь число треугольников может достигать сотен тысяч! Но иногда удается этого избежать. Например, в нашем цилиндре внутренняя сторона (а это обратная сторона треугольников) всегда находится сзади. Таким образом, достаточно отобразить цилиндр дважды – сначала внутреннюю, а затем и внешнюю стороны, и необходимость в упорядочивании отпадает. Для этого изменим процедуру Render:

код на языке vb
 
Private Sub Render()
  d3dDevice.Clear 0, ByVal 0, D3DCLEAR_TARGET Or D3DCLEAR_ZBUFFER, &H346666, 1, 0
  d3dDevice.BeginScene
 
  d3dDevice.SetStreamSource 0, vBuf, vSize
  d3dDevice.SetVertexShader vFlag
  d3dDevice.SetTexture 0, Tex0
 
  d3dDevice.SetRenderState D3DRS_CULLMODE, D3DCULL_CW
  d3dDevice.DrawPrimitive D3DPT_TRIANGLESTRIP, 0, 128
  d3dDevice.SetRenderState D3DRS_CULLMODE, D3DCULL_CCW
  d3dDevice.DrawPrimitive D3DPT_TRIANGLESTRIP, 0, 128
 
  d3dDevice.EndScene
  d3dDevice.Present ByVal 0, ByVal 0, 0, ByVal 0
End Sub
 

Посмотрите на цилиндр теперь – он отображается корректно!
Но такие проблемы с альфа-смешением возникают не всегда, если множитель при D3DRS_DESTBLEND равен единице – упорядочивание не требуется (запись в ZBuffer отключаем все равно!). Такие настройки могут применяться, например, для изображения огня. Впишите в процедуру Setting такие настройки:

код на языке vb
 
  d3dDevice.SetRenderState D3DRS_ZENABLE, D3DZB_TRUE
  d3dDevice.SetRenderState D3DRS_ZWRITEENABLE, 0
  d3dDevice.SetRenderState D3DRS_ALPHABLENDENABLE, 1
 
  d3dDevice.SetRenderState D3DRS_SRCBLEND, D3DBLEND_SRCALPHA
  d3dDevice.SetRenderState D3DRS_DESTBLEND, D3DBLEND_ONE
  d3dDevice.SetRenderState D3DRS_BLENDOP, D3DBLENDOP_ADD
 
  d3dDevice.SetTextureStageState 0, D3DTSS_COLOROP, D3DTOP_SELECTARG1
  d3dDevice.SetTextureStageState 0, D3DTSS_COLORARG1, D3DTA_TEXTURE
  d3dDevice.SetTextureStageState 0, D3DTSS_ALPHAOP, D3DTOP_MODULATE
  d3dDevice.SetTextureStageState 0, D3DTSS_ALPHAARG1, D3DTA_TEXTURE
  d3dDevice.SetTextureStageState 0, D3DTSS_ALPHAARG2, D3DTA_DIFFUSE
 

Такой цилиндр отображается корректно без упорядочивания. При таком альфа-смешении задний фон всегда осветляется. Есть второе значение для D3DRS_BLENDOP, при котором не требуется упорядочивание треугольников, а изображение затемняется:

код на языке vb
 
  d3dDevice.SetRenderState D3DRS_BLENDOP, D3DBLENDOP_REVSUBTRACT
 

При таком значении D3DRS_BLENDOP, произведение цвета, полученного при текстурировании, на альфа-аргумент вычитается из цвета заднего плана.