Chapter 4
|
GL_NEVER | Не проходит |
GL_LESS | Проходит if ( ref & mask) < ( stencil & mask) |
GL_LEQUAL | Проходит if ( ref & mask) ? ( stencil & mask) |
GL_GREATER | Проходит if ( ref & mask) > ( stencil & mask) |
GL_GEQUAL | Проходит if ( ref & mask) ? ( stencil & mask) |
GL_EQUAL | Проходит if ( ref & mask) = ( stencil & mask) |
GL_NOTEQUAL | Проходит if ( ref & mask) ? ( stencil & mask) |
GL_ALWAYS | Всегда проходит |
Если тест трафарета не пройден, то фрагмент(пикселы) фигуры не прорисовываются в данном месте, т.е. они не попадают в буффер кадра. Если тест пройден, то фигура рисуется. Вторая функция позволяет задать, как будет инициализироваться буфер трафарета. Параметры fail, zfail и zpass могут принимать одно из следующих значений:
GL_KEEP | Сохранить текущее значение в буфере трафарета |
GL_ZERO | Установить значение буфера трафарета в ноль |
GL_REPLACE | Заменить значение буфера трафарета на значение переменной ref, заданной функцие glStencilOp |
GL_INCR | Увеличить на единицу |
GL_DECR | Уменьшить на единицу |
GL_INVERT | Поразрядно инвертировать |
В случае непрохождения теста трафарета над фрагментом выполняется действие, определенное параметром fail. Например, если мы хотим заполнить область трафарета, где рисуется куб единицами, то можно использовать следующи код:
glStencilFunc(GL_NEVER, 1, 0); // значение mask не используется glStencilOp(GL_REPLACE, GL_KEEP, GL_KEEP); auxSolidCube(2.5);
Объясняю подробней: первая функция говорит о том, что тест трафарета всегда проходит неудачно. Вторая функция задает, что в случае неудачного теста трафарета, заменить значение, хранящееся в буфере трафарета, на значение переменной ref, а его мы задали, равным единице. В результате, на экране ничего не нарисуется т.к. тест трафарета завершался неудачно, но в буфере трафарета мы получили проекцию куба из единичек, т.е. буфер трафарета заполнен не только нулями. Теперь мы хотим заполнить двойками область, где прорисовывается сфера. Здесь мы уже должны учитывать буфер глубины, иначе мы заполним двойками всю область, где у нас рисуется сфера. Для того чтобы учитывать буфер глубины, тест трафарета должен завершиться положительно. Третий параметр zpass функции glStencilOp как раз указывает, что делать, если тест трафарета прошел, а тест глубины нет. Поэтому код выглядит так:
glStencilFunc(GL_ALWAYS, 2, 0); // значение mask не используется glStencilOp(GL_KEEP, GL_KEEP, GL_REPLACE); auxSolidSphere(1.5);
В результате получаем буфер трафарета, заполненный нулями, где ничего не было, единицами, где виден куб, и двойками, где видна сфера. В последнем примере тест трафарета прошел успешно, поэтому на экране была нарисована сфера. Но это нам не мешает, мы очистим буфер глубины и буфер цвета, но не буфер трафарета.
glClear( GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
Теперь дело техники нарисовать тот же самый куб без сферы. Надо установить, что тест трафарета проходит, если значение, находящееся в буфере трафарета, совпадает со значением второго параметра функции glStencilFunc. Как вы помните, куб в буфере трафарета имел значение единицы. Поэтому получаем:
glStencilFunc(GL_EQUAL, 1, 255); // куб рисуется только там, где // в буфере трафарета лежат единицы glColor3d(1,1,1); auxSolidCube(2.5);Создайте новый проект с именем stencil. Скопируйте glaux.c в stencil.c и отредактируйте функцию display следующим образом:
void CALLBACK display(void){ // очищаем все буферы glClear( GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT); // разрешаем тест трафарета glEnable(GL_STENCIL_TEST); // рисуем куб и заполняем буффер трафарета единицами // в том месте, где рисуется куб // тут у меня немного по другому, чем выше было разобрано, // но действие выполняется анологичное glStencilFunc(GL_ALWAYS, 1, 0); glStencilOp(GL_KEEP, GL_KEEP, GL_REPLACE); auxSolidCube(2.5); // заполняем буффер трафарета двойками // в том месте, где сфера закрывает куб glStencilFunc(GL_ALWAYS, 2, 0); glStencilOp(GL_KEEP, GL_KEEP, GL_REPLACE); auxSolidSphere(1.5); // очищаем буфферы цвета и глубины glClear( GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); glStencilFunc(GL_EQUAL, 1, 255); glColor3d(1,1,1); auxSolidCube(2.5); // вращаем сцену glRotated(3, 1,0,0); glRotated(5, 0,1,0); glRotated(7, 0,0,1); auxSwapBuffers();}
Теперь, давайте, немного приукрасим нашу программу. Давайте, внутри куба нарисуем красный шар, который будут опоясывать зеленый и синий торы. Делается это следующим образом: как и в предыдущей программе, вы составляете буфер трафарета, после чего очищаете буфер глубины и цета, запрещаете тест трафарета, т.к. нам надо просто вывести фигуры без трафарета, выводите шар с торами и, наконец, включаете тест трафарета и выводите куб с отверстиями. Вот код фунции display:
void CALLBACK display(void){ // очищаем все буферы glClear( GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT); // разрешаем тест трафарета glEnable(GL_STENCIL_TEST); // рисуем куб и заполняем буффер трафарета единицами // в том месте, где рисуется куб // тут у меня немного по другому, чем выше было разобрано, // но действие выполняется анологичное glStencilFunc(GL_ALWAYS, 1, 0); glStencilOp(GL_KEEP, GL_KEEP, GL_REPLACE); auxSolidCube(2.5); // заполняем буффер трафарета двойками // в том месте, где сфера закрывает куб glStencilFunc(GL_ALWAYS, 2, 0); glStencilOp(GL_KEEP, GL_KEEP, GL_REPLACE); auxSolidSphere(1.5); // очищаем буфферы цвета и глубины glClear( GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
// запрещаем тест трафарета и рисуем красную сферу glDisable(GL_STENCIL_TEST); glColor3d(1,0,0); auxSolidSphere(0.5); //синий тор glColor3d(0,0,1); auxSolidTorus(0.15, 0.6); // зеленый тор, повернутый на 90 градусов относительно синего glColor3d(0,1,0); glPushMatrix(); glRotated(90, 1,0,0); auxSolidTorus(0.15, 0.6); glPopMatrix(); //снова разрешаем тест трафарета glEnable(GL_STENCIL_TEST); |