Опубликован: 08.07.2007 | Доступ: свободный | Студентов: 1429 / 183 | Оценка: 4.43 / 4.02 | Длительность: 13:47:00
Специальности: Программист
Лекция 4:

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

< Лекция 3 || Лекция 4: 12345 || Лекция 5 >

Тест трафарета сравнивает два значения (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 позволяет определить действия, которые будут выполнены в случае:

  1. если тест трафарета завершился неудачно;
  2. если тест трафарета прошел успешно, а тест глубины завершился отрицательно;
  3. если и тест трафарета, и тест глубины завершились успешно.

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

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);
…

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


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

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

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

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

< Лекция 3 || Лекция 4: 12345 || Лекция 5 >