КГ_10глава (1024131), страница 2
Текст из файла (страница 2)
Результат работы программы показан на рис. 10.2.
Рис. 10.2. Изображение объектов и направление осей мировых координат
в программе StudexSl
Для иллюстрации работы Z-буфера (в OpenGL он называется буфером глубины — depth buffer) сначала рисуем грани пирамиды, а потом шахматное поле, которое расположено ниже. Грани пирамиды также рисуем все пять (хотя здесь видны только две), причем так, чтобы при отсутствии Z-буфера получался бы заведомо неправильный результат. Проверьте это, попробуйте отключить Z-буфер. Для этого достаточно удалить из текста оператор glEnable (GL_depth_test) . Что получится?
Программа StudexSl может служить простейшим примером построения изображения трехмерных объектов в заданной проекции. Изображение на рис. 10.2 вполне правдоподобно передает форму объектов. Однако в данной программе отсутствуют многие важные элементы построения реалистичных изображений. В первую очередь это относится к освещению. Так, например, грани пирамиды здесь закрашены разными цветами — передняя грань более светлым цветом, а боковая грань более темным. Эти цвета мы задали вызовом функций gicoior3f перед выводом соответствующих граней. Значения цветов выбраны произвольно. Здесь никак не были использованы возможности, которые предоставляет OpenGL для моделирования освещения.
10.4. Моделирование освещения
Для того чтобы поручить OpenGL изображать объекты в соответствии с некоторой моделью освещения, необходимо вызвать функцию glEnabie (gl_lighting) . Может быть использовано несколько источников света. Максимальное количество источников света зависит от версии реализации OpenGL. Источники света имеют номера от 0 до некоторого максимального значения. Включение i-го источника выполняется функцией
glEnabie (GL_LIGHTi), а выключение — функцией glDisable (GL_LIGHTi) . Так,
например, чтобы заставить светить нулевой источник, необходимо вызвать
функцию glEnabie (GL_LIGHT0).
Каждый источник света можно (и нужно) настроить индивидуально. Делается ЭТО ВЫЗОВОМ функций glLightf, glLighti ИЛИ glLightfv, glLightiv (век-
торные разновидности). Функции различаются типами и количеством аргументов. Рассмотрим некоторые примеры настройки.
Определить положение источника света gl_lighto можно следующим образом:
В массив lightpos [ ] необходимо записать однородные мировые координаты источника света в виде (x, у, z, w). При вызове glLightfv эти координаты будут преобразованы в соответствии с ракурсом показа, определяемом видовой матрицей. При w=1 будет обеспечено правильное соответствие закрашивания объектов расположению источника.
Направление действия источника света задается так:
В массиве iightdirection[] должны быть указаны координаты радиус-вектора в относительных единицах (х, у, z), направленного от источника света.
Угол распространения света от точечного направленного источника можно задать так:
где angle — угол в градусах в диапазоне от 0 до 90°. При этом свет в пространстве ограничивается конусом. Также допустимо значение angle = 180, которое соответствует равномерному распространению света во все стороны.
Этим далеко не исчерпываются возможности функций glLightf, glLighti, glLightfv и glLightiv для установки параметров источников света. Для наиболее полного ознакомления обратитесь к документации по Win32 SDK [61].
Необходимо учитывать, что многие параметры, в том числе и для источников света, в OpenGL установлены по умолчанию. Так, например, для источника gllighto установлен по умолчанию равномерный рассеянный свет (angle = 180). Кроме того, установки по умолчанию неодинаковы для различных ИСТОЧНИКОВ GLLIGHTi.
Кроме параметров настройки источника света еще одним важнейшим аспектом моделирования освещения является задание нормалей к поверхностям. При выводе каждого объекта OpenGL определяет взаимную ориентацию вектора направления источника света и текущего вектора нормали. По умолчанию установлено направление вектора нормали как (0, 0, 1), то есть вектор направлен вдоль оси z мировых координат. Направление текущего вектора нормали не изменяется до тех пор, пока не будет вызвана функция giNomai, например:
где пх, пу и nz — это координаты радиус-вектора нормали. Для данной функции они должны быть в диапазоне (-1.0, 1.0). Существуют и другие разновидности для glNormai, отличающиеся типами числовых значений координат.
Таким образом, при выводе каждой отдельной полигональной грани необходимо вначале устанавливать направление текущего вектора нормали. Для корректного расчета взаимного расположения векторов нормалей и направлений источников света при различных ракурсах показа необходимо установить режим нормализации векторов
Для правильного вывода освещаемых объектов нужно также определять свойства материала поверхности. Если предполагается изображать освещенными цветные объекты, то следует установить
Суммируем полученные сведения в программе studex52.
Результат работы программы studex52 показан на рис. 10.3.
Рис. 10.3. Моделирование освещения (свет справа сверху)
10.5. Стандартные объемные формы
В OpenGL предусмотрены некоторые стандартные, наиболее часто используемые трехмерные объекты. Набор таких форм представлен в библиотеке GLU (Utility Library), которая реализована в виде модуля giu32.dll и является неотъемлемой частью OpenGL. Она включает в себя несколько функций управления проекциями (одну из которых — gluPerspective мы уже использовали), функции работы с полигонами, кривыми и поверхностями типа В-сплайнов и другие функции.
Рассмотрим функции gluCylinder, gluSphere, gluDisk И gluPartialDisk (рис. 10.4—10.7).
Перечисленные объекты названы "quadric objects". Параметры slices и stacks определяют количество плоских граней, используемых для аппроксимации поверхности. Для того чтобы нарисовать подобный объект, необхо-
Рис. 10.4. Цилиндр
Рис. 10.5. Шар
Рис. 10.6. Диск
Рис. 10.7. Часть диска
димо вызвать функцию giuNewQuadric, а после рисования освободить память ВЫЗОВОМ функции gluDeleteQuadric.
По умолчанию каждый объект рисуется со сплошным заполнением. Изменить СТИЛЬ показа МОЖНО ВЫЗОВОМ функции gluQuadricDrawStyle. МОЖНО за-
дать такие стили показа — в виде точек, расположенных в вершинах многоугольника, каркасное изображение, сплошное заполнение и силуэт (разновидность каркасного). Например, вызов
дает каркасное изображение.
Объекты данного типа располагаются в пространстве в центре координат (0, 0, 0) с учетом матрицы glmodelview. Поэтому, чтобы нарисовать изображение объекта в требуемом месте, нужно соответствующим образом изменить эту матрицу, например, С ПОМОЩЬЮ функций glTranslate И glRotate.
Нижеприведенный пример иллюстрирует показ объектов типа "quadric
objects".
Файл studex53. срр:
Т); , 40);
tion);
Изображение в окне программы studex53 приведено на рис. 10.8.
Рис. 10.8. Цилиндры, шар и диск
При подготовке этого рисунка к печати был изменен цвет фона на белый. Однако на экране монитора синий цвет выглядит значительно лучше (в тексте программы: giciearColor(0, 0, 0.5, l.0f)).
10.6. Текстура
В OpenGL имеется достаточно полный набор средств для построения тексту-рированных изображений.
В качестве текстуры можно использовать растровое изображение. Оно может быть одномерным или двумерным. Для наложения текстуры необходимо выполнить несколько операций.
1. Сначала открыть в памяти массив, в котором будет храниться растр текстуры. Число байт массива рассчитывается исходя из количества бит на пиксел текстуры. Размеры растра текстуры обязательно должны быть равны степени двойки (плюс несколько пикселов на бордюр). Это требование создает некоторые неудобства для программиста, особенно в случае, когда текстура может быть прочитана из произвольного растрового файла. Впрочем, это не является неразрешимой проблемой — любой растр текстуры можно либо обрезать, либо растянуть (сжать) до требуемых размеров.
2. Заполнить массив текстуры. Здесь следует учитывать то, в каком формате представлен растр текстуры. Если пикселы текстуры представляются в формате RGB (24 бита на пиксел), то байты в массиве должны располагаться в виде троек (R, G, В). Заметим, что в массивах DIB Windows API цветовые компоненты располагаются в обратном порядке, то есть (В, G, R).
3. После того как массив открыт, нужно передать OpenGL адрес массива и другие его параметры. Делается это вызовом функции giTeximage2D для двумерной текстуры и giTeximageiD для одномерной
4. Затем можно задать параметры фильтрации текстуры (вызовом функции glTexParameter) для качественного отображения объектов различных размеров.