netlib.narod.ru< Назад | Оглавление | Далее >

8.1. Использование буфера трафарета

Чтобы работать с буфером трафарета мы должны сперва создать его при инициализации Direct3D, а затем разрешить его использование при визуализации. Создание буфера трафарета рассматривается в разделе 8.1.1. Чтобы разрешить использование буфера трафарета необходимо присвоить режиму визуализации D3DRS_STENCILENABLE значение true. Чтобы запретить использование буфера трафарета, присвойте режиму визуализации D3DRS_STENCILENABLE значение false. В приведенном ниже фрагменте кода мы сначала разрешаем использование буфера трафарета, а затем запрещаем его:

Device->SetRenderState(D3DRS_STENCILENABLE, true);

... // работа с буфером трафарета

Device->SetRenderState(D3DRS_STENCILENABLE, false);

 

ПРИМЕЧАНИЕ
DirectX 9.0 поддерживает двухсторонние трафареты (two-sided stencil, в этой книге они не используются), которые ускоряют визуализацию теневых объемов благодаря уменьшению количества проходов визуализации, необходимых для рисования теневого объема. Подробнее об этом говорится в документации к SDK.

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

Device->Clear(0, 0,
     D3DCLEAR_TARGET | D3DCLEAR_ZBUFFER | D3DCLEAR_STENCIL,
     0xff000000, 1.0f, 0 );

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

ПРИМЕЧАНИЕ
Согласно презентации NVIDIA «Creating Reflections and Shadows Using Stencil Buffers» проведенной Марком Дж. Килгардом, в современных видеокартах, если вы используете буфер глубины, использование буфера трафарета можно рассматривать как «бесплатное приложение».

8.1.1. Создание буфера трафарета

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

Обратите внимание, что существуют форматы в которых разряды под буфер трафарета не выделяются вообще. Например, формат D3DFMT_D32 говорит, что создается только 32-разрядный буфер глубины.

Кроме того, поддерживаемые форматы буфера трафарета различаются в зависимости от модели видеокарты. Например, некоторые видеокарты не поддерживают 8-разрядный буфер трафарета.

8.1.2. Проверка трафарета

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

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

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

Затем в проверке трафарета сравниваются значения LHS и RHS; при этом используется заданная ОперацияСравнения. Результатом вычислений является логическое значение (true или false). Мы записываем пиксель во вторичный буфер, если результатом проверки будет true (тест пройден). Если в результате проверки получается false (тест не пройден), пиксель не будет записан во вторичный буфер. Конечно, если пиксель не записывается во вторичный буфер, соответствующее ему значение в буфере глубины тоже не меняется.

8.1.3. Управление проверкой трафарета

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

8.1.3.1. Эталонное значение трафарета

Эталонное значение трафарета ref по умолчанию равно нулю, но мы можем менять его с помощью режима визуализации D3DRS_STENCILREF. Например, приведенный ниже фрагмент кода сделает эталонное значение трафарета равным единице:

Device->SetRenderState(D3DRS_STENCILREF, 0x1);

Обратите внимание, что мы предпочитаем использовать шестнадцатеричную запись чисел, поскольку она позволяет сразу увидеть распределение битов в числе, а это очень полезно при выполнении поразрядных операций, таких как И.

8.1.3.2. Маска трафарета

Значение маски трафарета mask используется для маскирования (скрытия) отдельных разрядов в эталонном значении трафарета ref и значении из буфера трафарета value. По умолчанию значение маски равно 0xffffffff и никакие разряды не маскируются. Можно изменить значение маски, установив состояние визуализации D3DRS_STENCILMASK. В приведенном ниже коде мы задаем значение, которое будет маскировать 16 старших разрядов:

Device->SetRenderState(D3DRS_STENCILMASK, 0x0000ffff);

 

ПРИМЕЧАНИЕ
Если вы ничего не поняли из разговора о битах и масках, скорее всего вам надо почитать о двоичных и шестнадцатеричных числах, а также о поразрядных операциях.

8.1.3.3. Значение трафарета

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

8.1.3.4. Операция сравнения

Мы можем задать используемую операцию сравнения, установив режим визуализации D3DRS_STENCILFUNC. Операция сравнения должна быть членом перечисления D3DCMPFUNC:

typedef enum _D3DCMPFUNC {
     D3DCMP_NEVER = 1,
     D3DCMP_LESS = 2,
     D3DCMP_EQUAL = 3,
     D3DCMP_LESSEQUAL = 4,
     D3DCMP_GREATER = 5,
     D3DCMP_NOTEQUAL = 6,
     D3DCMP_GREATEREQUAL = 7,
     D3DCMP_ALWAYS = 8,
     D3DCMP_FORCE_DWORD = 0x7fffffff
} D3DCMPFUNC;

8.1.4. Обновление буфера трафарета

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

В приведенных выше примерах StencilOperation — это одна из перечисленных ниже предопределенных констант:

8.1.5. Маска записи трафарета

Помимо уже рассмотренных относящихся к трафарету режимов визуализации, можно устанавливать маску записи, которая будет маскировать заданные разряды в любом записываемом в буфер трафарета значении. Маска записи задается в режиме визуализации D3DRS_STENCILWRITEMASK. Значение по умолчанию — 0xffffffff. В приведенном ниже примере устанавливается маска, которая обнуляет старшие 16 разрядов:

Device->SetRenderState(D3DRS_STENCILWRITEMASK, 0x0000ffff);

netlib.narod.ru< Назад | Оглавление | Далее >

Сайт управляется системой uCoz