Работа с расширениями OpenGL с использованием NVIDIA OpenGL SDK 5.1. (Часть 3)
Автор: Сергей Гайдуков
Во время подготовки примеров для этой части статьи я столкнулся со следующей проблемой. В FAQ по GLUT написано, что файл glut.h уже содержит необходимые определения из windows.h, которые необходимы для нормальной компиляции gl.h. Поэтому файл windows.h можно подключать как до, так и после подключения файла glut.h (а лучше, не подключать вообще). Но оказалось, что если следовать этим указаниям, то на некоторых компиляторах компиляция будет проходить успешно, а на некоторых - вылетать с ошибкой во время компиляции gl.h. Поэтому все примеры предыдущих частей, размещённые на сайте, были обновлены (в них была добавлена директива #include < windows.h>).
PS. Если вы откроете файл glut.h, то увидите почти в самом начале файла следующие строки:
# if 0 # define WIN32_LEAN_AND_MEAN # include <windows.h> # else
Потому, если заменить "# if 0" на "# if 1", то проблема должна исчезнуть. Но вам придется распространять этот файл вместе с вашей программой.
Расширения WGL_ARB_pbuffer и WGL_ARB_pixel_format
Использование класса PBuffer
Восстановление буфера пикселей в случае потери
Создание эффекта зеркального отражения с использованием pbuffer
Заключение
Достоинства
Недостатки
Расширения WGL_ARB_pbuffer и WGL_ARB_pixel_format
При написании программ, использующих многопроходные алгоритмы, часто возникает потребность осуществить промежуточное отображение на виртуальный экран, невидимый пользователю. Информация с виртуального экрана может использоваться для создания динамических текстур, зеркальных поверхностей, кубических текстур и т.д. При использовании виртуального экрана можно избежать мелькания служебной информации на экране, а также значительно повысить быстродействие (виртуальный экран хранится в видеопамяти, которая превосходит обычную оперативную память по быстродействию почти на порядок). DirectX почти с самого начала поддерживал такие виртуальные экраны, называемые внеэкранными поверхностями (off-screen surfaces).
OpenGL не содержит стандартных средств для работы с внеэкранными поверхностями, не считая использования второго кадрового буфера в режиме двойной буферизации (и то, эту функцию выполняет WGL). Но при использовании кадрового буфера мы сталкиваемся с ограничением - размер образа, создаваемого во втором кадровом буфере, не может превышать разрешение экрана (т.е. если пользователь работает в режиме 800*600, не удастся использовать динамические текстуры с разрешением 1024*1024).
В начале 1999 года появилось WGL-расширение WGL_ARB_pbuffer, предназначенное для работы с буфером пикселей (pixel buffer или сокращенно pbuffer). Что такое буфер пикселей? Это область видеопамяти, в которой размещается виртуальный экран. С точки зрения программы, виртуальный экран не отличается от настоящего - он имеет свой контекст OpenGL, поддерживает практически все команды OpenGL и т.д.
Ниже приводится пример простейшей программы, использующей буфер пикселей (см. каталог Ex01 в архиве, доступном на сайте журнала). Программа создает буфер пикселей размером 256*256, рисует в нем вращающийся чайник и копирует его на экран (см. рис. 1). Пример написан "по мотивам" примеров из NVIDIA OpenGL SDK.
Рисунок 1.
Но сначала сделаем небольшое отступление: рассмотрим расширение WGL_ARB_pixel_format. Это расширение содержит команду wglChoosePixelFormatARB, которая используется при создании буфера пикселей. Эта команда является расширенной версией команды wglChoosePixelFormat. Главное ее отличие от оригинала - отсутствие фиксированной структуры PIXELFORMATDESCRIPTOR. Иначе дальнейшее увеличение числа полей структуры привело бы к огромному количеству разных версий однотипных структур, что и произошло в DirectX. Вместо этого используются два массива (второй и третий параметры) iattributes и fattributes. Первый содержит значения целочисленных параметров, второй - вещественных. Для указания количества элементов в этих массивах используется четвертый параметр. Остальные параметры функции остались без изменения. Функция возвращает список поддерживаемых форматов пикселей, удовлетворяющих указанным условиям (пятый параметр). Шестой параметр - адрес переменной, в которой будет занесено количество элементов в массиве.
Массивы параметров имеют структуру, показанную в таблице 1.
Индекс | Значение |
0 | Название поля |
1 | Значение поля |
2 | Название поля |
3 | Значение поля |
... | ... |
Таблица 1.
Четные элементы содержат константу, которая определяет название поля, а нечетные - значения этого поля. Если в название поля равно 0, то оно и последующие поля игнорируются.
Теперь вернемся к нашей программе. После инициализации обоих расширений получаем значения дескриптора текущего окна и его дескриптор контекста OpenGL.
HDC hdc=wglGetCurrentDC(); HGLRC hglrc=wglGetCurrentContext( );
Затем создаем и заполняем массивы параметров iattributes и fattributes.
const MAX_ATTRIBS=32; //-------------------------- int iattributes[2*MAX_ATTRIBS]; // Массивы атрибутов float fattributes[2*MAX_ATTRIBS]; int niattribs=0; // Текуший целый атрибут int nfattribs=0; // Текуший вещественный атрибут // Очистка массива атрибутов for (int i=0; i<2*MAX_ATTRIBS; i++) { iattributes[i]=0; fattributes[i]=0; } // Требуется формат пикселей, совместимый с PBuffer iattributes[2*niattribs]=WGL_DRAW_TO_PBUFFER_ARB; iattributes[2*niattribs+1]=true; niattribs++; // 24-битный буфер глубины iattributes[2*niattribs]=WGL_DEPTH_BITS_ARB; iattributes[2*niattribs+1]=true; niattribs++; // 32-битный буфер цвета iattributes[2*niattribs]=WGL_RED_BITS_ARB; iattributes[2*niattribs+1]=true; niattribs++; iattributes[2*niattribs]=WGL_GREEN_BITS_ARB; iattributes[2*niattribs+1]=true; niattribs++; iattributes[2*niattribs]=WGL_BLUE_BITS_ARB; iattributes[2*niattribs+1]=true; niattribs++; iattributes[2*niattribs]=WGL_ALPHA_BITS_ARB; iattributes[2*niattribs+1]=true; niattribs++;
Обратите внимание, что при заполнении массива используется переменная niattribs, которая содержит номер текущего поля. Этот прием позволяет избежать исправления индексов при вставке/удалении параметров. Теперь получим список формата пикселей, которые можно использовать в буфере пикселей: