Каркас Windows-приложения. Особенности нового каркаса. Перемещение в пространстве (с текстурированными стенами), страница 19

q  zfail — То же, но для случая, когда трафаретный тест (stencil test) прошел, а тест глубины — нет.

q  zpass — То же, но для случая, когда оба теста прошли (или тест глубины выключен).

Все три параметра имеют тип перечисления и могут принимать одно из 6 значений:

GL_KEEP

Оставить текущее значение

GL_ZERO

Обнулить значение в stencil buffer

GL_REPLACE

Установить значение ref  в stencil buffer

GL_INCR

Увеличить текущее значение в stencil buffer

GL_DECR

Уменьшить текущее значение в stencil buffer

GL_INVERT

Побитово инвертировать текущее значение в stencil buffer

Если трафаретный тест не прошел, то изображение (то есть значения буфера цвета и буфера глубины) не изменяются. При этом, однако могут произойти изменения в самом stencil buffer. Параметр fail как раз их и определяет. Другие два параметра glStencilOp определяют, что делать, если stencil test прошел. Теперь все решает тест глубины (прошел он или не прошел).

Логика использования трафарета не проста, она требует повышенного внимания, поэтому лучше обратиться к примеру. Прежде всего вставьте в функцию Init строку кода, которая задает начальное значение трафаретного буфера.

glClearStencil (0);

Далее в нашем примере будут использованы такие настройки этого буфера.

glColorMask (0, 0, 0, 0);    // Set Color Mask

glEnable (GL_STENCIL_TEST);

glStencilFunc (GL_ALWAYS, 1, 1);

glStencilOp (GL_KEEP, GL_KEEP, GL_REPLACE);

Вызов glColorMask с нулями (а точнее, с FALSE) запрещает записывать в буфер кадра все три компоненты цвета. Это надо понимать как подготовку к заполнению stensil-буфера. Теперь все рисование пойдет не в буфер кадра, а в буфер трафарета. Вызов glEnable очевиден. Вызов glStencilOp с таким набором параметров означает, что в stencil-буфер попадет (см. GL_REPLACE) единица, если пройдет stencil test, а он пройдет всегда, благодаря установке GL_ALWAYS. Эти команды (все вместе) являются подготовкой к тому, что последует дальше. Следующие команды изобразят в буфере трафарета поверхность пола. Более точно, они лишь обозначат поверхность в буфере (единицами).

glDisable (GL_DEPTH_TEST);

DrawFloor();  // Draw the floor to the stencil buffer. We only want to mark it in the stencil buffer

glEnable (GL_DEPTH_TEST);

Финт с glDisable, glEnable позволяет использовать третий параметр функции glStencilOp. Итак поверхность пола обозначена в буфере трафарета. Далее надо создать отражение мяча. Оно должно располагаться в этой самой поверхности (только там и нигде более). Именно для этой цели и служит трафарет. Он отсечет все попытки отражения изобразиться где-либо еще (вне пределов пола). Эти попытки будут происходить, так как мяч и его отражение перемещается пользователем. Следующие команды создают отражение мяча.

glColorMask (1, 1, 1, 1);

glStencilFunc (GL_EQUAL, 1, 1);  // We draw only where the stencil is 1 (i.e. where the floor was drawn)

glStencilOp (GL_KEEP, GL_KEEP, GL_KEEP);   // Don't change the stencil buffer

glPushMatrix();

glScalef (1,-1, 1);         // Mirror Y Axis

glTranslatef (0, height, 0); // Position The Ball

glRotatef (angleX, 1, 0, 0);

glRotatef (angleY, 0, 1, 0);

DrawBall();   / Reflection of the ball

glPopMatrix();

glDisable (GL_STENCIL_TEST); // We don't need the stencil buffer any more

Вызов glColorMask с единицами (а точнее, с TRUE) вновь разрешает записывать в буфер кадра все три компоненты цвета. Это — подготовка к нормальному рисованию, а не заполнению stensil-буфера. Но это нормальное рисование будет происходить с учетом трафарета, так как он остался включенным. Команда glStencilFunc (GL_EQUAL, 1, 1); говорит OpenGL, что новые пикселы пройдут в буфер кадра только если они совпадут с трафаретом. Следующий вызов glStencilOp говорит о том, что сам буфер трафарета не будет изменяться.