3 С. А. Васильев opengl компьютерная графика
Скачать 491.09 Kb.
|
GL_NEVER НИКОГДА GL_LESS Если поступающее значение меньше, чем ref GL_EQUAL Если поступающее значение равно ref GL_LEQUAL Если поступающее значение меньше или равно ref GL_GREATE R Если поступающее значение больше, чем ref GL_NOTEQU AL Если поступающее значение не равно ref 53 Параметр Тест завершается положительно в слу- чае GL_GEQUAL Если поступающее значение больше или рав- но ref GL_ALWAYS Всегда. Установлено по умолчанию Данная команда позволяет принять или отклонить фрагмент, основываясь на сравнении заданного значения альфа-канала с реальным. Если результат сравнения положительный, то поступающий фраг- мент рисуется в буфере кадра (в зависимости от условий тестов трафарета и глубины). В случае отрица- тельного результата – вывод фрагмента не осуществляется. В данном примере выводится фрагмент объекта в буфер кадра, если его альфа-значение больше (0.4): glEnable(GL_ALPHA_TEST); glAlphaFunc(GL_GREATER, 0.4f); Используя команду glAlphaFunc() мы работаем с полностью прозрачным или полностью непро- зрачным смешиванием, но при этом не возникает реального смешивания. Для определения метода ре- ального смешивания выводимых фрагментов с изображением существующим в буфере кадра использу- ется команда void glBlendFunc(GLenum srcfactor,GLenum dstfactor) Параметр srcfactor определяет метод обработки RGBA значений, поступающих от источника на смешивание (выводимый фрагмент), а dstfactor определяет метод обработки RGBA значений, находя- щихся в буфере кадра с которыми будет осуществляться смешивание. Всего существует одиннадцать методов обработки RGBA значений. Девять из них предназначены для источника (srcfactor) и восемь для приемника (dstfactor). Параметр Метод GL_ZERO (0, 0, 0 ,0) GL_ONE (1, 1, 1 ,1) GL_SRC_COLOR (R S / k R , G S / k G , B S / k B , A S / k A ) Продолжение табл. Параметр Метод GL_ONE_MINUS_SRC_CO LOR (1, 1, 1, 1) – (R S / k R , G S / k G , B S / k B , A S / k A ) GL_DST_COLOR (R D / k R , G D / k G , B D / k B , A D / k A ) GL_ONE_MINUS_DST_CO LOR (1, 1, 1, 1) – (R D / k R , G D / k G , B D / k B , A D / k A ) GL_SRC_ALPHA (A S / k A , A S / k A , A S / k A , A S / k A ) GL_ONE_MINUS_SRC_AL PHA (1, 1, 1, 1) – (A S / k A , A S / k A , A S / k A , A S / k A ) GL_DST_ALPHA (A D / k A , A D / k A , A D / k A , A D / k A ) GL_ONE_MINUS_DST_AL PHA (1, 1, 1, 1) – (A D / k A , A D / k A , A D / k A , A D / k A ) 54 Параметр Метод GL_SRC_ALPHA_SATURA TE (i, i, i, 1), где i = min (A S , k A – A D / k A ) В таблице приняты следующие условные обозначения: R S , G S , B S , A S определяют составляющие цве- та источника; R D , G D , B D , A D определяют составляющие цвета приемника. Значение цвета изменяется в диапазоне [0, k C = 2 mC – 1], где C означает составляющие цвета R, G, B и A, а m – количество битовых плоскостей видео памяти, отведенных под R, G, B и A соответственно. Для определения итогового зна- чения RGBA после смешивания используются следующие уравнения: R(d) = min(k R , R S ⋅ s R + R D ⋅ d R ); G(d) = min(k G , G S ⋅ s G + G D ⋅ d G ); B(d) = min(k B , B S ⋅ s B + B D ⋅ d B ); A(d) = min(k A , A S ⋅ s A + A D ⋅ d A ), где s R , s G , s B , s A , d R , d G , d B , d A – соответствующие компоненты векторов методов из таблицы для источ- ника и для приемника цвета. По умолчанию смешивание заблокировано. Для его включения используется команда glE- nable(GL_BLEND). Для отключения – glDesable(GL_BLEND). Приведенные возможности смешивания цветов позволяют осуществить достаточно сложные замыслы разработчиков. На практике часто используют команду glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA) с примитивами, отсортированными по глубине от наиболее к наименее отдаленным и непрозрачными элементами в глубине. Последнее подсказано логикой визуализации "па- кета" полупрозрачных графических примитивов. Рассмотрим пример вывода трех примитивов: непрозрачного красного треугольника; полупрозрач- ного зеленого квадрата и полупрозрачного синего прямоугольника. Процедура вывода имеет вид: GLvoid DrawPrim() { glClear( GL_COLOR_BUFFER_BIT); // Непрозрачный красный треугольник glColor4f(1.0f, 0.0f,0.0f, 1.0f); glBegin(GL_TRIANGLES); glVertex3f( 0.0f, 1.8f, 1.0f); glVertex3f(-1.4f, -1.5f, 1.0f); glVertex3f( 1.4f, -1.5f, 1.0f); glEnd(); glEnable(GL_BLEND); // Разрешаем смешивание цветов glBlendFunc(GL_SRC_ALPHA,GL_SRC_ALPHA); // Режим смешивания glColor4f(0.0f, 1.0f,0.0f, 0.5f); // Полупрозрачный зеленый квадрат glBegin(GL_QUADS); glVertex3f( 1.0f, 1.0f, 2.0f); glVertex3f(-1.0f, 1.0f, 2.0f); glVertex3f(-1.0f, -1.0f, 2.0f); glVertex3f( 1.0f, -1.0f, 2.0f); glEnd(); // Полупрозрачный синий прямоугольник glColor4f(0.0f, 0.0f,1.0f, 0.5f); glBegin(GL_QUADS); glVertex3f( 2.0f, 0.5f, 0.0f); glVertex3f(-2.0f, 0.5f, 0.0f); glVertex3f(-2.0f, -0.5f, 0.0f); 55 glVertex3f( 2.0f, -0.5f, 0.0f); glEnd(); glDisable(GL_BLEND); // Запрещаем смешивание цветов } В результате работы данной процедуры мы можем видеть красный треугольник через полупрозрач- ный квадрат и прямоугольник. 14 РАБОТА С БУФЕРАМИ За общепринятым понятием буфер кадра в OpenGL скрывается не один, а несколько буферов – цве- та, трафарета, глубины и аккумулятора (накопления). Это разделение позволяет расширить функцио- нальные возможности OpenGL. Рассмотрим механизмы работы некоторых буферов. 14.1 Буфер трафарета Буфер трафарета предоставляет огромные возможности для творчества. С его помощью реализуются самые разнообразные эффекты, начиная от простого вырезания одной фигуры из другой до реализации теней, отражений и прочих непростых функций, требующих от вас уже не только знакомство с библио- текой OpenGL, но и понимания алгоритмов машинной графики. Наложение трафарета разрешает или нет рисование на пиксельном уровне. В качестве трафарета мо- жет выступать любой графический примитив. При этом рисование осуществляется в плоскости тра- фарета. После чего этот буфер используется как маска для вывода графики на экран. Главный меха- низм работы с трафаретом базируется на тестах трафарета, которые сравнивают значения в буфере трафарета с заданным значением. Если тест проходит, то тестируемый пиксель помещается в буфер кадра для визуализации. Сам тест разрешается или блокируется командами glEnable/glDisable с аргументом GL_STENCIL_TEST. Очищается буфер трафарета при помощи функции glClear с параметром GL_STENCIL_BUFFER_BIT. Для проведения трафаретного тестирования предусмотрены команды: glStencilFunc, отвечающая за функцию сравнения, и glStencilOp,определяющая действие на базе проверки трафарета. Рассмотрим эти команды подробнее: void glStencilFunc (GLenum func, int ref, GLuint mask) Данная команда задает правило (параметром func), по которому будет определяться результат срав- нения значений, хранящихся в буфере трафаретов (stencil) с некоторым заданным через параметр ref. Сравнение осуществляется по маске mask. Переменная func может принимать одно из следующих зна- чений: Константа Тест … GL_NEVER НЕ ПРОХОДИТ НИКОГДА GL_LESS Проходит, если (ref & mask) < (stencil & mask) GL_EQUAL Проходит, если (ref & mask) = (stencil & mask) GL_LEQUAL Проходит, если (ref & mask) ≤ (stencil & mask) GL_GREATE R Проходит, если (ref & mask) > (stencil & mask) GL_NOTEQU AL Проходит, если (ref & mask) ≠ (stencil & mask) GL_GEQUAL Проходит, если (ref & mask) ≥(stencil & mask) GL_ALWAYS Проходит всегда 56 Параметр ref задает значение для сравнения и может принимать любое из диапазона [0, 2 n – 1], где n – число битовых плоскостей в буфере трафаретов. Аргумент mask задает маску для значений ref и sten- cil. По умолчанию тест трафарета заблокирован. В этом случае модификация буфера трафарета не мо- жет произойти и это означает положительный результат теста трафарета. Команда glStencilOp предназначена для определения действий над пикселем буфера маски в случае положительного или отрицательного результата теста. void glStencilOp (GLenum fail, GLenum zfail, GLenum zpass) Аргумент fail задает действие в случае отрицательного результата теста, и может принимать сле- дующие значения: Константа Действие GL_KEEP СОХРАНИТЬ ТЕКУЩЕЕ ЗНАЧЕНИЕ В БУФЕРЕ ТРАФАРЕТА GL_ZERO Установить значение буфера трафарета в ноль GL_REPLA CE Заменить значение буфера трафарета на значе- ние переменной ref, заданной командой glStencilOp GL_INCR Увеличить на единицу текущее значение буфе- ра трафарета GL_DECR Уменьшить на единицу текущее значение бу- фера трафарета GL_INVER T Поразрядно инвертировать текущее значение трафарета Параметры zfail и zpass определяют действия для отрицательного и положительного, соответствен- но, завершение теста глубины, которые будут выполнены в случае положительного результата выпол- нения теста трафарета. Для этих параметров допускаются те же символьные константы, что для пара- метра fail. Рассмотрим простой пример использования буфера трафарета. Пусть на фоне градиентно-закрашенного квадрата необходимо вывести зеленый треугольник с вы- резанным окном в виде треугольника меньшего размера, через который можно видеть базовый квадрат. Квадрат расположен чуть дальше, чем остальные объекты. Рассмотрим поэтапно наши действия: 1 Определяем значение буфера трафарета для фона, например – 1. 2 Рисуем градиентно-закрашенного квадрат. 3 Заполняем в буфере трафаретов треугольное "окно" значениями, например – 2. 4 Выводим зеленого треугольника в тех местах, где значения в буфере трафарета не равны 2. Рассмотрим фрагмент кода программы, выполняющий поставленную задачу. Комментарии подроб- но поясняют все выполняемые действия. GLvoid DrawPrim() { // Значение, которым будет заполняться буфер стенсила при его очистке glClearStencil(1); // Определяем, какие биты могут писаться в стенсил буфер glStencilMask(0xFF); // Очищаем все буферы glClear( GL_COLOR_BUFFER_BIT | GL_STENCIL_BUFFER_BIT); glBegin(GL_QUADS); // Рисуем градиентно-закрашенный квадрат glColor3f( 1,0,0);glVertex3f( 2.0f, 2.0f, -0.1f); glColor3f( 0,1,0);glVertex3f(-2.0f, 2.0f, -0.1f); glColor3f( 0,0,1);glVertex3f(-2.0f, -2.0f, -0.1f); 57 glColor3f( 1,0,1);glVertex3f( 2.0f, -2.0f, -0.1f); glEnd(); // Разрешаем проведение теста трафарета для треугольного "окна" glEnable(GL_STENCIL_TEST); // Определяем функцию и значение для сравнения, // треугольник не рисуется glStencilFunc(GL_NEVER, 2, 0); // Заменяем значение буфера трафарета на значение 2 glStencilOp(GL_REPLACE, GL_KEEP, GL_KEEP); glBegin(GL_POLYGON); // Определяем область "окна" glVertex3f( 0.0f, 1.0f, 0.0f); glVertex3f( 1.0f, -1.0f, 0.0f); glVertex3f(-1.0f, -1.0f, 0.0f); glEnd(); // Изменяем параметры теста буфера трафарета; // следующий объект будет рисоваться только в тех местах, // для которых значение в буфере трафарета не равно 2 glStencilFunc(GL_NOTEQUAL, 2, 255); glColor3f(0.0f, 1.0f,0.0f); // Задаем зеленый цвет glBegin(GL_POLYGON); // Рисуем треугольник glVertex3f( 0.0f, 1.6f, 0.0f); glVertex3f(-1.4f, -1.4f, 0.0f); glVertex3f( 1.4f, -1.4f, 0.0f); glEnd(); } При работе с буфером трафарета необходимо аккуратно продумывать последовательность дейст- вий. 14.2 Буферы накопления В OpenGL возможно существование специально отведенных внутренних буферов (передний – GL_FRONT,задний – GL_BACK,левый – GL_LEFT, правый – GL_RIGHT, передний левый – GL_FRONT_LEFT, передний правый – GL_FRONT_RIGHT, задний левый – GL_BACK_LEFT , задний правый – GL_BACK_RIGHT и вспомогательные – GL_AUX0, GL_AUX1, GL_AUX2, GL_AUX3) для временного хранения визуальных изображений. Конкретное наличие того или иного буфера зависит от конфигурирования системы. На практике используют GL_FRONT и GL_BACK. При этом возможен процесс накапливания значений пиксель изображений и процесс считывания этих дан- ных. Выбор буфера для записи изображения, например, для работы команды glDrawPixels(), выполняется командой void glDrawBuffer (GLenum mode) Параметр mode определяет буфер для записи. Этой командой можно выбрать сразу несколько бу- феров и записывать изображение сразу в несколько буферов По умолчанию mode равно GL_FRONT для режима с однократной буферизацией и GL_BACK для режима с двойной буферизацией. Для выбора цветового буфера, который будет служить в качестве источника для чтения пикселей, например, при вызове команд glReadPixels(), glCopyPixels(), glCopyTexImage*(), существует команда void glReadBuffer(GLenum mode) Параметр mode определяет буфер для чтения. Буферы для glReadBuffers() те же самые, что и для команды glDrawBuffers(). По умолчанию mode равно GL_FRONT для режима с однократной буфериза- цией и GL_BACK для режима с двойной буферизацией. 58 14.3 Буфер аккумулятора В OpenGL существует специально отведенный внутренний буфер для временного хранения визу- альных изображений. При этом возможен процесс накапливания значений пиксель изображений. Кроме этого, имеется возможность попиксельных операций над этими изображениями. На практике, подобные буферы используют для получения эффектов нерезкости, сглаживания, "мягких" теней и т.п. Операции с буфером накопления осуществляются командой void glAccum (GLenum op, GLfloat value) Параметр op задает операцию над пикселями и может принимать следующие значения: Константа Операция над пикселями GL_LOAD ПИКСЕЛИ БЕРУТСЯ ИЗ БУФЕРА, ВЫ- БРАННОГО НА ЧТЕНИЕ КОМАНДОЙ GLREADBUFFER(), ИХ ЗНАЧЕНИЯ УМ- НОЖАЮТСЯ НА VALUE И ЗАНОСЯТСЯ В БУФЕР-АККУМУЛЯТОР GL_ ACCUM Аналогично GL_LOAD,только результат не просто записывается в буфер-аккумулятор, а складывается с уже имеющимся в буфере GL_MULT Пиксели в буфере аккумулятора умножаются на значение переменной value GL_ ADD Пиксели в буфере аккумулятора складыва- ются со значением переменной value GL_ RE- TURN Изображение переносится из буфера аккуму- лятора в буфер, выбранный для записи. Пе- ред этим значение каждого пикселя умножа- ется на value Например, чтобы "смазать" изображение, в буфере аккумулятора одна и та же сцена рисуется не- сколько раз. Каждый раз с немного измененными значениями координат расположения камеры. Буфер аккумулятор можно "очищать" определенными значениями составляющих цвета R, G, B и A. Для этого используется команда: void glClearAccum (GLfloat R, GLfloat G, GLfloat B, GLfloat alpha) 14.4 Буфер глубины Работая с трехмерной графикой нам приходится постоянно сталкиваться с глубиной сцены. На ос- новании глубины работает алгоритм, использующий Z-буфер, для удаления невидимых граней. Каждое поступающее значение глубины фрагмента сравнивается с уже имеющимся в буфере глубины и выво- дится на экран (или нет) в зависимости от результатов выполнения этого теста. По умолчанию тест глубины заблокирован. Для его включения/выключения используется команда glEnable/glDisable с аргументом |