3 С. А. Васильев opengl компьютерная графика
Скачать 491.09 Kb.
|
glCallList (GLuint list) Параметр list задает целочисленное имя списка изображений. Рассмотрим пример подготовки и вызова списка изображений. … // Открываем список изображений (без выполнения) под номером 2 glNewList(2,GL_COMPILE); glColor3f(1.0f, 0.0f,0.0f); // Задаем цвет создаваемого примитива glBegin(GL_POLYGON); // Задаем сам примитив glVertex3f( 1.0f, 1.0f, 0.0f); glVertex3f(–1.0f, 1.0f, 0.0f); glVertex3f(–1.0f, –1.0f, 0.0f); glVertex3f( 1.0f, –1.0f, 0.0f); glEnd(); glEndList(); // Закрываем список изображений под номером 2 … glCallList(2); … В список можно включать вызовы уже готовых списков изображений. Рассмотрим список из двух вызовов готовых списков 1 и 2: … // Открываем список изображений (без выполнения) под номером 1 glNewList(1,GL_COMPILE); glColor3f(0.0f, 1.0f,0.0f); glBegin(GL_TRIANGLES); glVertex3f( 1.0f, 2.0f, 0.0f); glVertex3f(–1.0f, 2.0f, 0.0f); glVertex3f(–1.0f, –2.0f, 0.0f); glEnd(); glEndList(); // Открываем список изображений (без выполнения) под номером 2 glNewList(2,GL_COMPILE); glColor3f(1.0f, 0.0f,0.0f); glBegin(GL_TRIANGLES); glVertex3f( 1.0f, 1.0f, 0.0f); glVertex3f(–1.0f, –1.0f, 0.0f); glVertex3f(1.0f, –1.0f, 0.0f); glEnd(); glEndList(); // Открываем список изображений (без выполнения) под номером 3 glNewList(3,GL_COMPILE); glCallList(1); glCallList(2); 25 glEndList(); … // Вызов списка 3 glCallList(3); … Для выполнения сразу нескольких готовых списков используется команда: void glCallList (GLsizei n, GLenum type, Const GLvoid *lists) где n – количество исполняемых списков, lists – указатель на массив, содержащий список имен спи- сков изображений, которые необходимо исполнить, type – тип значений в списке имен lists и может принимать следующие символьные константы: Константа Тип значений в списке имен изобра- жений GL_BYTE ПАРАМЕТР LISTS ЯВЛЯЕТСЯ УКАЗАТЕЛЕМ НА МАССИВ С БАЙТОВЫМИ ЭЛЕМЕНТАМИ, ПРИНИМАЮЩИМИ ЗНАЧЕНИЯ В ДИАПАЗОНЕ [−128, 127] GL_UNSIGNED_BY TE Параметр lists является указателем на массив с положительными байтовы- ми элементами, принимающими зна- чения в диапазоне [0, 255] GL_SHORT Параметр lists является указателем на массив с двухбайтовыми элементами, принимающими значения в диапазо- не [−32768, 32767] GL_UNSIGNED_SH ORT Параметр lists является указателем на массив с положительными двухбай- товыми элементами, принимающими значения в диапазоне [0, 65535] GL_INT Параметр lists является указателем на массив с четырехбайтовыми целыми элементами и т.д. (см. MSDN) Перед вызовом команды glCallLists можно задать постоянное смещение к каждому имени списка изображения из массива lists. Это выполняется командой void glListBase (GLuint base) где base – целочисленное смещение. По умолчанию это смещение равно нлю. Как уже было показано в примере, команды glCallList и glCallLists могут быть вложены в другие списки изображений. Уровней вложения не может быть больше 64. При работе со списками, особенно при формировании шрифтов, приходится следить за номерами создаваемых списков, что не всегда удобно. Эту проблему легко разрешает функция glGenList, генери- рующая непрерывный набор пустых дисплейных списков. Рассмотрим формат записи этой команды. GLuint glGenList (GLsizei range) Параметр range определяет количество пустых дисплейных списков, которые необходимо сгенери- ровать. Функция glGenList возвращает целое число n, которое является именем первого дисплейного списка. Если range больше 1, то также будут созданы пустые дисплейные списки с именами n+1, n+2, … , n+range−1. При нулевом значении range функция glGenList вернет значение 0 и никакой дисплей- ный список не создастся. В ходе выполнения программы можно удалять непрерывную группу имен списков изображений. Допустим, имеется группа имен, например: 1, 3, 4, 5, 6, 8, 9, 10. Мы можем удалить из этой группы лю- бую непрерывную последовательность имен списков, например, 4, 5 и 6. Для этого необходимо вос- пользоваться специальной командой 26 void glDeleteLists (GLuint list, GLsizei range) где list – целое число, являющееся именем первого удаляемого списка изображений, range – коли- чество удаляемых списков. Для приведенного выше примера, оформление команды glDeleteLists выглядит следующим обра- зом: glDeleteLists(4,3). 9 ВЫВОД ТЕКСТА Текст в OpenGL выводится на экран посимвольно и каждый символ представляется как обычный графический образ. Для этого, предварительно, каждый символ, выбранного шрифта, готовится в виде BitMap (битового массива) в своем индивидуальном дисплейном списке. Так как дисплейный список имеет числовое имя, то зная код выводимого символа и соответствующее базовое смещение по отноше- нию названий (номеров) дисплейных списком мы можем активизировать соответствующий список изо- бражения. Рассмотрим эту концептуальную схему вывода текста на экран подробно. Графическая библиотека имеет готовую команду, строящую набор дисплейных списков для симво- лов заданного шрифта типа TrueType – команду BOOL wglUseFontBitmaps (HDC hdc,DWORD first, DWORD count,DWORD listBase) Параметр hdc – ссылка на контекст устройства, шрифт которого будет использоваться, параметр first – первый код символа, count- количество символов и listBase – стартовый дисплейный список. В итоге после отработки этой команды будут сформированы count битовых образов символов шрифта устройства hdc , начиная с кода first. И каждый битовый образ будет размещен в своем дисплейном спи- ске, начиная с номера listBase. Для указания конкретного места вывода на экране используется команда glRasterPos2i(). Цвет будущего текста настраивается командой glColor*(). И так, пример вывода текста – "Привет OpenGL !!!" : … // Выбираем текущий шрифт системы SelectObject (hDC, GetStockObject (SYSTEM_FONT)); // Форм. 255 дисплейных списков изображений символов, начиная с // кода 1 и размещая с базового имени дисплейного списка – 1 wglUseFontBitmaps (hDC, 1, 255, 1); glRasterPos2i(20,10); // С позиции экрана (20,10) glColor3f(1.0,1.0,0.0);// Желтым цветом // Выводим 17 дисплейных списков (17 символов текста) glCallLists (17, GL_UNSIGNED_BYTE, "Привет OpenGL !!!"); … Рассмотрим еще один пример, в котором мы попробуем выбирать любой шрифт из системы Win- dows и изменять размер выводимых символов текста. Для этого нам придется использовать функцию GDI CreateFont(), которая создает логический шрифт с соответствующими атрибутами. Рассмотрим на- значение ее параметров: HFONT CreateFont ( int nHeight, // Высота фонта (ячейки символа) int nWidth, // Средняя ширина символа int nEscapement, // Угол отношения int nOrientation, // Угол наклона к оси х int fnWeight, // Ширина шрифта DWORD fdwItalic, // Курсив DWORD fdwUnderline, // Подчеркивание DWORD fdwStrikeOut, // Перечеркивание DWORD fdwCharSet, // Идентификатор набора символов DWORD fdwOutputPrecision, // Точность вывода DWORD fdwClipPrecision, // Точность отсечения DWORD fdwQuality, // Качество вывода DWORD fdwPitchAndFamily, // Настройка шага и семейства LPCTSTR lpszFace); // Название шрифта (!) 27 Если значение параметра nHeight установить со знаком минус, то мы сообщаем Windows, что надо найти нам шрифт, основанный на высоте символов. Если мы используем положительное число, мы вы- бираем шрифт, основанный на высоте ячейки. Среднюю ширину символа(nWidth)обычно задают по умолчанию, для этого достаточно указать в этом поле значение 0. Параметры nEscapement и nOrientationзадают нулями. Если кому требуется изменять угол наклона символов – экспериментируйте, используя документацию MSDN. Ширина шрифта (fnWeight)может принимать значения из диапазона 0-1000. Но на практике поль- зуются только некоторыми значениями, которые и ведены символьные константы: FW_DONTCARE – 0, FW_NORMAL – 400, FW_BOLD – 700, и FW_BLACK – 900. Чем выше значение , тем более жир- ный шрифт. Значение TRUE параметра fdwItalicразрешает делать курсив. Значение TRUE параметра fdwUnderline разрешаетделать подчеркивание. Значение TRUE параметра fdwStrikeOutразрешает делать перечеркивание. Тип набора символов определяет параметрfdwCharSet, напри- мер, RUSSIAN_CHARSET, ANSI_CHARSET, DEFAULT_CHARSET, OEM_CHARSET, SYMBOL_CHARSET и т.д. Параметр fdwOutputPrecision сообщает Windows какой из наборов символов использовать, если их доступно больше чем один. Если – OUT_TT_PRECIS,то система должна выбрать Truetype версию шрифта. Truetype шрифты всегда смотрят лучше, особенно когда масштабируются символы. При ис- пользовании константы OUT_TT_ONLY_PRECIS система должна использовать только Truetype шрифт. Точность отсечения (fdwClipPrecision) обычно ставится по умолчанию – CLIP_DEFAULT_PRECIS. Качество вывода (fdwQuality) управляет алгоритмом реалистичности при формировании символов и может принимать значения: PROOF_QUALITY, DRAFT_QUALITY, NONANTIALIASED_QUALITY, DEFAULT_QUALITY или ANTIALIASED_QUALITY. Из контекста названий констант можно опре- делиться с выбором. В нашей программе будем использовать значение ANTIALIASED_QUALITY. Предпоследний параметр (fdwPitchAndFamily) отвечает за шаг и семейство шрифтов. Возможные значения: FF_SWISS, FF_DECORATIVE, FF_DONTCARE, FF_MODERN, FF_ROMAN и FF_SCRIPT. Для нашего примера можно воспользоваться комбинацией: FF_DONTCARE|DEFAULT_PITCH. Последний параметр (lpszFace) определяет используемый шрифт. В данном случае – " Times New Roman Cyr ". … HFONT hFont; // Windows шрифт GLuint base; //Базовый номер дисплейного списка … void glPrintText(unsigned int base, char *string) { if((base == 0 || string == NULL)) return; glPushAttrib(GL_LIST_BIT); glListBase(base – 32); glCallLists(strlen(string),GL_UNSIGNED_BYTE, string); glPopAttrib(); } GLvoid CFont(char *fontName, int Size) { base = glGenLists(224); // Выделяем место под 224 символа // Создаем шрифт hFont = CreateFont(Size, 0, 0, 0, FW_BOLD, FALSE, FALSE, FALSE, ANSI_CHARSET, OUT_TT_PRECIS, 28 CLIP_DEFAULT_PRECIS, ANTIALIASED_QUALITY, FF_DONTCARE | DEFAULT_PITCH, fontName); SelectObject(hDC, hFont); // Выбираем созданный шрифт // Форм. 224 дисплейных списков изображений символов, начиная с // кода 32 и размещая с базового имени дисплейного списка – base wglUseFontBitmaps(hDC, 32, 224, base); DeleteObject(hFont); // Удаляем шрифт } // Инициализация GL int InitGL(GLvoid) { glShadeModel(GL_SMOOTH); glClearColor(0.0f, 0.0f, 0.0f, 0.5f); glClearDepth(1.0f); glEnable(GL_DEPTH_TEST); glDepthFunc(GL_LEQUAL); glHint(GL_PERSPECTIVE_CORRECTION_HINT, GL_NICEST); // *********Формируем шрифт ********* CFont("Courier", 36); return TRUE; } GLvoid Draw() { unsigned int ListBase; glClear(GL_COLOR_BUFFER_BIT|GL_DEPTH_BUFFER_BIT); glLoadIdentity(); glRasterPos2i(20,10); glColor3f(1.0,1.0,0.0); PrintText(base, "Привет OpenGL!!!"); } Для корректного завершения работы графического приложения ре- комендуется удалять из памяти дисплейные списки отведенные под сим- волы: GLvoid KillFont(GLvoid) // Удаление дисплейных списков { glDeleteLists(base, 224); // Удаление 224 символа } 10 ПРЕОБРАЗОВАНИЕ КООРДИНАТ Любое графическое приложение в конечном итоге преобразует координаты вершин графического объекта в оконные координаты графического устройства. В OpenGL это преобразование проходит за несколько основных этапов: 1 Модельно-видовое преобразование. 2 Преобразование проекции и нормализация. 3 Преобразование к области вывода. 10.1 Матричные операции В OpenGL принята правосторонняя система координат, т.е. ось z направлена на наблюдателя. Для перехода в левостороннюю систему координат необходимы специальные матрицы преобразований. Все преобразования координат в OpenGL происходят на уровне матричных операций. Все матрицы имеют размер 4 ×4 и участвуют в преобразовании координат по следующему правилу: 29 1 Z Y X = 15 11 7 3 14 10 6 2 13 9 5 1 12 8 4 0 m m m m m m m m m m m m m m m m 1 z y x В OPENGL ВСЕ ОПЕРАЦИИ ПРЕОБРАЗОВАНИЙ ОСУЩЕСТВЛЯЮТСЯ С ТЕКУЩЕЙ МАТРИЦЕЙ. ПРИ ЭТОМ, РАЗЛИЧАЮТ ТРИ ВИДА МАТРИЦ: МОДЕЛЬНО-ВИДОВАЯ, МАТ- РИЦА ПРОЕКЦИИ И МАТРИЦА ТЕКСТУРЫ. МОДЕЛЬНО-ВИДОВАЯ МАТРИЦА УЧАСТВУЕТ В ПРЕОБРАЗОВАНИЯХ КООРДИНАТ ОБЪЕКТОВ В МИРОВОЙ СИСТЕМЕ КООРДИНАТ, А ИМЕННО, ПЕРЕМЕЩЕНИИ, МАСШТАБИРОВАНИИ И ПОВОРОТАХ. СПОСОБ ПРОЕКЦИИ ГРАФИЧЕСКИХ ОБЪЕКТОВ НА ПЛОСКОСТЬ ЭКРАНА ОПРЕДЕЛЯЕТ МАТРИЦА ПРОЕЦИ- РОВАНИЯ. СВЯЗЬ КООРДИНАТ ТОЧЕК ИЗОБРАЖЕНИЯ ТЕКСТУРЫ С КООРДИНАТАМИ ТОЧЕК ПОВЕРХНОСТИ ГРАФИЧЕСКОГО ОБЪЕКТА ОПРЕДЕЛЯЕТ МАТРИЦА ТЕКСТУР. ОПРЕДЕЛЕНИЕ ТЕКУЩЕЙ МАТРИЦЫ ПРЕОБРАЗОВАНИЙ ОСУЩЕСТВЛЯЕТСЯ КО- МАНДОЙ: VOID GLMATRIXMODE (GLENUM MODE), ГДЕ MODE ПРИНИМАЕТ ЗНАЧЕНИЕ КОНСТАНТ СОГЛАСНО ТАБЛИЦЫ. Mode Вид матрицы GL_MODELVI EW Модельно- видовая GL_PROJECTI ON Проекции GL_TEXTURE Текстуры Внимание!Умножение координат объекта на текущую матрицу происходит в момент вызова соот- ветствующей команды OpenGL, определяющей координату. Для заполнения текущей матрицы преобразований соответствующими значениями предназначена специальная команда: void glLoadMatrix[f d] (GLtype *m) Например, для формирования единичной матрицы можно воспользоваться следующим кодом GLfloat mId[4][4] = { 1.0f, 0.f, 0.0f, 0.0f, 0.0f, 1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f}; glLoadMatrixf(&mId[0][0]); Внимание! В массив матрица записывается по столбцам. Кстати, такой вид записи матрицы в программе хорошо согласуется с общепринятым подходом в компьютерной графике, когда точка в пространстве задается вектором строкой. В этом случае при лю- бом преобразовании вектор-строка умножается на матрицу преобразования, что требует изменения рас- становки элементов в матрице (строки меняются местами со столбцами). Например, для задачи одновре- менного увеличения масштаба геометрического объекта по оси y в 2 раза и смещении его точек по оси x на 3 единицы, по оси z на 4 единицы достаточно сформировать массив в виде GLfloat mST[4][4] = { 1.0f, 0.f, 0.0f, 0.0f, 0.0f, 2.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f, 0.0f, 3.0f, 0.0f, 4.0f, 1.0f}; и передать его в текущую матрицу преобразования glLoadMatrixf(&mST[0][0]); Внимание!Примите этот дополнительный пример, как рекомендацию к использованию на практи- ке для написания высокоэффективного кода графической программы. Единичная матрица часто используется в OpenGL и для облегчения программирования предусмот- рена команда glLoadIdenty(), которая устанавливает единичную матрицу текущего преобразования. Иногда приходится умножать текущую матрицу на другую матрицу. Для этой цели используется команда void glMultMatrix[f d] (GLtype *m), где параметр m задет матрицу размером 4 ×4, на которую будет умножаться текущая матрица. 30 СОСТОЯНИЕ МАТРИЦ ПРЕОБРАЗОВАНИЯ МОЖНО СОХРАНЯТЬ И ВЫЗЫВАТЬ ПО МЕРЕ НАДОБНОСТИ. ДЛЯ ЭТО СУЩЕСТВУЮТ КОМАНДЫ: void glPushMatrix (void) void glPopMatrix (void) Эти команды сохраняют и читают текущую матрицу преобразования из стека. Для каждого вида матриц преобразований имеется свой стек. 10.2 Модельно-видовые преобразования ОПРЕДЕЛЕНИЕ МАТРИЦЫ ВИДОВОГО ПРЕОБРАЗОВАНИЯ УДОБНЕЕ ОСУЩЕСТВ- ЛЯТЬ СПЕЦИАЛЬНЫМИ КОМАНДАМИ OPENGL: ПЕРЕНОС, МАСШТАБИРОВАНИЕ И ВРАЩЕНИЕ. ПРЕОБРАЗОВАНИЯ ОСУЩЕСТВЛЯЮТСЯ В МИРОВОЙ СИСТЕМЕ КООРДИ- НАТ. РАССМОТРИМ ИХ ПОДРОБНЕЕ. void glTranslate[f d] (GLtype Dx, GLtype Dy, GLtype Dz) ЭТА КОМАНДА ГОТОВИТ МАТРИЦУ ПРЕОБРАЗОВАНИЯ ДЛЯ ПЕРЕНОСА ГРАФИЧЕ- СКОГО ОБЪЕКТА НА РАССТОЯНИЕ DX ПО ОСИ Х, НА РАССТОЯНИЕ DY ПО ОСИ У И НА РАССТОЯНИЕ DZ ПО ОСИ Z. void glScale[f d] (GLtype Sx, GLtype Sy, GLtype Sz) ПРИ ПОМОЩИ ЭТОЙ КОМАНДЫ ОСУЩЕСТВЛЯЕТСЯ ФОРМИРОВАНИЕ ВИДОВОЙ МАТРИЦЫ ДЛЯ МАСШТАБИРОВАНИЯ ОБЪЕКТА ВДОЛЬ ОСЕЙ МИРОВЫХ КООРДИНАТ. В SX РАЗ ВДОЛЬ ОСИ Х, В SY РАЗ ВДОЛЬ ОСИ У И В SZ РАЗ ВДОЛЬ ОСИ Z. VOID GLROTATE[F D](GLTYPE ANGLE, GLTYPE X, GLTYPE Y, GLTYPE Z) Эта команда рассчитывает видовую матрицу для выполнения вращения объекта против часовой стрелки на угол angle относительно радиус-вектора, заданного параметрами x, y и z. |