Opengl игорь Тарасов Часть i основы OpenGL
Скачать 1.72 Mb.
|
OpenGL Игорь Тарасов Часть I Основы OpenGL Глава 1. Введение. Глава 2. Быстрый старт Глава 3. Рисуем простые объекты Глава 4. Полезные мелочи Глава 5. Работа с картинками Глава 6. Освещение и все, что с ним связано Глава 7. Инициализация или как написать приложение с нуля Глава 8. Примеры интересных программ Приложение A. Где взять OpenGL и другое ПО Библиография Загрузка исходных файлов и поддержка книги Chapter 1 Введение. 1.1 Что это такое и кому это нужно? OpenGL - Open Graphics Languge, открытый графический язык. Термин "открытый" - значит независимый от производителей. Имеется спецификация OpenGL, где все четко задокументировано и описано. Библиотеку OpenGL может производить кто-угодно. Главное, чтобы библиотека удовлетворяла спецификации OpenGL и ряду тестов. Как следствие, в библиотеке нет никаких темных мест, секретов, недокументированных возможностей и т.п. Библиотеку выпускают такие корпорации, как Microsoft, Silicon Graphics, а также просто группы программистов. Одним из таких примеров служит реализация Mesa. Эту библиотеку написали целый ряд программистов, главным автором является Brian Paul. Библиотека Mesa распространяется в исходных текстах на языке Си и собирается почти для любой операционной системы. Стандарт OpenGL развивается с 1992 года. Он разрабатывается фирмой Silicon Graphics. С тех пор библиотека завоевала огромную популярность и была интегрирована со множеством языков и систем разработки приложений. Вы можете писать программу на Си,С++,Pascal,Java и многих других языках. Существуют также объектно-ориентированные библиотеки OpenGL. Библиотека OpenGL представляет из себя интерфейс программирования трехмерной графики. Единицей информации является вершина, из них состоят более сложные объекты. Программист создает вершины, указывает как их соединять(линиями или многоугольниками), устанавливает координаты и параметры камеры и ламп, а библиотека OpenGL берет на себя работу создания изображения на экране. OpenGL идеально подходит для программистов, которым необходимо создать небольшую трехмерную сцену и не задумываться о деталях реализации алгоритмов трехмерной графики. Для профессионалов, занимающихся программированием трехмерной графики, библиотека тоже будет полезной, т.к. она представляет основные механизмы и выполняет определенную автоматизацию. 1.2 О книге Эта книга является самоучителем по популярной библиотеке OpenGL. Изначально задумывалась некая брошюра, что-то типа небольшого самоучителя. Потом проект сильно разросся, и я подумал: "А почему бы не написать книгу?". Я рассчитываю, что вы уже неплохо знакомы с программированием, в частности, с языком Си. Здесь, в основном, будет рассматриваться написание программ в среде Windows. Рассмотрю, конечно же, и особенности использования OpenGL в операционной системе Unix. Я опишу несколько различных типов приложений. Первый тип - это консольное приложение win32 с использованием библиотеки glaux.lib. Второе - обычное оконное приложение(Win32 Application). Третье - это приложение на базе MFC с архитектурой документ/вид. Четвертое - я покажу, как писать Java-апплеты с использованием библиотеки Magician. Magician - это библиотека java-классов с функциями, идентичными OpenGL. И пятое - Unix-приложение. Различия в написании этих приложений проявляются в начальной инициализации, префиксах и суффиксах названий функций. В остальном, на 90% все везде одинаково. Книга состоит из двух частей - "Основы OpenGL" и "OpenGL для профессионалов". Первая часть является скорее учебником, вторая - справочником по малоизвестным функциональным возможностям OpenGL. Я хотел сделать каждую главу книги самодостаточной. Насколько мне это удалось, судить вам. Но я бы рекомендовал читать книгу последовательно. Главное, на что я делал упор, так это на простоту и понятность. Все примеры очень простые, и их размер не превышает нескольких килобайт. Все написано на чистом Си. В основу книги положен реальный опыт работы. И последнее, что надо сказать здесь, я не претендую на полноту и детальную точность изложения материала. Книга ставит задачей научить читателя элементарным вещам, и поэтому здесь все объясняется простым и понятным языком на конкретных примерах с точки зрения практика, а не теоретика.Более точную информацию вы сможете найти в спецификации по OpenGL и на сайте Silicon Graphics http://www.sgi.com/software/opengl. Книга написана при помощи пакета LATEX2e в ОС Linux. 1.3 Об авторе Со мной можно связаться по электронной почте: * FidoNet: 2:5020/370.2 620.20 1103.5 * Inet: itarasov@rtuis.miem.edu.ru Если у вас имеются дополнения или какие-то материалы, которые, по вашему мнению, желательно включить в книгу, то мы с удовольствием обсудим эту тему. Особенно я занят поиском материалов для второй части книги. 1.4 Благодарности Хочется поблагодарить огромную массу людей, без которых эта книга вряд ли бы состоялась. Прежде всего, хочу выразить благодарность тем, кто непосредственно помогал мне при написании книги. Chapter 2 Быстрый старт 2.1 Устанавливаем OpenGL Начнем с самого главного, установим необходимое программное обеспечение. Я предполагаю, что Windows у Вас уже установлен. Во-первых, установите MSVisualC++6.0 и jdk113 или выше. Во-вторых, нам понадобится реализация библиотеки OpenGL. Она входит в поставку Windows95/NT - это билиотеки opengl32.dll & glu32.dll. Вы также можете взять библиотеки OpenGL от Silicon Graphics. Инструкция по установке там прилагается. Вам придется скопировать opengl.dll и glu.dll в windows\system и положить opengl.lib, glu.lib в подкатолог Lib, где установлено MSVisualC++. В-третьих, вам понадобятся четыре моих программы-шаблона, которые представляют собой начальный скелет, который мы потом будем наполнять функциональностью. Где взять OpenGL от Silicon Graphics, Magician, jdk и мои программы-шаблоны, смотри в приложение 'А'. 2.2 Давайте что-нибудь изобразим Самым простым объектом, с помощью которого можно увидеть всю мощь OpenGL, является сфера. Давайте попытаемся ее изобразить. Выполните следующее: Запустите MSVisualC++6.0 Щелкните меню File->New->Win32 Console Application. Выберете каталог и имя проекта, впишите - sphere, щелкните OK. Я все свои проекты держу на диске D в каталоге Projects. Projects ветвится дальше на подкатологи с базами данных, утилитами, графикой и Java-приложениями. В общем, старайтесь присваивать разумные имена и вести разумную структуру каталогов. Это очень серьезная проблема. У меня некоторые ребята не учли моих советов, и через две недели у них в домашних директориях образовался такой беспорядок, что они сами перестали понимать, что и где у них лежит. Выберете An Empty Project, щелкните Finish. Cкопируйте в каталог вашего проекта мой шаблон console.c и переименуйте его в sphere.c Присоедините его к проекту. Project->Add To Project->Files Щелкните Build->Set Active Configuration и установите тип проекта sphere - Win32 Release Далее, щелкайте Project->Settings->Link->Object/library modules и добавьте туда opengl32.lib, glu32.lib и glaux.lib Вставьте в функцию display следующий код: glColor3d(1,0,0); auxSolidSphere(1); Теперь откомпилируйте и запустите Вашу программу. Меню Build->Execute Sphere.exe Исходный файл смотрите здесь. Исполняемый файл здесь. glColor3d устанавливает текущий цвет, которым будут рисоваться фигуры. Тут нужно пояснить, как устанавливается цвет и общюю философию в названии функций OpenGL. Цвет устанавливается четырьмя параметрами: красный, синий, зеленый и прозрачность. Эти параметры вариируются в диапозоне от нуля до единицы. Четвертый параметр нам пока не нужен, поэтому мы вызвали glColor с тремя параметрами. В этом случае, значение четвертого параметра, прозрачности, по умолчанию считается равным единице, т.е. абсолютно непрозрачным, ноль - будет абсолютно прозрачным. Так как в языке Си нет перегрузки функций, то применяется следующий синтаксис вызова функций - FuncionName[n=число параметров][тип параметров]. Доступны следующие типы: b - GLbyte байт s - GLshort короткое целое i - GLint целое f - GLfloat дробное d - GLdouble дробное с двойной точностью ub - GLubyte беззнаковый байт us - GLushortбеззнаковое короткое целое ui - GLuint беззнаковое целое v - массив из n параметров указанного типа В нашем случае - glColor3d - означает, что в функцию передается три параметра типа GLdouble. Также можно было вызвать glColor3i, т.е. три параметра типа GLint. Если тип параметров короткое целое, целое или байт, то компонента цвета приводится к диапазону [0,1]. Или же glColor3dv означает, что в качестве параметров передается массив из трех элементов типа GLdouble. Например: double array[] = {0.5, 0.75, 0.3, 0.7}; ... glColor3dv(array); glColor3ub(200,100,0);// приводится к 200/256, 100/256, 0,256 auxSolidSphere - рисует сферу в начале координат и единичным радиусом. 2.3 Упражнение: "Трехмерные фигуры" Замените функцию auxSolidSphere на функцию, из указанных ниже с соответсвующими параметрами. Значения параметров устанавливайте порядка единицы - 0.5-1.7. Если вы укажете слишком маленький размер, фигуру будет плохо видно; если слишком большой, то она получится урезанной. Это связано с тем, что ее край, как бы вылезет из монитора. auxSolidCube(width) // куб auxSolidBox(width, height, depth) // коробка auxSolidTorus(r,R) // тор auxSolidCylinder(r,height) // цилиндер auxSolidCone(r,height) // конус auxSolidIcosahedron(width) // многогранники auxSolidOctahedron(width) auxSolidTetrahedron(width) auxSolidDodecahedron(width) auxSolidTeapot(width) // рисует чайник С помошью выше указанных функций вы можете рисовать сплошные фигуры. Если вам надо нарисовать проволочную, то вместо Solid пишите Wire. Пример: auxWireCube(1) // рисует проволочный куб. 2.4 Переход к новым координатам Продолжим рисовать трехмерные фигуры. В предыдущем параграфе вы научились рисовать примитивные трехмерные объекты. Но проблема в том, что они рисуются только в начале координат, т.е. в точке (0,0,0). Для того чтобы изобразить сферу в точке ( x0,y0,z0 ), надо переместить начало координат в эту точку, т.е. надо перейти к новым координатам. Эта процедура довольно распространенная при программировании графики и анимации. Часто, бывает очень удобно, сместить координаты в новую точку и повернуть их на требуемый угол, и ваши расчеты резко упростятся. Конктреный пример мы рассмотрим ниже, когда научимся программировать анимацию. А пока вы узнаете, как переходить к новым координатам. Для перехода к новым координатам в OpenGL есть две функции: glTranslated( Dx,Dy,Dz ) glRotated(j,x0,y0,z0 ) Первая функция сдвигает начало системы координат на ( Dx,Dy,Dz ). Вторая - поворачивает на угол j против часовой стрелки вокруг вектора (x0,y0,z0) Теперь, стоит сказать еще о двух очень важных функциях: glPushMatrix() glPopMatrix() Они предназначены для сохранения и восстановления текущих координат. Я не стал здесь приводить пример на то, как неудобно переходить от одной системы координат к другой и помнить все ваши переходы. Гораздо удобнее с помощью glPushMatrix() сохранить текущие координаты, потом сдвигаться, вертеться, как вам угодно, а после, вызывом glPopMatrix вернуться к старым координатам. Итак, настало время поэкспериментировать. Создайте новый проект, повторив пункты из раздела 2.2. Только назовите его sphere2. Вставьте в функцию display следующий код: glPushMatrix(); // сохраняем текущие координаты glTranslated(1.4,0,0); // сдвигаемся по оси Х на 1.4 glColor3d(0,1,0); auxSolidSphere(0.5); // рисуем сферу в (1.4,0,0) в абсолютных координатах glTranslated(1,0,0); // еще раз сдвигаемся glColor3d(0,0,1); auxSolidSphere(0.3); glPopMatrix(); // возвращаемся к старой системе координат glColor3d(1,0,0); auxSolidSphere(0.75); // рисуем сферу в точке (0,0,0) в абсолютных координатах Теперь, откомпилируйте и запустите вашу программу. Меню Build->Execute Sphere.exe Исходный файл смотрите здесь. Исполняемый файл здесь. В общем-то, из комментариев многое понятно. Обращаю ваше внимание только на два последних вызова auxSolidSphere. Перед вызовом glPopMatrix сфера рисуется в точке (2,0,0), а после, в точке (0,0,0). 2.5 Упражнение: "Cписок трехмерных фигур" Используя список функций из предыдущего упражнения, нарисуйте эти фигуры в два столбца. Слева проволочные. Справа сплошные. Примечание: тут хочу заметить, что в версии glaux.lib от фирмы Microsoft имеется следующий баг: цилиндр и конус рисуются всегда либо проволочными, либо сплошными. Если вы первый цилиндр/конус в программе нарисовали проволочным, то далее все цилиндры/конусы будут проволочными. Соответсвенно, если первой была сплошная фигура, то далее все будут сплошные. Поэтому, не стоит паниковать. Это ошибка Microsoft. Могу также вас порадовать, что ниже я расскажу, как обойти эту проблему. Исходный файл смотрите здесь. Исполняемый файл здесь. 2.6 Поворот координат Создайте новый проект с именем Rotate. Переименуйте glaux.c в rotate.c В функцию display вставьте следующий код: glColor3d(1,0,0); auxSolidCone(1, 2); // рисуем конус в центре координат glPushMatrix(); // сохраняем текущие координаты glTranslated(1,0,0); // сдвигаемся в точку (1,0,0) glRotated(75, 1,0,0); // поворачиваем систему координат на 75 градусов glColor3d(0,1,0); auxSolidCone(1, 2); // рисуем конус glPopMatrix(); // возвращаемся к старым координатам Как видите, конус повернулся в абсолютных координатах. Так что, для того, чтобы нарисовать фигуру не в начале координат, надо: сохранить текущие координаты сдвинуть(glTranslated), повернуть(glRotated) нарисовать то, что хотели вернуться к старым координатам Вызовы glPushMatrixglPopMatrix могут быть вложенными, т.е.: glPushMatrix(); ... glPushMatrix(); glPopMatrix(); ... glPopMatrix(); Естественно число вызовов glPopMatrix должно соответствовать числу вызовов glPushMatrix. 2.7 Упражнение: "Снеговик" Используя функцию glRotate, нарисуйте снеговика. Три сферы, шапка - конус, нос - тоже конус, глаза - сфера, рот можно квадратным сделать - glBox. Исходный файл смотрите здесь. Исполняемый файл здесь. Примечание: Имеется еще один баг в glaux.lib от Microsoft. Кажется, последний из известных мне. Функция aux[Solid/Wire]Cylinder прежде, чем нарисовать цилиндр, сдвигает и поворачивает координаты. Так что, если вы уже сместили и повернули координаты, то цилиндр нарисуется совсем не там, где вы рассчитывали. Люди из Microsoft, конечно же, будут уверять, что это особенность, и предложат вам скачать очередной ServicePack.;-) А я ниже расскажу, как более правильно рисовать цилиндры и конусы. Если вам некогда ждать, то далее приведен исправленный код этих функций. Большинство из вас сейчас пропустят его и перейдут к следующему очень интересному разделу - "Анимация". И правильно сделаете. К исправлению ошибок вернетесь, когда немного освоитесь. Но я все же решил привести код по исправлению ошибок Microsoft именно здесь. Можете пересобрать glaux.lib, заменив соответсвующий код в файле shapes.c. Где взять исходники, смотрите в приложение 'A'. По-моему, они есть в MSDN. void auxWireCylinder (GLdouble radius, GLdouble height) { GLUquadricObj *quadObj; GLdouble *sizeArray, *tmp; GLuint displayList; sizeArray = (GLdouble *) malloc (sizeof (GLdouble) * 2); tmp = sizeArray; *tmp++ = radius; *tmp++ = height; displayList = findList (CYLINDERWIRE, sizeArray, 2); if (displayList == 0) { glNewList(makeModelPtr (CYLINDERWIRE, sizeArray, 2), GL_COMPILE_AND_EXECUTE); quadObj = gluNewQuadric (); gluQuadricDrawStyle (quadObj, GLU_LINE); gluCylinder (quadObj, radius, radius, height, 12, 2); glEndList(); } else { glCallList(displayList); free (sizeArray); } } void auxSolidCylinder (GLdouble radius, GLdouble height) { GLUquadricObj *quadObj; GLdouble *sizeArray, *tmp; GLuint displayList; sizeArray = (GLdouble *) malloc (sizeof (GLdouble) * 2); tmp = sizeArray; *tmp++ = radius; *tmp++ = height; displayList = findList (CYLINDERSOLID, sizeArray, 2); if (displayList == 0) { glNewList(makeModelPtr (CYLINDERSOLID, sizeArray, 2), GL_COMPILE_AND_EXECUTE); quadObj = gluNewQuadric (); gluQuadricDrawStyle (quadObj, GLU_FILL); gluQuadricNormals (quadObj, GLU_SMOOTH); gluCylinder (quadObj, radius, radius, height, 12, 2); glEndList(); } else { glCallList(displayList); free (sizeArray); } } void auxSolidCone (GLdouble base, GLdouble height) { GLUquadricObj *quadObj; GLdouble *sizeArray, *tmp; GLuint displayList; sizeArray = (GLdouble *) malloc (sizeof (GLdouble) * 2); tmp = sizeArray; *tmp++ = base; *tmp++ = height; displayList = findList (CONESOLID, sizeArray, 2); if (displayList == 0) { glNewList(makeModelPtr (CONESOLID, sizeArray, 2), GL_COMPILE_AND_EXECUTE); quadObj = gluNewQuadric (); gluQuadricDrawStyle (quadObj, GLU_FILL); gluQuadricNormals (quadObj, GLU_SMOOTH); gluCylinder (quadObj, base, (GLdouble)0.0, height, 15, 10); glEndList(); } else { glCallList(displayList); free (sizeArray); } } |