netlib.narod.ru | < Назад | Оглавление | Далее > |
Чтобы работать с буфером трафарета мы должны сперва создать его при инициализации Direct3D, а затем разрешить его использование при визуализации. Создание буфера трафарета рассматривается в разделе 8.1.1. Чтобы разрешить использование буфера трафарета необходимо присвоить режиму визуализации D3DRS_STENCILENABLE значение true. Чтобы запретить использование буфера трафарета, присвойте режиму визуализации D3DRS_STENCILENABLE значение false. В приведенном ниже фрагменте кода мы сначала разрешаем использование буфера трафарета, а затем запрещаем его:
Device->SetRenderState(D3DRS_STENCILENABLE, true); ... // работа с буфером трафарета Device->SetRenderState(D3DRS_STENCILENABLE, false);
Мы можем очистить буфер трафарета, заполнив его указанным значением, с помощью метода IDirect3DDevice9::Clear. Вспомните, что тот же самый метод используется для очистки вторичного буфера и буфера глубины.
Device->Clear(0, 0, D3DCLEAR_TARGET | D3DCLEAR_ZBUFFER | D3DCLEAR_STENCIL, 0xff000000, 1.0f, 0 );
Обратите внимание, что в третьем аргументе мы добавили флаг D3DCLEAR_STENCIL, указывающий что мы хотим очистить буфер трафарета вместе со вторичным буфером и буфером глубины. Для задания значения, которым будет заполнен буфер трафарета используется шестой аргумент; в данном примере мы заполняем буфер нулями.
Буфер трафарета создается в тот же самый момент, когда вы создаете буфер глубины. Задавая формат буфера глубины мы одновременно указываем и формат буфера трафарета. Фактически буфер глубины и буфер трафарета совместно используют один и тот же внеэкранный буфер поверхности, но каждый буфер испльзует свою часть выделяемой для каждого пикселя памяти. Для примера рассмотрим следующие три формата глубины/трафарета:
D3DFMT_D24S8 — Этот формат говорит, что создается 32-разрядный буфер глубины/трафарета в котором для каждого пикселя выделяются 24 бита под буфер глубины и 8 бит под буфер трафарета.
D3DFMT_D24X4S4 — Этот формат говорит, что создается 32-разрядный буфер глубины/трафарета в котором для каждого пикселя выделяются 24 бита под буфер глубины и 4 бита под буфер трафарета. Оставшиеся 4 разряда не используются.
D3DFMT_D15S1 — Этот формат говорит, что создается 16-разрядный буфер глубины/трафарета в котором для каждого пикселя выделяются 15 бит под буфер глубины и 1 бит под буфер трафарета.
Обратите внимание, что существуют форматы в которых разряды под буфер трафарета не выделяются вообще. Например, формат D3DFMT_D32 говорит, что создается только 32-разрядный буфер глубины.
Кроме того, поддерживаемые форматы буфера трафарета различаются в зависимости от модели видеокарты. Например, некоторые видеокарты не поддерживают 8-разрядный буфер трафарета.
Как упоминалось ранее, буфер трафарета можно использовать для блокирования визуализации отдельных частей вторичного буфера. Защищать конкретный пиксель от перезаписи или нет определяется с помощью проверки трафарета, выполняемой по следующей формуле:
(ref & mask) ОперацияСравнения (value & mask)
Если использование трафарета разрешено, проверка трафарета выполняется для каждого пикселя и в ней участвуют два операнда:
Левый операнд (LHS = ref & mask) определяется путем выполнения поразрядной логической операции И между определенным в приложении эталонным значением (ref) и определенным в приложении значением маски (mask).
Правый операнд (RHS = value & mask) определяется путем выполнения поразрядной логической операции И между соответствующим данному пикселю значением из буфера трафарета (value) и определенным в приложении значении маски (mask).
Затем в проверке трафарета сравниваются значения LHS и RHS; при этом используется заданная ОперацияСравнения. Результатом вычислений является логическое значение (true или false). Мы записываем пиксель во вторичный буфер, если результатом проверки будет true (тест пройден). Если в результате проверки получается false (тест не пройден), пиксель не будет записан во вторичный буфер. Конечно, если пиксель не записывается во вторичный буфер, соответствующее ему значение в буфере глубины тоже не меняется.
Для увеличения гибкости Direct3D позволяет нам управлять переменными, используемыми в проверке трафарета. Другими словами, мы можем задавать эталонное значение трафарета, значение маски и даже операцию сравнения. Хотя мы не можем явно задать значение, записываемое в буфер трафарета, у нас есть достаточно возможностей для управления тем, какие значения будут записываться в буфер трафарета (и, кроме того, мы можем очистить буфер).
Эталонное значение трафарета ref по умолчанию равно нулю, но мы можем менять его с помощью режима визуализации D3DRS_STENCILREF. Например, приведенный ниже фрагмент кода сделает эталонное значение трафарета равным единице:
Device->SetRenderState(D3DRS_STENCILREF, 0x1);
Обратите внимание, что мы предпочитаем использовать шестнадцатеричную запись чисел, поскольку она позволяет сразу увидеть распределение битов в числе, а это очень полезно при выполнении поразрядных операций, таких как И.
Значение маски трафарета mask используется для маскирования (скрытия) отдельных разрядов в эталонном значении трафарета ref и значении из буфера трафарета value. По умолчанию значение маски равно 0xffffffff и никакие разряды не маскируются. Можно изменить значение маски, установив состояние визуализации D3DRS_STENCILMASK. В приведенном ниже коде мы задаем значение, которое будет маскировать 16 старших разрядов:
Device->SetRenderState(D3DRS_STENCILMASK, 0x0000ffff);
Как упоминалось ранее это значение в буфере трафарета для текущего пикселя, который участвует в проверке трафарета. Например, если мы проводим проверку трафарета для пикселя, находящегося в позиции (i, j), то значением будет число, хранящееся в позиции (i, j) буфера трафарета. Мы не можем явно устанавливать значения отдельных элементов буфера трафарета, но помните, что можно очищать буфер. Кроме того можно использовать режимы визуализации трафарета чтобы управлять тем, какие значения будут записаны в буфер. Относящиеся к работе с трафаретами режимы визуализации будут рассмотрены ниже.
Мы можем задать используемую операцию сравнения, установив режим визуализации 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;
D3DCMP_NEVER — Проверка трафарета всегда завершается неудачно.
D3DCMP_LESS — Проверка трафарета завершается успешно, если LHS < RHS.
D3DCMP_EQUAL — Проверка трафарета завершается успешно, если LHS = RHS.
D3DCMP_LESSEQUAL — Проверка трафарета завершается успешно, если LHS ≤ RHS.
D3DCMP_GREATER — Проверка трафарета завершается успешно, если LHS > RHS.
D3DCMP_NOTEQUAL — Проверка трафарета завершается успешно, если LHS ≠ RHS.
D3DCMP_GREATEREQUAL — Проверка трафарета завершается успешно, если LHS ≥ RHS.
D3DCMP_ALWAYS — Проверка трафарета всегда завершается успешно.
Помимо алгоритма принятия решения записывать конкретный пиксель во вторичный буфер или нет, мы можем задать правила обновления элементов буфера трафарета в следующих случаях:
Проверка трафарета для пикселя в позиции (i, j) завершилась неудачно. Мы можем определить, как в таком случае будет обновляться элемент (i, j) буфера трафарета установив режим визуализации D3DRS_STENCILFAIL:
Device->SetRenderState(D3DRS_STENCILFAIL, StencilOperation);
Тест глубины для пикселя в позиции (i, j) завершился неудачно. Мы можем определить, как в таком случае будет обновляться элемент (i, j) буфера трафарета установив режим визуализации D3DRS_STENCILZFAIL:
Device->SetRenderState(D3DRS_STENCILZFAIL, StencilOperation);
Тест глубины и проверка трафарета для пикселя в позиции (i, j) завершились успешно. Мы можем определить, как в таком случае будет обновляться элемент (i, j) буфера трафарета установив режим визуализации D3DRS_STENCILPASS:
Device->SetRenderState(D3DRS_STENCILPASS, StencilOperation);
В приведенных выше примерах StencilOperation — это одна из перечисленных ниже предопределенных констант:
D3DSTENCILOP_KEEP — Значение в буфере трафарета не должно меняться (следовательно, остается то значение, которое было в буфере до этого).
D3DSTENCILOP_ZERO — Элементу буфера трафарета присваивается ноль.
D3DSTENCILOP_REPLACE — Элемент буфера трафарета будет замен на эталонное значение трафарета.
D3DSTENCILOP_INCRSAT — Элемент буфера трафарета будет увеличен. Если в результате увеличения будет превышено максимальное допустимое значение элемента буфера трафарета, элементу будет присвоено максимальное допустимое значение.
D3DSTENCILOP_DECRSAT — Элемент буфера трафарета будет уменьшен. Если в результате уменьшения значение элемента буфера трафарета станет меньше нуля, элементу будет присвоен ноль.
D3DSTENCILOP_INVERT — Элемент буфера трафарета будет поразрядно инвертирован.
D3DSTENCILOP_INCR — Элемент буфера трафарета будет увеличен. Если в результате увеличения будет превышено максимальное допустимое значение элемента буфера трафарета, элементу будет присвоен ноль.
D3DSTENCILOP_DECR — Элемент буфера трафарета будет уменьшен. Если в результате уменьшения значение элемента буфера трафарета станет меньше нуля, элементу будет присвоено максимальное допустимое значение.
Помимо уже рассмотренных относящихся к трафарету режимов визуализации, можно устанавливать маску записи, которая будет маскировать заданные разряды в любом записываемом в буфер трафарета значении. Маска записи задается в режиме визуализации D3DRS_STENCILWRITEMASK. Значение по умолчанию — 0xffffffff. В приведенном ниже примере устанавливается маска, которая обнуляет старшие 16 разрядов:
Device->SetRenderState(D3DRS_STENCILWRITEMASK, 0x0000ffff);
netlib.narod.ru | < Назад | Оглавление | Далее > |