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

Полупрозрачность. Цветовой ключ. Буфер трафарета

Разбить на страницы
Показывать лекцию целиком

Полупрозрачность

Рассмотрим далее реализацию такого эффекта как полупрозрачность ( alpha blending ). Этот механизм позволяет задавать для выводимых примитивов прозрачные и полупрозрачные пиксели. Т.е. существует возможность указать, какие пиксели не будут выводиться в силу своей полной прозрачности, а какие будут выводиться частично прозрачными. Полупрозрачность основывается на принципе смешивания цветов. Математически это можно выразить так: ColorResult = Color1*(1-t) + Color2*t, 0<=t<=1. Эта векторная запись должна интерпретироваться для каждого отдельного цветового канала. Пусть ColorResult = (r, g, b), Color1 = (r1, g1, b1), Color2 = (r2, g2, b2), тогда

r = r1*(1-t) + r2*t
g = g1*(1-t) + g2*t
b = b1*(1-t) + b2*t, 0<=t<=1.

Ниже приведен пример смешивания двух цветов (красного и зеленого) для различных значений параметра t (Color1 = красный = (255,0,0) Color2 = зеленый = (0,255,0)).

t=0 t=1/8 t=2/8 t=3/8 t=4/8 t=5/8 t=6/8 t=7/8 t=1

При работе с полупрозрачностью, как правило, имеют дело (оперируют) с двумя цветами: цвет источника ( source color ) – это пиксель, который вы собираетесь отобразить (записать в буфер кадра) и цвет приемника ( destination color ) – это пиксель, который уже существует и записан в буфере кадра. Другими словами можно сказать, что цвет источника ( source color ) – "пиксель который рисуем", а цвет приемника ( destination color ) – "пиксель на котором рисуем". Механизм полупрозрачности использует следующую формулу для управления степенью полупрозрачности:

Финальный цвет = 
Цвет пикселя источника * Коэффициент прозрачности источника +
Цвет пикселя приемника * Коэффициент прозрачности приемника.

Программист может управлять коэффициентами прозрачности с помощью флагов:

коэффициент прозрачности источника - D3DRS_SRCBLEND,

коэффициент прозрачности приемника - D3DRS_DESTBLEND и используя формулу FinalPixel = SourcePixelColor*SourceBlendFactor + DestPixelColor*DestBlendFactor.

Механизм полупрозрачности по умолчанию выключен как опция. Активировать/деактивировать полупрозрачность можно следующим образом:

C++ device->SetRenderState( D3DRS_ALPHABLENDENABLE, {TRUE, FALSE} );
Pascal device.SetRenderState( D3DRS_ALPHABLENDENABLE, {1, 0} );

Установка коэффициентов смешивания ( SourceBlendFactor и DestBlendFactor ) осуществляется следующим образом:

SetRenderState( D3DRS_SRCBLEND, SourceBlendFactor ),
SetRenderState( D3DRS_DESTBLEND, DestBlendFactor ),

где в качестве SourceBlendFactor и DestBlendFactor могут выступать предопределенные константы:

D3DBLEND_ZERO—blendFactor=(0,0,0,0)
D3DBLEND_ONE—blendFactor=(1,1,1,1)
D3DBLEND_SRCCOLOR—blendFactor=(Rs, Gs, Bs, As)
D3DBLEND_INVSRCCOLOR—blendFactor=(1–Rs, 1–Gs, 1–Bs, 1–As)
D3DBLEND_SRCALPHA—blendFactor=(As, As, As, As)
D3DBLEND_INVSRCALPHA—blendFactor=(1–As, 1–As, 1–As, 1–As)
D3DBLEND_DESTALPHA—blendFactor=(Ad, Ad, Ad, Ad)
D3DBLEND_INVDESTALPHA—blendFactor=(1–Ad, 1–Ad, 1–Ad, 1–Ad)
D3DBLEND_DESTCOLOR—blendFactor=(Rd, Gd, Bd, Ad)
D3DBLEND_INVDESTCOLOR—blendFactor=(1–Rd, 1–Gd, 1–Bd, 1–Ad)
D3DBLEND_SRCALPHASAT—blendFactor=(f,f,f,1), где f=min(As, 1–Ad).
По умолчанию SourceBlendFactor = D3DBLEND_SRCALPHA
DestBlendFactor = D3DBLEND_INVSRCALPHA.

Рассмотрим несколько примеров использования механизма полупрозрачности.

Пример 1.

Если мы не хотим ничего "смешивать", тогда можно воспользоваться такой формулой:

FinalPixel = SourcePixelColor*1 + DestPixelColor*0.

Этого можно достичь, выставив следующие значения коэффициентов смешивания:

SetRenderState( D3DRS_SRCBLEND, D3DBLEND_ONE );
SetRenderState( D3DRS_DESTBLEND,D3DBLEND_ZERO );

Пример 2.

Чтобы происходило "сложение" цветов, можно использовать такую формулу:

FinalPixel = SourcePixelColor*1 + DestPixelColor*1.

Для этого, оба коэффициента смешивания выставим в единицу:

SetRenderState( D3DRS_SRCBLEND, D3DBLEND_ONE );
SetRenderState( D3DRS_DESTBLEND, D3DBLEND_ONE );

Ниже приведен визуальный пример такого "сложения" цветов.

Следует отметить, что примитивы при полупрозрачности могут быть не только однотонными. Ниже показаны примеры "умножения" цветов для примитивов, с плавными переходами цветов.

Пример 3.

Эффект "перемножения" цветов примитивов можно получить с помощью формулы

FinalPixel = SourcePixelColor*0 + DestPixelColor*SourcePixelColor.

Значения коэффициентов смешивания выставим следующим образом:

SetRenderState( D3DRS_SRCBLEND, D3DBLEND_ZERO );
SetRenderState( D3DRS_DESTBLEND, D3DBLEND_SRCCOLOR );

Ниже показаны примеры подобного "умножения" цветов при различном фоне.

цвет фона D3DCOLOR_XRGB(0,0,0) цвет фона D3DCOLOR_XRGB(255,255,255)

Прозрачность может "содержаться" и в вершинах примитивов. В дополнение к красной ( red ), зеленой ( green ) и синей ( blue ) цветовым составляющим, каждый пиксель может иметь "прозрачную" составляющую или так называемый альфа канал ( alpha channel ). Альфа канал имеет 256 уровней прозрачности, 0…255:

0 – пиксель полностью прозрачен

255 – пиксель полностью непрозрачен

128 – пиксель прозрачен наполовину.

До сих пор цвет мы определяли с помощью тройки чисел RGB, используя макрос-функцию D3DCOLOR_XRGB(). Для задания значения альфа составляющей вершины можно воспользоваться функцией D3DCOLOR_ARGB(a, r, g, b), где первый параметр определяет значение полупрозрачности. Следует заметить, что значение альфа канала (как и всех цветовых составляющих) приводится к диапазону значений [0…1]. Ниже приводится пример заполнения вершин примитивов данными о цвете со значением полупрозрачности 50 процентов.

C++
points[0].color =  D3DCOLOR_ARGB( 128, 255, 0, 0 );
…
Pascal
points[0].color := D3DCOLOR_ARGB( 128, 255, 0, 0 );
…

Использовать полупрозрачность в вершинах примитивов можно с помощью все той же формулы

FinalPixel = SourcePixelColor*SourceBlendFactor + 
   +DestPixelColor*DestBlendFactor,

при этом задействовав константы смешивания с суффиксом ALPHA. Так, например, следующие установки коэффициентов смешивания

SetRenderState( D3DRS_SRCBLEND, D3DBLEND_SRCALPHA );
SetRenderState( D3DRS_DESTBLEND, D3DBLEND_INVSRCALPHA );

преобразуют формулу к виду

FinalPixel = SourcePixelColor*(Alpha) + DestPixelColor*(1- Alpha),

где Alpha – значение альфа составляющей пикселя-источника.

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

D3DCOLOR_XRGB(255,0,0); D3DCOLOR_ARGB(128,0,0,255);

Последовательность вывода примитивов будет такой:

  • Первым рисуется красный треугольник (полупрозрачность выключена);
  • Включаем полупрозрачность: SetRenderState(D3DRS_ALPHABLENDENABLE, 1) ;
  • Рисуем синий треугольник (в вершинах задана 50 % полупрозрачность);
  • В результате формула смешивания примет вид: FinalPixel = Синий*0.5 + Красный*(1-0.5).

    Ниже приведены примеры вывода примитивов с различной степенью полупрозрачности.

    ARGB = (32,0,0,255) ARGB = (64,0,0,255) ARGB = (128,0,0,255)
    ARGB = (160,0,0,255) ARGB = (192,0,0,255) ARGB(255,0,0,255)

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

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

    Последовательность вывода примитивов должна быть следующей:

  • Вначале выводится квадрат с текстурой, при этом полупрозрачность выключена;
  • Включается режим полупрозрачности с нужными коэффициентами смешивания;
  • Выводится цветной треугольник поверх квадрата.
  • Информация о полупрозрачности пикселей может содержаться и в самой текстуре. В этом случае для альфа составляющей отводится, как правило, такое же количество бит, что и под каждый из цветовых каналов. Наиболее распространенный формат представления изображения с альфа-каналом это 32 битные изображения, где на каждый канал отводится по 8 бит. Для создания полупрозрачной текстуры можно воспользоваться утилитой DirectX Texture Tool, которая поставляется совместно с DirectX SDK. Сам альфа-канал можно создать в виде изображения в оттенках серого цвета, в котором абсолютно черные пиксели будут соответствовать полной прозрачности, а белые пиксели – полной непрозрачности.

    По умолчанию если текстура содержит альфа канал, то значение альфа составляющей берется из текстуры. Если же альфа канал не присутствует в текстуре, то значение альфа составляющей будет получено из вершины примитива. Тем не менее, можно явно указать "источник" альфа канала:

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

    Ниже приведен пример вывода полупрозрачной текстуры.

    Текстура (RGB канал) Альфа канал Результат

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

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

    Исходное изображение Альфа канал Вывод на текстуру

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

    Цветовой ключ

    В библиотеке Direct3D имеется функция D3DXCreateTextureFromFileEx(), которая позволяет задать так называемый цветовой ключ ( color key ). Механизм цветового ключа заключается в том, что оговаривается заданный цвет, который становится прозрачным при выводе текстуры на некоторую поверхность. Данная функция имеет 14 параметров, но нам для рассмотрения примера потребуется всего 4, для остальных параметров зададим значения по умолчанию. Первый параметр функции представляет собой указатель на устройство вывода, второй содержит имя загружаемого графического файла текстуры, одиннадцатый параметр и представляет собой цветовой ключ в формате ARGB, причем значение альфа составляющей должно обязательно быть 255, и последний параметр – указатель на переменную, в которую будет возвращен результат вызова. Ниже приведен пример вызова этой функции.

    C++
    D3DXCreateTextureFromFileEx(device, "tree.bmp", D3DX_DEFAULT,       
                            D3DX_DEFAULT, D3DX_DEFAULT, 0,
                            D3DFMT_UNKNOWN, D3DPOOL_MANAGED,
                            D3DX_DEFAULT, D3DX_DEFAULT, 
                        D3DCOLOR_ARGB(255,0,0,0), NULL, NULL, tex);
    Pascal
    D3DXCreateTextureFromFileEx(device, 'tree.bmp', D3DX_DEFAULT,       
                            D3DX_DEFAULT, D3DX_DEFAULT, 0,
                            D3DFMT_UNKNOWN, D3DPOOL_MANAGED,
                            D3DX_DEFAULT, D3DX_DEFAULT, 
                            D3DCOLOR_ARGB(255,0,0,0), nil, nil, tex);

    После загрузки текстуры с цветовым ключом необходимо включить режим полупрозрачности и выставить необходимые параметры смешивания цветов:

    device->SetRenderState(D3DRS_ALPHABLENDENABLE, true);
    device->SetRenderState(D3DRS_SRCBLEND, D3DBLEND_SRCALPHA);
    device->SetRenderState(D3DRS_DESTBLEND, D3DBLEND_INVSRCALPHA);

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

    Буфер трафарета

    Библиотека Direct3D располагает средствами работы с так называемым буфером трафарета. Буфер трафарета представляет собой двумерный массив с размерами как у буфера кадра и z-буфера, причем пиксель с координатами (x,y) в буфере трафарета будет соответствовать пикселю с такими же координатами в буфере кадра. Буфер трафарета работает как маска (трафарет), позволяя нам блокировать вывод некоторых пикселей на экран по заданному правилу. Принцип работы с буфером трафарета – это, как правило, двухпроходный алгоритм. Сначала мы разбиваем область вывода на зоны и каждой зоне присваиваем номер, при этом ничего не выводится на экран. Затем на основании некоторого установленного правила, мы производим непосредственный вывод сцены на экран, причем одни зоны могут быть выведены, другие нет.

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

    C++
    device->SetRenderState( D3DRS_STENCILENABLE, true ); // включение
    device->SetRenderState( D3DRS_STENCILENABLE, false ); // выключение
    Pascal
    device.SetRenderState( D3DRS_STENCILENABLE, 1 ); // включение
    device.SetRenderState( D3DRS_STENCILENABLE, 0 ); // выключение

    Очистка буфера трафарета осуществляется с помощью вызова метода Clear интерфейса IDirect3DDevice9, который использовался нами и для очистки буфера кадра.

    C++
    device->Clear( 0, 0, D3DCLEAR_TARGET | D3DCLEAR_STENCIL,             
                             D3DCOLOR_XRGB(255,255,255), 0.0f, 0 );
    Pascal
    device.Clear( 0, nil, D3DCLEAR_TARGET or D3DCLEAR_STENCIL,
                           D3DCOLOR_XRGB(255,255,255), 0.0, 0 );

    Добавленная константа (D3DCLEAR_STENCIL) в третий аргумент метода указывает, что мы собираемся очищать еще и буфер трафарета. А последний параметр метода (в нашем случае он ноль) определяет значение, которым будет заполнен буфер трафарета.

    В силу того, что буфер трафарета может работать только совместно с буфером глубины, нам придется сказать несколько слов и о нем. Буфер глубины или z-буфер – это вспомогательный "экран" необходимый для удаления невидимых наблюдателю граней и поверхностей. Буфер глубины представляет собой двумерный массив, хранящий z-координаты каждого пикселя. Программно буфер глубины может быть инициализирован с помощью заполнения двух полей структуры D3DPRESENT_PARAMETERS:

    C++
    D3DPRESENT_PARAMETERS params;
    …
    ZeroMemory( params, sizeof(params) );
    …
    params.EnableAutoDepthStencil = true;
    params.AutoDepthStencilFormat = D3DFMT_D16;
    …
    Pascal
    var
    params: TD3DPresentParameters;
    …
    ZeroMemory( @params, SizeOf(params) );
    …
    params.EnableAutoDepthStencil := true;
    params.AutoDepthStencilFormat := D3DFMT_D16;
    …

    Установка поля EnableAutoDepthStencil в значение true разрешает работы с буферами глубины и трафарета. Поле AutoDepthStencilFormat задает их формат. В приведенном выше примере задается формат только для буфера глубины, который имеет 16-ти битный формат памяти.

    Буфер трафарета может быть создан в тот же момент, когда создается буфер глубины. Определяя формат буфера глубины, мы можем указать формат и для трафаретного буфера. Z-буфер и буфер трафарета представляют собой внеэкранные поверхности одинакового размера но разного формата.

    Ниже приведены константы, которые позволяют задать формат буфера глубины и трафарета совместно:

    D3DFMT_D24S8 буфер глубины определяется 24 битами на пиксель; трафаретный буфер задан 8-ю битами на пиксель.
    D3DFMT_D15S1 буфер глубины определяется 15 битами на пиксель; трафаретный буфер задан одним битом на пиксель.
    D3DFMT_D24X4S4 буфер глубины определяется 24 битами на пиксель; трафаретный буфер задан 4-мя битами на пиксель и 4 бита не используются

    Следует отметить, что не все видеокарты могут поддерживать 8-ми битный буфер трафарета.

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

    (ref mask) ОперацияСравнения (value mask),

    где символ "" означает побитовую операцию AND,

    mask – некоторая заданная маска сравнения, которая может быть использована для того чтобы скрыть (выключить) некоторые биты одновременно в двух параметрах: value и ref (по умолчанию mask = 0xffffffff ).

    Изменить значение маски трафарета можно следующим образом:

    C++ device->SetRenderState( D3DRS_STENCILMASK, 0xff00ffff );
    Pascal device.SetRenderState( D3DRS_STENCILMASK, $ff00ffff );

    Значение, задаваемое параметром ref по умолчанию равно нулю. Изменить его можно с помощью следующих строк:

    C++ device->SetRenderState( D3DRS_STENCILREF, 1 );
    Pascal device.SetRenderState( D3DRS_STENCILREF, 1 );

    Тест трафарета сравнивает два значения (ref mask) и (value mask), и если результат сравнения выдает истину, то тест считается успешно пройденным. В качестве операции сравнения могут выступать следующие 8 предопределенных констант:

    Константа Тест трафарета завершается успешно в случае …
    D3DCMP_NEVER Никогда
    D3DCMP_LESS Если (ref mask) < (value mask)
    D3DCMP_EQUAL Если (ref mask) = (value mask)
    D3DCMP_LESSEQUAL Если (ref mask) <= (value mask)
    D3DCMP_GREATER Если (ref mask) > (value mask)
    D3DCMP_NOTEQUAL Если (ref mask) <> (value mask)
    D3DCMP_GREATEREQUAL Если (ref mask) >= (value mask)
    D3DCMP_ALWAYS Всегда

    Задать нужную операцию сравнения с помощью следующего вызова:

    C++ device->SetRenderState( D3DRS_STENCILFUNC, <операция сравнения> );
    Pascal device.SetRenderState( D3DRS_STENCILFUNC, <операция сравнения> );

    где <операция сравнения> - одна из перечисленных в таблице констант.

    Если тест трафарета завершился неудачно, то для данных пикселей происходит блокировка записи в буфер кадра. Если же тест трафарета проходит успешно, то пиксели записываются в буфер кадра.

    Библиотека Direct3D позволяет определить действия, которые будут выполнены в случае:

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

    SetRenderState( D3DRS_STENCILFAIL, <действие> );
    SetRenderState( D3DRS_STENCILZFAIL, <действие>);
    
    SetRenderState( D3DRS_STENCILPASS, <действие>);

    В качестве <действие> может выступать одна из предопределенных констант:

    Константа Действие
    D3DSTENCILOP_KEEP Не изменять значение в буфере трафарета
    D3DSTENCILOP_ZERO Установить значение в буфере трафарета в ноль
    D3DSTENCILOP_REPLACE Заменить значение в буфере трафарета на значение ref, определенное константой D3DRS_STENCILREF
    D3DSTENCILOP_INCRSAT Увеличить значение буфера трафарета на единицу
    D3DSTENCILOP_DECRSAT Уменьшить значение буфера трафарета на единицу
    D3DSTENCILOP_INVERT Произвести операцию побитового инвертирования
    D3DSTENCILOP_INCR Увеличить значение буфера трафарета на единицу
    D3DSTENCILOP_DECR Уменьшить значение буфера трафарета на единицу

    Различие между константами D3DSTENCILOP_INCRSAT и D3DSTENCILOP_INCR заключается в том, что при выходе за границу допустимого диапазона значений, в первом случае результат будет приведен к максимальному значению, а во втором – нулю. Аналогично с константами D3DSTENCILOP_DECRSAT и D3DSTENCILOP_DECR: в случае выхода за левую границу интервала (ноль), результат будет приведен к нулю, а во втором случае к максимальному значению.

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

    Алгоритмически шаги, достижения представленного результата можно записать так:

    Шаг 1.

    Очистка буфера кадра и буфера трафарета (значение для фона в буфере трафарета - ноль)

    device->Clear(0, 0, D3DCLEAR_TARGET | D3DCLEAR_STENCIL,
                  D3DCOLOR_XRGB(255,255,255), 0.0f, 0);
    Шаг 2.

    Вывод квадрата, покрытого текстурой (тест трафарета при этом отключен)

    …
    device->SetTexture(0, tex);
    device->DrawPrimitive(D3DPT_TRIANGLELIST, 0, 2);
    …
    Шаг 3.

    3.1 Включаем (разрешаем) тест трафарета.

    3.2. В качестве параметра прохождения теста трафарета установить D3DCMP_NEVER (тест никогда не проходит и, следовательно, примитив не будет записан в буфер кадра).

    3.3. В качестве значения записать в буфер трафарета, например, число два.

    3.4. В качестве действия отрицательного прохождения теста трафарета установить D3DSTENCILOP_REPLACE (в буфере трафарета будет записана "двойка" на месте вырезки)

    3.5. Вызвать функцию отрисовки желтого треугольника (сам треугольник не будет нарисован, но буфер трафарета обновит свое содержимое)

    …
    device->SetRenderState(D3DRS_STENCILENABLE, true);
    device->SetRenderState(D3DRS_STENCILFUNC, D3DCMP_NEVER);
    device->SetRenderState(D3DRS_STENCILREF, 0x2);
    device->SetRenderState(D3DRS_STENCILFAIL, D3DSTENCILOP_REPLACE);
    device->DrawPrimitive(D3DPT_TRIANGLELIST, 0, 1);
    …
    Шаг 4.

    4.1. В качестве параметра прохождения теста трафарета установить D3DCMP_GREATER

    4.2. В качестве значения, с которым будет сравниваться содержимое буфера трафарета, установить, например, число один.

    4.3. Вывести разноцветный треугольник

    …
    device->SetRenderState(D3DRS_STENCILFUNC, D3DCMP_ GREATER);
    device->SetRenderState(D3DRS_STENCILREF, 0x1);
    device->SetRenderState(D3DRS_STENCILFAIL, D3DSTENCILOP_REPLACE);
    device->DrawPrimitive(D3DPT_TRIANGLELIST, 3, 1);
    …

    Таким образом, содержимое буфера трафарета будет выглядеть следующим образом:

    Зеленый цвет соответствует значению ноль в буфере трафарета (фон), желтый – значению два, красный – значению один (разноцветный треугольник).

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

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

    Страницы:

    Полупрозрачность

    Рассмотрим далее реализацию такого эффекта как полупрозрачность ( alpha blending ). Этот механизм позволяет задавать для выводимых примитивов прозрачные и полупрозрачные пиксели. Т.е. существует возможность указать, какие пиксели не будут выводиться в силу своей полной прозрачности, а какие будут выводиться частично прозрачными. Полупрозрачность основывается на принципе смешивания цветов. Математически это можно выразить так: ColorResult = Color1*(1-t) + Color2*t, 0<=t<=1. Эта векторная запись должна интерпретироваться для каждого отдельного цветового канала. Пусть ColorResult = (r, g, b), Color1 = (r1, g1, b1), Color2 = (r2, g2, b2), тогда

    r = r1*(1-t) + r2*t
    g = g1*(1-t) + g2*t
    b = b1*(1-t) + b2*t, 0<=t<=1.

    Ниже приведен пример смешивания двух цветов (красного и зеленого) для различных значений параметра t (Color1 = красный = (255,0,0) Color2 = зеленый = (0,255,0)).

    t=0 t=1/8 t=2/8 t=3/8 t=4/8 t=5/8 t=6/8 t=7/8 t=1

    При работе с полупрозрачностью, как правило, имеют дело (оперируют) с двумя цветами: цвет источника ( source color ) – это пиксель, который вы собираетесь отобразить (записать в буфер кадра) и цвет приемника ( destination color ) – это пиксель, который уже существует и записан в буфере кадра. Другими словами можно сказать, что цвет источника ( source color ) – "пиксель который рисуем", а цвет приемника ( destination color ) – "пиксель на котором рисуем". Механизм полупрозрачности использует следующую формулу для управления степенью полупрозрачности:

    Финальный цвет = 
    Цвет пикселя источника * Коэффициент прозрачности источника +
    Цвет пикселя приемника * Коэффициент прозрачности приемника.

    Программист может управлять коэффициентами прозрачности с помощью флагов:

    коэффициент прозрачности источника - D3DRS_SRCBLEND,

    коэффициент прозрачности приемника - D3DRS_DESTBLEND и используя формулу FinalPixel = SourcePixelColor*SourceBlendFactor + DestPixelColor*DestBlendFactor.

    Механизм полупрозрачности по умолчанию выключен как опция. Активировать/деактивировать полупрозрачность можно следующим образом:

    C++ device->SetRenderState( D3DRS_ALPHABLENDENABLE, {TRUE, FALSE} );
    Pascal device.SetRenderState( D3DRS_ALPHABLENDENABLE, {1, 0} );

    Установка коэффициентов смешивания ( SourceBlendFactor и DestBlendFactor ) осуществляется следующим образом:

    SetRenderState( D3DRS_SRCBLEND, SourceBlendFactor ),
    SetRenderState( D3DRS_DESTBLEND, DestBlendFactor ),

    где в качестве SourceBlendFactor и DestBlendFactor могут выступать предопределенные константы:

    D3DBLEND_ZERO—blendFactor=(0,0,0,0)
    D3DBLEND_ONE—blendFactor=(1,1,1,1)
    D3DBLEND_SRCCOLOR—blendFactor=(Rs, Gs, Bs, As)
    D3DBLEND_INVSRCCOLOR—blendFactor=(1–Rs, 1–Gs, 1–Bs, 1–As)
    D3DBLEND_SRCALPHA—blendFactor=(As, As, As, As)
    D3DBLEND_INVSRCALPHA—blendFactor=(1–As, 1–As, 1–As, 1–As)
    D3DBLEND_DESTALPHA—blendFactor=(Ad, Ad, Ad, Ad)
    D3DBLEND_INVDESTALPHA—blendFactor=(1–Ad, 1–Ad, 1–Ad, 1–Ad)
    D3DBLEND_DESTCOLOR—blendFactor=(Rd, Gd, Bd, Ad)
    D3DBLEND_INVDESTCOLOR—blendFactor=(1–Rd, 1–Gd, 1–Bd, 1–Ad)
    D3DBLEND_SRCALPHASAT—blendFactor=(f,f,f,1), где f=min(As, 1–Ad).
    По умолчанию SourceBlendFactor = D3DBLEND_SRCALPHA
    DestBlendFactor = D3DBLEND_INVSRCALPHA.

    Рассмотрим несколько примеров использования механизма полупрозрачности.

    Пример 1.

    Если мы не хотим ничего "смешивать", тогда можно воспользоваться такой формулой:

    FinalPixel = SourcePixelColor*1 + DestPixelColor*0.

    Этого можно достичь, выставив следующие значения коэффициентов смешивания:

    SetRenderState( D3DRS_SRCBLEND, D3DBLEND_ONE );
    SetRenderState( D3DRS_DESTBLEND,D3DBLEND_ZERO );

    Пример 2.

    Чтобы происходило "сложение" цветов, можно использовать такую формулу:

    FinalPixel = SourcePixelColor*1 + DestPixelColor*1.

    Для этого, оба коэффициента смешивания выставим в единицу:

    SetRenderState( D3DRS_SRCBLEND, D3DBLEND_ONE );
    SetRenderState( D3DRS_DESTBLEND, D3DBLEND_ONE );

    Ниже приведен визуальный пример такого "сложения" цветов.

    Следует отметить, что примитивы при полупрозрачности могут быть не только однотонными. Ниже показаны примеры "умножения" цветов для примитивов, с плавными переходами цветов.

    Пример 3.

    Эффект "перемножения" цветов примитивов можно получить с помощью формулы

    FinalPixel = SourcePixelColor*0 + DestPixelColor*SourcePixelColor.

    Значения коэффициентов смешивания выставим следующим образом:

    SetRenderState( D3DRS_SRCBLEND, D3DBLEND_ZERO );
    SetRenderState( D3DRS_DESTBLEND, D3DBLEND_SRCCOLOR );

    Ниже показаны примеры подобного "умножения" цветов при различном фоне.

    цвет фона D3DCOLOR_XRGB(0,0,0) цвет фона D3DCOLOR_XRGB(255,255,255)

    Прозрачность может "содержаться" и в вершинах примитивов. В дополнение к красной ( red ), зеленой ( green ) и синей ( blue ) цветовым составляющим, каждый пиксель может иметь "прозрачную" составляющую или так называемый альфа канал ( alpha channel ). Альфа канал имеет 256 уровней прозрачности, 0…255:

    0 – пиксель полностью прозрачен

    255 – пиксель полностью непрозрачен

    128 – пиксель прозрачен наполовину.

    До сих пор цвет мы определяли с помощью тройки чисел RGB, используя макрос-функцию D3DCOLOR_XRGB(). Для задания значения альфа составляющей вершины можно воспользоваться функцией D3DCOLOR_ARGB(a, r, g, b), где первый параметр определяет значение полупрозрачности. Следует заметить, что значение альфа канала (как и всех цветовых составляющих) приводится к диапазону значений [0…1]. Ниже приводится пример заполнения вершин примитивов данными о цвете со значением полупрозрачности 50 процентов.

    C++
    points[0].color =  D3DCOLOR_ARGB( 128, 255, 0, 0 );
    …
    Pascal
    points[0].color := D3DCOLOR_ARGB( 128, 255, 0, 0 );
    …

    Использовать полупрозрачность в вершинах примитивов можно с помощью все той же формулы

    FinalPixel = SourcePixelColor*SourceBlendFactor + 
       +DestPixelColor*DestBlendFactor,

    при этом задействовав константы смешивания с суффиксом ALPHA. Так, например, следующие установки коэффициентов смешивания

    SetRenderState( D3DRS_SRCBLEND, D3DBLEND_SRCALPHA );
    SetRenderState( D3DRS_DESTBLEND, D3DBLEND_INVSRCALPHA );

    преобразуют формулу к виду

    FinalPixel = SourcePixelColor*(Alpha) + DestPixelColor*(1- Alpha),

    где Alpha – значение альфа составляющей пикселя-источника.

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

    D3DCOLOR_XRGB(255,0,0); D3DCOLOR_ARGB(128,0,0,255);

    Последовательность вывода примитивов будет такой:

  • Первым рисуется красный треугольник (полупрозрачность выключена);
  • Включаем полупрозрачность: SetRenderState(D3DRS_ALPHABLENDENABLE, 1) ;
  • Рисуем синий треугольник (в вершинах задана 50 % полупрозрачность);
  • В результате формула смешивания примет вид: FinalPixel = Синий*0.5 + Красный*(1-0.5).

    Ниже приведены примеры вывода примитивов с различной степенью полупрозрачности.

    ARGB = (32,0,0,255) ARGB = (64,0,0,255) ARGB = (128,0,0,255)
    ARGB = (160,0,0,255) ARGB = (192,0,0,255) ARGB(255,0,0,255)

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

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

    Последовательность вывода примитивов должна быть следующей:

  • Вначале выводится квадрат с текстурой, при этом полупрозрачность выключена;
  • Включается режим полупрозрачности с нужными коэффициентами смешивания;
  • Выводится цветной треугольник поверх квадрата.
  • Информация о полупрозрачности пикселей может содержаться и в самой текстуре. В этом случае для альфа составляющей отводится, как правило, такое же количество бит, что и под каждый из цветовых каналов. Наиболее распространенный формат представления изображения с альфа-каналом это 32 битные изображения, где на каждый канал отводится по 8 бит. Для создания полупрозрачной текстуры можно воспользоваться утилитой DirectX Texture Tool, которая поставляется совместно с DirectX SDK. Сам альфа-канал можно создать в виде изображения в оттенках серого цвета, в котором абсолютно черные пиксели будут соответствовать полной прозрачности, а белые пиксели – полной непрозрачности.

    По умолчанию если текстура содержит альфа канал, то значение альфа составляющей берется из текстуры. Если же альфа канал не присутствует в текстуре, то значение альфа составляющей будет получено из вершины примитива. Тем не менее, можно явно указать "источник" альфа канала:

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

    Ниже приведен пример вывода полупрозрачной текстуры.

    Текстура (RGB канал) Альфа канал Результат

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

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

    Исходное изображение Альфа канал Вывод на текстуру

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

    Цветовой ключ

    В библиотеке Direct3D имеется функция D3DXCreateTextureFromFileEx(), которая позволяет задать так называемый цветовой ключ ( color key ). Механизм цветового ключа заключается в том, что оговаривается заданный цвет, который становится прозрачным при выводе текстуры на некоторую поверхность. Данная функция имеет 14 параметров, но нам для рассмотрения примера потребуется всего 4, для остальных параметров зададим значения по умолчанию. Первый параметр функции представляет собой указатель на устройство вывода, второй содержит имя загружаемого графического файла текстуры, одиннадцатый параметр и представляет собой цветовой ключ в формате ARGB, причем значение альфа составляющей должно обязательно быть 255, и последний параметр – указатель на переменную, в которую будет возвращен результат вызова. Ниже приведен пример вызова этой функции.

    C++
    D3DXCreateTextureFromFileEx(device, "tree.bmp", D3DX_DEFAULT,       
                            D3DX_DEFAULT, D3DX_DEFAULT, 0,
                            D3DFMT_UNKNOWN, D3DPOOL_MANAGED,
                            D3DX_DEFAULT, D3DX_DEFAULT, 
                        D3DCOLOR_ARGB(255,0,0,0), NULL, NULL, tex);
    Pascal
    D3DXCreateTextureFromFileEx(device, 'tree.bmp', D3DX_DEFAULT,       
                            D3DX_DEFAULT, D3DX_DEFAULT, 0,
                            D3DFMT_UNKNOWN, D3DPOOL_MANAGED,
                            D3DX_DEFAULT, D3DX_DEFAULT, 
                            D3DCOLOR_ARGB(255,0,0,0), nil, nil, tex);

    После загрузки текстуры с цветовым ключом необходимо включить режим полупрозрачности и выставить необходимые параметры смешивания цветов:

    device->SetRenderState(D3DRS_ALPHABLENDENABLE, true);
    device->SetRenderState(D3DRS_SRCBLEND, D3DBLEND_SRCALPHA);
    device->SetRenderState(D3DRS_DESTBLEND, D3DBLEND_INVSRCALPHA);

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

    Буфер трафарета

    Библиотека Direct3D располагает средствами работы с так называемым буфером трафарета. Буфер трафарета представляет собой двумерный массив с размерами как у буфера кадра и z-буфера, причем пиксель с координатами (x,y) в буфере трафарета будет соответствовать пикселю с такими же координатами в буфере кадра. Буфер трафарета работает как маска (трафарет), позволяя нам блокировать вывод некоторых пикселей на экран по заданному правилу. Принцип работы с буфером трафарета – это, как правило, двухпроходный алгоритм. Сначала мы разбиваем область вывода на зоны и каждой зоне присваиваем номер, при этом ничего не выводится на экран. Затем на основании некоторого установленного правила, мы производим непосредственный вывод сцены на экран, причем одни зоны могут быть выведены, другие нет.

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

    C++
    device->SetRenderState( D3DRS_STENCILENABLE, true ); // включение
    device->SetRenderState( D3DRS_STENCILENABLE, false ); // выключение
    Pascal
    device.SetRenderState( D3DRS_STENCILENABLE, 1 ); // включение
    device.SetRenderState( D3DRS_STENCILENABLE, 0 ); // выключение

    Очистка буфера трафарета осуществляется с помощью вызова метода Clear интерфейса IDirect3DDevice9, который использовался нами и для очистки буфера кадра.

    C++
    device->Clear( 0, 0, D3DCLEAR_TARGET | D3DCLEAR_STENCIL,             
                             D3DCOLOR_XRGB(255,255,255), 0.0f, 0 );
    Pascal
    device.Clear( 0, nil, D3DCLEAR_TARGET or D3DCLEAR_STENCIL,
                           D3DCOLOR_XRGB(255,255,255), 0.0, 0 );

    Добавленная константа (D3DCLEAR_STENCIL) в третий аргумент метода указывает, что мы собираемся очищать еще и буфер трафарета. А последний параметр метода (в нашем случае он ноль) определяет значение, которым будет заполнен буфер трафарета.

    В силу того, что буфер трафарета может работать только совместно с буфером глубины, нам придется сказать несколько слов и о нем. Буфер глубины или z-буфер – это вспомогательный "экран" необходимый для удаления невидимых наблюдателю граней и поверхностей. Буфер глубины представляет собой двумерный массив, хранящий z-координаты каждого пикселя. Программно буфер глубины может быть инициализирован с помощью заполнения двух полей структуры D3DPRESENT_PARAMETERS:

    C++
    D3DPRESENT_PARAMETERS params;
    …
    ZeroMemory( params, sizeof(params) );
    …
    params.EnableAutoDepthStencil = true;
    params.AutoDepthStencilFormat = D3DFMT_D16;
    …
    Pascal
    var
    params: TD3DPresentParameters;
    …
    ZeroMemory( @params, SizeOf(params) );
    …
    params.EnableAutoDepthStencil := true;
    params.AutoDepthStencilFormat := D3DFMT_D16;
    …

    Установка поля EnableAutoDepthStencil в значение true разрешает работы с буферами глубины и трафарета. Поле AutoDepthStencilFormat задает их формат. В приведенном выше примере задается формат только для буфера глубины, который имеет 16-ти битный формат памяти.

    Буфер трафарета может быть создан в тот же момент, когда создается буфер глубины. Определяя формат буфера глубины, мы можем указать формат и для трафаретного буфера. Z-буфер и буфер трафарета представляют собой внеэкранные поверхности одинакового размера но разного формата.

    Ниже приведены константы, которые позволяют задать формат буфера глубины и трафарета совместно:

    D3DFMT_D24S8 буфер глубины определяется 24 битами на пиксель; трафаретный буфер задан 8-ю битами на пиксель.
    D3DFMT_D15S1 буфер глубины определяется 15 битами на пиксель; трафаретный буфер задан одним битом на пиксель.
    D3DFMT_D24X4S4 буфер глубины определяется 24 битами на пиксель; трафаретный буфер задан 4-мя битами на пиксель и 4 бита не используются

    Следует отметить, что не все видеокарты могут поддерживать 8-ми битный буфер трафарета.

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

    (ref mask) ОперацияСравнения (value mask),

    где символ "" означает побитовую операцию AND,

    mask – некоторая заданная маска сравнения, которая может быть использована для того чтобы скрыть (выключить) некоторые биты одновременно в двух параметрах: value и ref (по умолчанию mask = 0xffffffff ).

    Изменить значение маски трафарета можно следующим образом:

    C++ device->SetRenderState( D3DRS_STENCILMASK, 0xff00ffff );
    Pascal device.SetRenderState( D3DRS_STENCILMASK, $ff00ffff );

    Значение, задаваемое параметром ref по умолчанию равно нулю. Изменить его можно с помощью следующих строк:

    C++ device->SetRenderState( D3DRS_STENCILREF, 1 );
    Pascal device.SetRenderState( D3DRS_STENCILREF, 1 );

    Тест трафарета сравнивает два значения (ref mask) и (value mask), и если результат сравнения выдает истину, то тест считается успешно пройденным. В качестве операции сравнения могут выступать следующие 8 предопределенных констант:

    Константа Тест трафарета завершается успешно в случае …
    D3DCMP_NEVER Никогда
    D3DCMP_LESS Если (ref mask) < (value mask)
    D3DCMP_EQUAL Если (ref mask) = (value mask)
    D3DCMP_LESSEQUAL Если (ref mask) <= (value mask)
    D3DCMP_GREATER Если (ref mask) > (value mask)
    D3DCMP_NOTEQUAL Если (ref mask) <> (value mask)
    D3DCMP_GREATEREQUAL Если (ref mask) >= (value mask)
    D3DCMP_ALWAYS Всегда

    Задать нужную операцию сравнения с помощью следующего вызова:

    C++ device->SetRenderState( D3DRS_STENCILFUNC, <операция сравнения> );
    Pascal device.SetRenderState( D3DRS_STENCILFUNC, <операция сравнения> );

    где <операция сравнения> - одна из перечисленных в таблице констант.

    Если тест трафарета завершился неудачно, то для данных пикселей происходит блокировка записи в буфер кадра. Если же тест трафарета проходит успешно, то пиксели записываются в буфер кадра.

    Библиотека Direct3D позволяет определить действия, которые будут выполнены в случае:

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

    SetRenderState( D3DRS_STENCILFAIL, <действие> );
    SetRenderState( D3DRS_STENCILZFAIL, <действие>);
    
    SetRenderState( D3DRS_STENCILPASS, <действие>);

    В качестве <действие> может выступать одна из предопределенных констант:

    Константа Действие
    D3DSTENCILOP_KEEP Не изменять значение в буфере трафарета
    D3DSTENCILOP_ZERO Установить значение в буфере трафарета в ноль
    D3DSTENCILOP_REPLACE Заменить значение в буфере трафарета на значение ref, определенное константой D3DRS_STENCILREF
    D3DSTENCILOP_INCRSAT Увеличить значение буфера трафарета на единицу
    D3DSTENCILOP_DECRSAT Уменьшить значение буфера трафарета на единицу
    D3DSTENCILOP_INVERT Произвести операцию побитового инвертирования
    D3DSTENCILOP_INCR Увеличить значение буфера трафарета на единицу
    D3DSTENCILOP_DECR Уменьшить значение буфера трафарета на единицу

    Различие между константами D3DSTENCILOP_INCRSAT и D3DSTENCILOP_INCR заключается в том, что при выходе за границу допустимого диапазона значений, в первом случае результат будет приведен к максимальному значению, а во втором – нулю. Аналогично с константами D3DSTENCILOP_DECRSAT и D3DSTENCILOP_DECR: в случае выхода за левую границу интервала (ноль), результат будет приведен к нулю, а во втором случае к максимальному значению.

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

    Алгоритмически шаги, достижения представленного результата можно записать так:

    Шаг 1.

    Очистка буфера кадра и буфера трафарета (значение для фона в буфере трафарета - ноль)

    device->Clear(0, 0, D3DCLEAR_TARGET | D3DCLEAR_STENCIL,
                  D3DCOLOR_XRGB(255,255,255), 0.0f, 0);
    Шаг 2.

    Вывод квадрата, покрытого текстурой (тест трафарета при этом отключен)

    …
    device->SetTexture(0, tex);
    device->DrawPrimitive(D3DPT_TRIANGLELIST, 0, 2);
    …
    Шаг 3.

    3.1 Включаем (разрешаем) тест трафарета.

    3.2. В качестве параметра прохождения теста трафарета установить D3DCMP_NEVER (тест никогда не проходит и, следовательно, примитив не будет записан в буфер кадра).

    3.3. В качестве значения записать в буфер трафарета, например, число два.

    3.4. В качестве действия отрицательного прохождения теста трафарета установить D3DSTENCILOP_REPLACE (в буфере трафарета будет записана "двойка" на месте вырезки)

    3.5. Вызвать функцию отрисовки желтого треугольника (сам треугольник не будет нарисован, но буфер трафарета обновит свое содержимое)

    …
    device->SetRenderState(D3DRS_STENCILENABLE, true);
    device->SetRenderState(D3DRS_STENCILFUNC, D3DCMP_NEVER);
    device->SetRenderState(D3DRS_STENCILREF, 0x2);
    device->SetRenderState(D3DRS_STENCILFAIL, D3DSTENCILOP_REPLACE);
    device->DrawPrimitive(D3DPT_TRIANGLELIST, 0, 1);
    …
    Шаг 4.

    4.1. В качестве параметра прохождения теста трафарета установить D3DCMP_GREATER

    4.2. В качестве значения, с которым будет сравниваться содержимое буфера трафарета, установить, например, число один.

    4.3. Вывести разноцветный треугольник

    …
    device->SetRenderState(D3DRS_STENCILFUNC, D3DCMP_ GREATER);
    device->SetRenderState(D3DRS_STENCILREF, 0x1);
    device->SetRenderState(D3DRS_STENCILFAIL, D3DSTENCILOP_REPLACE);
    device->DrawPrimitive(D3DPT_TRIANGLELIST, 3, 1);
    …

    Таким образом, содержимое буфера трафарета будет выглядеть следующим образом:

    Зеленый цвет соответствует значению ноль в буфере трафарета (фон), желтый – значению два, красный – значению один (разноцветный треугольник).

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

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

    Вернуться к учебному плану