Добавил:
Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:

722

.pdf
Скачиваний:
5
Добавлен:
15.11.2022
Размер:
450.3 Кб
Скачать

тенсивности и для изображения объекта или сцены выполняется перспективное преобразование, то нормаль следует вычислять до перспективного деления. В противном случае направление нормали будет искажено, а это приведет к тому, что интенсивность задаваемая моделью освещения, будет определена неправильно.

ЗАКРАСКА МЕТОДОМ ГУРО

Если при построении полигональной поверхности для каждой грани используется по одной нормали, то модель освещения создает изображение, состоящее из отдельных многоугольников. Методом Гуро можно получить сглаженное изображение. Для того, чтобы изобразить объект методом построчного сканирования, нужно в соответствии с моделью освещения рассчитать интенсивность каждого пиксела вдоль сканирующей строки. Нормали к поверхности аппроксимируются в вершинах многоугольников так, как описано в предыдущем разделе. Однако сканирующая строка не обязательно проходит через вершины многоугольника. При закраске Гуро сначала определяется интенсивность вершин многоугольника, а затем с помощью билинейной интерполяции вычисляется интенсивность каждого пиксела на сканирующей строке.

Качество изображения намного улучшается, но при внимательном его рассмотрении заметно проявление эффекта полос Маха. Это происходит потому, что такой метод интерполяции обеспечивает лишь непрерывность значений интенсивности вдоль границ многоугольников, но не обеспечивает непрерывности изменения интенсивности.

Закраска Гуро лучше всего выглядит в сочетании с простой моделью с диффузным отражением, описываемой уравнениями освещения

(1) или (2), так как форма бликов при зеркальном отражении сильно зависит от выбора многоугольников, представляющих объект или поверхность.

ЗАКРАСКА ФОНГА

Закраска Фонга требует больших вычислительных затрат, однако она позволяет разрешить многие проблемы метода Гуро. При закраске Гуро вдоль сканирующей строки интерполируется значение интенсивности, а при закраске Фонга - вектор нормали. Затем он используется в модели освещения для вычисления интенсивности пиксела. При этом достигается лучшая локальная аппроксимация кривизны поверхности и, следовательно, получается более реалистичное изображение. В частности, правдоподобнее выглядят зеркальные блики.

При закраске Фонга аппроксимация кривизны поверхности производится сначала в вершинах многоугольников путем аппроксимации нормали в вершине. После этого билинейной интерполяцией вычисляется нормаль в каждом пикселе.

Хотя метод Фонга устраняет большинство недостатков метода Гуро, он тоже основывается на линейной интерполяции. Поэтому в местах разрыва первой производной интенсивности заметен эффект полос Маха, хотя и не такой сильный, как при закраске Гуро. Однако, иногда этот эффект проявляется сильнее у метода Фонга, например для сфер. Кроме того, оба метода могут привести к ошибкам при изображении невыпуклых многоугольников.

Также возникают трудности, когда любой из этих методов применяется при создании последовательности кинокадров. Например, закраска может значительно изменяться от кадра к кадру. Это происходит из-за того, что правило закраски зависит от поворотов, а обработка ведется в пространстве изображения. Поэтому, когда от кадра к кадру меняется ориентация объекта, его закраска (цвет) тоже изменяется, причем достаточно заметно.

ПРОЗРАЧНОСТЬ

В основных моделях освещения и алгоритмах удаления невидимых линий и поверхностей рассматриваются только непрозрачные поверхности и объекты. Однако существуют и прозрачные объекты, пропускающие свет, например, такие, как стакан, ваза, окно автомобиля, вода. При переходе из одной среды в другую, например из воздуха в воду, световой луч преломляется; поэтому торчащая из воды палка кажется согнутой. Преломление рассчитывается по закону Снеллиуса, который утверждает, что падающий и преломляющий лучи лежат в одной плоскости, a углы падения и преломления связаны формулой

N1*sin(a) = N2*sin(p)

где N1, и N2 - показатели преломления двух сред, a - угол падения, p - угол преломления. Ни одно вещество не пропускает весь падающий свет, часть его всегда отражается.

Так же, как и отражение, пропускание может быть зеркальным (направленным) или диффузным. Направленное пропускание двойственно прозрачным веществам, например стеклу. Если смотреть на объект сквозь такое вещество, то, за исключением контурах линий криволинейных поверхностей, искажения происходить не будет. Если свет при пропускании через вещество рассеивается, то мы имеем диффузное пропускание. Такие вещества кажутся полупрозрачными или матовыми. Если смотреть на объект сквозь такое вещество, то он будет выглядеть нечетким или искаженным.

На первый взгляд для получения верного результата достаточно знать истинные угловые соотношения в точках пересечения луча с объектом. Однако это не так, потому что длина пути луча в преобразованном объекте также меняется. Разница в длине пути приводит к тому, что, во-первых, не совпадают точки выхода луча из объекта, так что луч все равно не попадает в правильную точку фона. Во-вторых, меняется количество поглощенного объектом света, поэтому исходящий луч имеет другую интенсивность.

Для того чтобы устранить влияние преломления, можно либо применять алгоритмы, работающие в пространстве объекта, либо пользоваться специальными преобразованиями между пространствами объекта и изображения. Однако проще включить преломление в алгоритмы построения видимых поверхностей методом трассировки лучей, использующие глобальную модель освещения.

В простейших реализациях эффекты прозрачности преломления вообще не рассматриваются. Кроме того, не принимается во внимание, как путь, пройденный лучом в среде, влияет на его интенсивность. Самые ранние разработки в этой области принадлежат Ньюэлу. Простое пропускание света можно встроить в любой алгоритм удаления невидимых поверхностей, кроме алгоритма с Z-буфером. Для того чтобы его учесть, необходимы отдельные буферы прозрачности, интенсивности и весовых коэффициентов, а также нужно отметить прозрачные многоугольники в структуре данных. Для алгоритма, использующего Z-буфер, последовательность действий такова:

Для каждого многоугольника:

если многоугольник прозрачен, то внести его в список прозрачных многоугольников;

если многоугольник непрозрачен и Z > Zбуфер, то записать его в буфер кадра для непрозрачных многоугольников и скорректировать этот буфер.

Для каждого многоугольника из списка прозрачных многоугольников: если Z >= Zбуфер, то прибавить его коэффициент прозрачности к значению, содержащемуся в буфере весовых коэффициентов прозрачности;

41

прибавить его интенсивность к значению, содержащемуся в буфере интенсивности прозрачности, в соответствии с правилом

Iнов = Iстар * Gстар + Ii * Gi

где Iнов - новое значение интенсивности, Iстар - старое значение интенсивности, записанное в буфере интенсивности прозрачности, Ii - интенсивность текущего многоугольника, Gстар - старый коэффициент прозрачности из буфера весовых коэффициентов прозрачности, Gi - коэффициент прозрачности текущего многоугольника. Таким образом, получается взвешенная сумма интенсивностей всех прозрачных многоугольников, находящихся перед ближайшим непрозрачным многоугольником.

Объединим буферы интенсивности для прозрачных и непрозрачных многоугольников.

Эту процедуру удобнее использовать в сочетании с алгоритмом построчного сканирования с Z-буфером, поскольку для полного алгоритма с Z-буфером требуется очень много памяти.

Одной из интересных прикладных задач, связанных с прозрачностью, является визуализация внутреннего вида сложных объектов или пространств.

Для этого всем многоугольникам поверхности приписываются коэффициенты прозрачности, первоначально равные 1, т.е. они считаются непрозрачными. Можно построить изображение такого объекта с удаленными невидимыми гранями. Затем коэффициенты прозрачности некоторых групп граней заменяются на 0, т. е. они делаются невидимыми. При новом построении изображения сцены получается внутренний вид этого объекта или пространства.

Для того чтобы включить преломление в модель освещения. нужно при построении видимых поверхностей учитывать не только падающий, но и отраженный и пропущенный свет. Эффективнее всего это выполняется с помощью глобальной модели освещения в сочетании с алгоритмом трассировки лучей для выделения видимых поверхностей. Обычно рассматриваются только зеркально отраженные и пропущенные лучи, так как диффузное отражение от просвечивающих поверхностей порождает бесконечное количество беспорядочно ориентированных лучей. Поэтому моделируются только прозрачные вещества. для которых формула расчета интенсивности является простым расширением ранее описанных моделей.

ТЕНИ

Если положения наблюдателя и источника света совпадают, то теней не видно, но они появляются, когда наблюдатель перемещается в любую другую точку. Изображение с построенными тенями выглядит гораздо реалистичнее, и, кроме того, тени очень важны для моделирования. Например, особо интересующий нас участок может оказаться невидимым из-за того. что он попадает в тень. В прикладных областях - строительстве, разработке космических аппаратов и др. - тени влияют на расчет падающей солнечной энергии, обогрев и кондиционирование воздуха.

Наблюдения показывают, что тень состоит из двух частей: полутени и полной тени. Полная тень - это центральная, темная, резко очерченная часть, а полутень - окружающая ее более светлая часть. В машинной графике обычно рассматриваются точечные источники, создающие только полную тень. Распределенные источники света конечного размера создают как тень. так и полутень: в полной тени свет вообще отсутствует, а полутень освещается частью распределенного источника. Из-за больших вычислительных затрат, как правило, рассматривается только полная тень, образуемая точечным источником света. Сложность и, следовательно, стоимость вычисле-

ний зависят и от положения источника. Легче всего, когда источник находится в бесконечности, и тени определяются с помощью ортогонального проецирования. Сложнее, если источник расположен на конечном расстоянии, но вне поля зрения; здесь необходима перспективная проекция. Самый трудный случай, когда источник находится в поле зрения. Тогда надо делить пространство на секторы и искать тени отдельно для каждого сектора.

Для того чтобы построить тени, нужно по существу дважды удалить невидимые поверхности: для положения каждого источника и для положения наблюдателя или точки наблюдения, т. е. это двухшаговый процесс.

После добавления теней к структуре данных, как обычно, строится вид сцены из заданной точки наблюдения. Отметим, что для создания разных видов не нужно вычислять тени заново, так как они зависят только от положения источника и не зависят от положения наблюдателя.

Идея совмещения процессов построения теней и удаления невидимых поверхностей была впервые предложена Аппелем. Им разработан как метод трассировки лучей, так и метод построчного сканирования. Включение теней в интервальный алгоритм построчного сканирования осуществляется в два этапа.

На первом этапе для каждого многоугольника сцены и каждого источника определяются самозатененные участки и проекционные тени. Они записываются в виде двоичной матрицы, в которой строки - многоугольники, отбрасывающие тень, а столбцы - затеняемые многоугольники. Единица в матрице означает, что грань может отбрасывать тень на другую, нуль - что не может. Единица на диагонали соответствует многоугольнику в собственной тени.

Если сцена состоит из n многоугольников, то возможно n(n-1) проекционных теней, поэтому важно найти эффективный способ получения матрицы. Проецируют сцену на сферу с центром в источнике света и применяют к спроецированным многоугольникам габаритные тесты с прямоугольной оболочкой для исключения большинства случаев. Можно совместить вектор направления к источнику с осью Z. Затем количество вариантов можно сильно сократить путем использования простых трехмерных габаритных тестов. Для еще большего сокращения числа вариантов можно применить более сложные методы сортировки, например приоритетную сортировку Ньюэла - Ньюэла - Санча.

Обычно матрица включается в связный список, объединяющий тени и многоугольники.

Второй этап - обработка сцены относительно положения наблюдателя - состоит из двух процессов сканирования. В интервальном алгоритме построчного сканирования первый процесс определяет, какие отрезки на интервале видимы. Второй с помощью списка теневых многоугольников находит, падает ли тень на многоугольник, который создает видимый отрезок на данном интервале. Второе сканирование для интервала производится следующим образом:

если нет ни одного теневого многоугольника, то видимый отрезок изображается;

если для многоугольника, содержащего видимый отрезок, имеются теневые многоугольники, но они не пересекают и не покрывают данный интервал, то видимый отрезок изображается; если интервал полностью покрывается одним или несколькими

теневыми многоугольниками, то интенсивность изображаемого видимого отрезка определяется с учетом интенсивностей этих многоугольников и самого отрезка; если один или несколько теневых многоугольников частично

покрывают интервал, то он разбивается в местах пересечения с ребрами теневых многоугольников. Затем алгоритм применяется

42

рекурсивно к каждому из подынтервалов до тех пор, пока интервал не будет изображен.

Здесь предполагается, что интенсивность видимого отрезка зависит от интенсивности теневого многоугольника. В простейшем случае можно считать, что тени абсолютно черные. Однако, если взять источник света и два каких-нибудь предмета, то можно увидеть, что тень может быть не только такой. Интенсивность, т. е. чернота тени, зависит от интенсивности источника и от расстояния между затененной гранью и гранью, отбрасывающей тень. Это вызвано oгpaничeнным размером источника и тем, что на затененную поверхность падает рассеянный свет.

Для того, чтобы смоделировать такой эффект, можно установить прoпopциoнaльную зависимость интенсивности тени и источника. Если накладывается несколько теней, то их интенсивности складываются. Более cлoжных расчетов требует правило, позволяющее сделать интeнcивнocть тени пропорциональной как интенсивности источника так и расстоянию между поверхностью, на которую падает тень и поверхностью, отбрасывающей тень.

ФАКТУРА

Вмашинной графике фактурой называется детализация строения поверхности. Обычно рассматриваются два вида детализации. Первый состоит в том, чтобы на гладкую поверхность нанести заранее заданный узор. После этого поверхность все равно остается гладкой. Наложение узора на гладкую поверхность выполняется с помощью функции отображения. Второй тип детализации заключается в создании неровностей на поверхности. Такие шероховатые поверхности реализуются путем внесения возмущений в параметры, задающие поверхность.

Главным при нанесении рисунка на поверхность является отображение. Поэтому в данном случае задача сводится к преобразованию систем координат. Если рисунок задан в фактурном пространстве в одной прямоугольной системе координат, а поверхность - в другой прямоугольной системе координат, то для нанесения рисунка на поверхность нужно найти или задать функцию отображения одного пространства на другое.

Обычно, хотя необязательно, предполагается, что функция отображения линейна.

Для нанесения рисунка на поверхность необходимо отображение объектного пространства в пространство изображения, а также рассмотренное выше преобразование из фактурного пространства в объектное. Может быть применено также любое видовое преобразование. Если для пространства изображения используется растровое устройство, то можно применить два несколько отличающихся метода.

Первый основан на алгоритме разбиения Кэтмула. Алгоритм Кэтмула разбивает кусок поверхности на фрагменты до тех пор, пока фрагмент не будет покрывать центр только одного пиксела. Затем интенсивность пиксела можно было бы найти по узору, который получен при отображении параметрических значений центра фрагмента или пиксела в фактурное пространство. Но, как указал Кэтмул, такой метод поточечной выборки приводит к сильному лестничному эффекту. Чтобы этого не случилось, Кэтмул, разбивает как кусок поверхности, так и соответствующий узор. Когда найден фрагмент, покрывающий центр только одного пиксела, усредненная интенсивность соответствующего фрагмента узора используется для определения интенсивности пиксела.

Вобщем случае полученный фрагмент узора не обязательно прямоугольный. Когда он изображается на растровом устройстве, его

интенсивность равна средней взвешенной интенсивности пикселов фактуры на данном фрагменте. В качестве весовой функции берется отношение площади пикселов фактуры, находящихся внутри фрагмента, к их полной площади. Таким образом, алгоритм разбиения Кэтмула начинает свою работу на куске поверхности в объектном пространстве и развивается в двух направлениях: в пространстве изображения и фактурном пространстве.

Одно из преимуществ алгоритма разбиения Кэтмула состоит в том, что не обязательно знать обратное преобразование из пространства изображения в объектное пространство или глубину (значение Z) фрагмента в пространстве изображения. Однако есть и недостатки: например, фрагмент может не совпадать с одним пикселом в пространстве изображения. Часто глубина известна из алгоритма удаления невидимых поверхностей. Для того чтобы найти обратное преобразование, нужно сохранить трехмерное видовое преобразование и преобразование объектного пространства в пространство изображения до проецирования на плоскость картины. При этом в фактурное пространство переводится точная площадь, покрываемая пикселом в пространстве изображения. Задача состоит в том, чтобы отобразить площадь пиксела из пространства изображения на поверхность в объектном пространстве, а затем - в фактурное пространство. Интенсивность пиксела в пространстве изображения равна средней интенсивности пикселов, покрытых этой площадью в фактурном пространстве. На полученный коэффициент умножается диффузная компонента модели освещения. Существуют, конечно, и другие, более сложные методы, позволяющие устранять лестничный эффект.

В рассмотренных методах рисунок наносится на гладкую поверхность. и она после этого остается гладкой. Для того чтобы поверхность казалась шероховатой, можно отсканировать фотографию нерегулярной фактуры и отобразить ее на поверхность. Однако при этом будет казаться, что неровности нарисованы на гладкой поверхности. Дело в том, что в векторе нормали к настоящей шероховатой поверхности и, следовательно, в направлении отражения есть небольшая случайная составляющая. На этой основе разработан метод возмущения нормали для построения неровных поверхностей.

Эффект шероховатости зависит от масштаба изображаемого объекта. Например, если размер объекта увеличится в два раза, то величина вектора нормали возрастет в четыре раза, а его возмущения - только в два. Это приводит к тому. что увеличенный объект кажется более гладким. Однако масштаб фактуры на перспективном изображении не зависит от перемещения объекта в пространстве по направлению к наблюдателю или от него.

Один из последних методов построения нерегулярностей основан на фрактальных поверхностях. Фрактальная поверхность состоит из случайно заданных полигональных или биполиномиальных поверхностей. С помощью фрактальных поверхностей изображались природные объекты - камни, деревья, облака, а также ландшафты. Этот метод основан на работе Мандельброта.

Для того чтобы получить полигональную фрактальную поверхность, исходный многоугольник рекурсивно разбивается на фрагменты. Для этого можно, например, случайным образом сместить центр и середины сторон многоугольника, причем и исходный, и полученный многоугольники не обязательно должны быть плоскими.

Одно из преимуществ фрактальных поверхностей в том, что их можно разбивать "бесконечно" и получить любой уровень детализации. Он может зависеть от положения наблюдателя: чем ближе точка наблюдения, тем с большей степенью детализации изображается поверхность. Если наблюдатель находится далеко, объем вычислений значительно сокращается. Фрактальная поверхность изображается с помощью любого подходящего алгоритма удаления невидимых поверх-

43

ностей и любой модели освещения. Однако число разбиений возрастает со скоростью выше линейной, поэтому между количеством разбиений и уровнем детализации должен быть некоторый компромисс. Иначе потребуется слишком много вычислений.

ВВЕДЕНИЕ В OPENGL

Графический стандарт OpenGL, разработан и утвержден в 1992 году девятью ведущими фирмами, среди которых Digital Equipment

Corporation, Evans & Sutherland, Hewlett-Packard Co., IBM Corp., Intel Corp., Intergraph Corp., Silicon Graphics, Inc., Sun Microsystems, inc. и конечно же Miciosoft. В основу стандарта была положена библиотека IRIS GL, разработанная Silicon Graphics. Эта достаточно простая в изучении и использовании графическая система (она включает в себя три библиотеки: Opengl32.1ib, qlu32.ab и glaux.lib), обладающая при этом поразительно широкими возможностями. Вот только некоторые из ее достоинств:

Стабильность. OpenGL устоявшийся стандарт, действующий уже 6 лет. Все вносимые в него изменения предварительно анонсируются и реализуются таким образом, чтобы гарантировать нормальную работу уже на писанного программного обеспечения.

Надежность. Все приложения, использующие OpenGL, гарантируют одинаковый визуальный результат вне зависимости от используемого оборудования и операционной системы.

Переносимость. Приложения, использующие OpenGL, могут запускаться на персональных компьютерах, рабочих станциях или суперкомпьютерах.

Простота использования. OpenGL хорошо структурирована. Ее драйверы включают информацию об основном оборудовании, освобождая разработчика приложения от необходимости проектирования для специфических особенностей графических устройств. Команды OpenGL обеспечивают необходимый баланс между необходимыми функциональными возможностями и гибкостью. Каждая команда OpenGL строго придерживается опубликованной спецификации, сохраняя драгоценный цикл разработки, который теряется при работе с другим, менее удачно спроектированным интерфейсом.

Система OpenGL - это графический стандарт, который предоставляет широкие возможности несмотря на то, что поддерживает простейшую модель программирования. Ее процедурный интерфейс позволяет программистам легко и эффективно описывать как простые, так и комплексные задачи воспроизведения. Поскольку OpenGL применяется только для воспроизведения, то она может включаться в состав любой, не только графической (например X Windows, Windows 95 и Windows NT) операционной системы. Более того, OpenGL спроектирована таким образом чтобы использовать все преимущества любых, даже самых изощренных графических подсистем.

OpenGL является программным интерфейсом для графических устройств и вкачает в себя свыше ста функции и процедур, которые позволяют программисту определять объекты и сложные операции для создания высококачественных образов. С точки зрения программиста OpenGL представляет собой множество команд, одни из которых позволяют определять двумерные и трехмерные графические объекты, а другие управляют их отображением в буфере кадра В этом состоит основное и единственное предназначение OpenGL. Она не поддерживает никакое другое периферийное устройство (например, мышь или клавиатуру), которое может быть связано с графическим устройством. Поэтому программист должен сам обеспечить возможность принимать данные от пользователя, используя для этого другие механизмы.

Перечислим основные возможности, которые OpenGL предоставляет разработчикам:

-Геометрические примитивы (точки, линии и многоугольники)

-Растровые примитивы (битовые массивы и прямоугольники пикселей)

-Работа с цветом в RGBA и индексном режимах

-Видовые и модельные преобразования

-Удаление невидимых линий и поверхностей

-Прозрачность

-Использование В-сплайнов для рисования линий и поверхностей

-Наложение текстуры

-Применение освещения

-Использование плавного сопряжения цветов, устранения ступенчатости, "тумана" и других "атмосферных" эффектов

-Использование списков изображений

Как видите, возможности "почти безграничны" - трудно придумать задачу, которую нельзя было бы решить с помощью OpenGL.

Архитектура OpenGL

В самом общем случае можно сказать, что OpenGL представляет собой обычный набор команд. Они определяют координаты объектов, управляют их трансформацией, позволяют задать параметры объектов (такие, например, как цвета) и, наконец, "рисуют" его. Все это собрано в некоторую единую структуру, которую разработчики назвали конвейером OpenGL.

+------------------+

+>Подготовка списков¦

¦¦изображений ¦

¦+------------------

 

 

+

 

 

 

 

 

¦

¦

+-------------

+

+----------

+

+------------

 

+

Команды

¦

¦Аппроксимация¦

¦Обработка ¦

¦Растеризация¦

---------

+--

>

кривых и +--

>вершин и

+---

>и обработка +-+

^

¦

¦поверхностей ¦

¦ сборка

¦ ^

¦фрагментов

 

¦ ¦

¦

¦

+-------------

+

¦примитивов¦ ¦

+------------

 

+ ¦

¦

¦

 

 

+----------

+ ¦

 

 

¦

¦

¦

 

+-------------

+

¦

+-----------

+

¦

¦

v

 

¦ Операции

¦

¦

¦Определение¦

¦

+------------

 

 

>над пикселами+-----------

 

>параметров ¦

¦

 

 

 

+-------------

+

 

¦ текстуры

¦

¦

 

 

 

^

 

 

+-----------

+

¦

 

 

 

¦

 

 

 

 

¦

 

 

 

¦

 

 

+-----------

+

¦

 

 

 

+-----------------

 

 

¦Буфер кадра<---

+

 

 

 

 

 

 

+-----------

+

 

Синтаксис команд OpenGL

Командами в OpenGL называются функции или процедуры. Имеется достаточно большая группа команд, которые реализованы в нескольких вариантах, различающихся числом и типами аргументов. Для описания таких команд будем использовать следующий синтаксис:

rtype CommandName[1 2 3 4][b s i f d ub us ui][v] (atype arg)

Команда представляется четырьмя компонентами - именем и тремя символами:

CommandName Имя команды, такое как gIVertex или glColor. [1234] Цифра, показывающая число аргументов команды.

44

[b s i f d ub Символы, определяющие тип аргумента. us ui]

[v]Буква, показывающая, что в качестве аргумента используется указатель на массив значений.

Допустимы следующие типы аргументов:

Символ

Тип OpenGL

Тип С (C++)

b

GLbyte

char

s

GLshort

short

i

Glint

int

f

Glfloat

float

d

Gldouble

double

ub

Glubyte

unsigned byte

us

Glushort

unsigned short

ui

Gluint

unsigned int

Параметр rtype определяет тип возвращаемого значения и для каждой команды указывается в явном виде. Параметр atype и аргумент(ы) arg определяются типом и числом аргументов соответственно.

Чтобы сказанное было более понятно, приведем два примера из списка возможных команд для определения вершин.

Команды

 

 

void glVertex3f(

 

glVertex3s(

float arg1,

и

short arg1,

float arg2,

 

short arg2,

float arg3)

 

short arg3)

в представленном синтаксисе записываются в виде: void glVertex3[f s](atype arg)

Компоненты, представленные в квадратных скобках, не во всех случаях являются обязательными.

Команды всегда обрабатываются в порядке, в котором они получены, хотя может наблюдаться задержка прежде, чем команда возымеет действие.

Модель выполнения

Модель для интерпретации команд OpenGL клиент-серверная. Приложение (клиент) генерирует команды, которые интерпретируются и обрабатываются OpenGL (сервер). Сервер может оперировать на том же самом компьютере, что и клиент или на ином компьютере. Сервер может сохранять несколько GL контекстов (контекстов воспроизведения). Клиент может соединяться с любым из этих контекстов.

Эффекты команд OpenGL на буфер изображения в конечном счете управляются оконной системой, которая распределяет ресурсы буфера изображения. Оконная система определяет, к которой части буфера изображения OpenGL может обращаться в данный момент и связывается с OpenGL за получением информации о том, как эта часть структурирована. Поэтому нет никаких команд OpenGL, чтобы конфигурировать буфер изображения или инициализировать OpenGL. Конфигурация буфера изображения сделана вне OpenGL вместе с оконной системой; инициализация OpenGL происходит, когда оконная система распределяет окно для исполнения OpenGL.

ОСОБЕННОСТИ РЕАЛИЗАЦИИ OPENGL В WINDOWS NT И WINDOWS 95

Являясь графическим стандартом, OpenGL может работать практически под управлением любой операционной системы. И хотя это

действительно так, однако для каждой конкретной системы существует своя реализация этого стандарта, которая может не поддерживать некоторые из общих возможностей. В полной мере это относится и к операционным системам Windows. Строго придерживаясь стандарта, реализация OpenGL для Windows NT и Windows 95 требует выполнения некоторых предварительных настроек, связанных с ocобенностями этих операционных систем. Для того, чтобы оконная система могла работать с OpenGL, необходимо провести ее инициализацию и сконфигурировать буфер фрейма (кадра). Обе эти операции выполняются вне

OpenGL.

Вспомним, как осуществляется рисование в Windows. Создается контекст устройства, и весь графический вывод осуществляется через него. Нечто подобное необходимо и для работы с OpenGL, только в отличие от рисования GDI, OpenGL использует концепцию контекста воспроизведения (rendering context), который связывает OpenGL с оконными системами Windows NT и Windows 95. Если контекст устройства содержит информацию, относящуюся к графическим компонентам GDI Windows NT и Windows 95, то контекст воспроизведения содержит информацию, относящуюся к OpenGL.

Таким образом, чтобы начать работать с командами OpenGL, приложение должно создать один или несколько контекстов воспроизведения для потока и сделать текущим один из них. Каждый поток при этом может иметь один и только один текущий контекст воспроизведения, который ассоциирован с определенным контекстом устройства Контекст воспроизведения может быть текущим только для одного потока.

Второй момент, связанный с особенностями реализации OpenGL в Windows NT и Windows 95, заключается в том, что перед созданием контекста воспроизведения необходимо установить для него формат пикселей, который определяет некоторые свойства поверхности рисования OpenGL и должен совпадать с форматом пикселей соответствующего контекста воспроизведения.

Итак, перед тем как начать пользоваться командами OpenGL, необходимо выполнить некоторые обязательные инициализирующие действия. Рассмотрим их.

УСТАНОВКА СТИЛЯ ОКНА OPENGL

Прежде всего обращаем внимание на то, что OpenGL требует для своего окна наличия установленных стилей WS_CLIPCHILDREN и

WS_CLIPSIBLINGS.

Приведенный ниже фрагмент кода иллюстрирует, как и где это можно сделать.

BOOL CPrimView::PreCreateWindow(CREATESTRUCT &cs)

{

//OpenGL требует обязательного наличия стилей

//WS_CLIPCHILDREN и WS_CLIPSIBLINGS

cs.style |= (WS_CLIPCHILDREN | WS_CLIPSIBLIMGS); return CView::PreCreateWindow(cs);

}

 

УСТАНОВКА ФОРМАТА ПИКСЕЛЕЙ

 

Реализация OpenGL фирмы Microsoft для Windows NT и

Windows

95 использует специальную структуру PIXELFORMATDESCRIPTOR,

чтобы

представить данные формата пикселей:

 

typedef struct tagPIXELFORMATDESCRIPTOR {

 

WORD nSize;

// Размер структуры

 

45

WORD nVersion; // Номер версии

DWORD dwFlags; /* Битовые флаги, определяющие устройство и интерфейс, с которым совместим формат пикселей (табл. 1)

*/

BYTE iPixelType; /* Режим, используемый для изображения цветов. Доступны два значения флага: PFD_TYPE_RGBA - цвет каждого пикселя определяется четырьмя значениями: красным, зеленым, синим и альфа; PFD_TYPE_COLOR INDEX - цвет каждого пикселя определяется индексом в специальной таблице цветов

*/

BYTE cColorBits;// Число битовых плоскостей в каждом буфере // цвета

BYTE cRedBits; // Число битовых плоскостей красного в каждом

// буфере RGBA

BYTE cRedShift;// Смещение от начала числа битовых плоскостей // красного в каждом буфере RGBA

BYTE cGreenBits;

BYTE cGreenShift;

BYTE cBlueBits;

BYTE cBlueShift;

BYTE cAlphaBits;

BYTE cAlphaShift;

BYTE AccumBits; // Число битовых плоскостей в буфере аккумуля- // тора

BYTE cAccumRedBits; // Число битовых плоскостей красного в бу- // фере аккумулятора

BYTE cAccumGreenBits;

BYTE cAccumBlueBits;

BYTE cAccumAlphaBits;

BYTE cDepthBits;

// Размер буфера глубины (ось z)

BYTE cStencilBits;

// Размер буфера трафарета

BYTE cauxBuffers;

// Число вспомогательных буферов

BYTE iLayerType;

// Может принимать одно из следующих значе-

 

// ний:

 

// PFD MAIN_PLANE,

// PFD OVERLAY_PLANE // PFD_UNDERLAY_PLANE

BYTE bReserved;

DWORD dwLayerMask; // Игнорируется

DWORD dwVisibleMask; // Индекс или цвет прозрачности нижней // плоскости

DWORD dwDamageMask; // Игнорируется

} PIXELFORMATDESCRIPTOR;

Рассмотрим поля этой структуры:

Таблица 1

-----------------------------------------------------------------

Значение Назначение

-----------------------------------------------------------------

PFD_DRAW_TO_WINDOW Разрешено рисование в окне или на поверхности устройства

PFD_DRAW_TO_BITMAP

PFD_SUPPORT_GDI PFD_SUPPORT_OPENGL PFD_GENERIC_FORMAT

Разрешено рисование в битовый массив в памяти

Поддерживается рисование GDI

Поддерживается рисование OpenGL

Формат пикселей поддерживается программной реализацией GDI, называемой также основной реализацией. Если этот флаг не установлен, то формат пикселей поддерживается драйвером устройства или оборудования

PFD_NEED_PALETTE

Для управления палитрой

устройства

 

используются пиксели RGBA. Логическая

 

палитра требуется для получения

луч-

 

шего результата для этого типа предс-

 

тавления пикселей (в

частности,

для

 

проведения гамма-коррекции цветов).

 

Цвета в палитре должны быть определе-

 

ны соответственно

в полях cRedBits,

 

cRedShift,

cGreenBits,

cGreenShift,

 

cBlueBits и cBlueShift. Палитра долж-

 

на быть создана и инициализирована в

 

контексте

устройства до вызова функ-

 

ции wglMakeCurrent

 

 

 

PFD_NEED_SYSTEM_PALETTE Используется системой со специальным оборудованием для OpenGL, которое поддерживает только одну палитру устройства. Для таких систем используются специальные ускорители и они должны иметь фиксированный размер и порядок, например 3-3-2, при работе в режиме RGB, или должны совпадать с логической палитрой в режиме индексации цветов. При установленном этом флаге вызов функции SetSystemPaletteUse

приводит к отображению "один к одному" логической и системной палитр. Если оборудование для OpenGL поддерживает несколько палитр, и драйвер устройства отводит для них место, нет необходимости устанавливать этот флаг точно так же, как он не устанавливается для основного формата пикселей

PFD_DOUBLEBUFFER Поддерживается режим двойной буферизации.

PFD_SWAP_LAYER_BUPFERS Показывает, может ли устройство менять местами отдельные уровни с форматами пикселей, которые включают верхние и нижние плоскости при двойной буферизации. В противном случае

46

все уровни рассматриваются как единая группа. При установленном этом флаге можно использовать функцию wglSwaplayerBuffers

-----------------------------------------------------------------

Основная реализация OpenGL в Windows поддерживает 24 различных фор мата пикселей. Несмотря на то что каждый формат идентифицируется индексом от 1 до 24, они не являются постоянными, и поэтому никогда нельзя полагаться на порядок индексов. Формат пикселей характеризуется некоторыми свойствами, основным из которых является число битов на пиксел.

Исходно поддерживаются пять битовых плоскостей: 32, 24, 16, 8 и 4 бита на пиксель. Эти пять и еще три формата пикселей, определяемые драйвером дисплея, рассматриваются как внутренний (native) формат. Остальные 16 поровну делятся между организацией других битовых плоскостей и поддержкой битовых массивов (они рассматриваются не как внутренний формат). Все внутренние форматы представлены в таблице:

 

 

Таблица 2

-----------------------------------------------------------------

Режим

Буферизация

Размер буфера глубины

-----------------------------------------------------------------

PFD_TYPE_RGBA

Одинарная

32

 

Одинарная

16

 

Двойная

32

 

Двойная

16

PFD_TYPE_COLOR_INDEX

Одинарная

32

 

Одинарная

16

 

Двойная

32

 

Двойная

16

-----------------------------------------------------------------

Для работы с этой структурой в Win32 реализованы четыре функции. Контекст устройства может поддерживать несколько форматов пикселей, которые в Windows NT и Windows 95 идентифицируются по значению индекса. При этом текущим может быть только один формат. Прежде чем установить некоторый желательный формат пикселей, необходимо направить системе запрос - поддерживает ли она его. Сделать это можно при помощи функции

int ChoosePixelFormat( HDC hdc,

const PIXELFORMATDESCRIPTOR *ppfd);

Функция просматривает, в контексте устройства hdc, поддерживаемые форматы пикселей, и выбирает наиболее совпадающий с описанным в структуре, на которую указывает ppfd. Поля структуры описаны выше, поэтому здесь остановимся только на дополнительных сведениях (ограничениях) об их использовании.

Если в поле dwFlags структуры установлены какие-либо флаги, то функция учитывает их при поиске лучшего совпадения. Для того чтобы в дальнейшем при работе не возникало никаких неожиданностей, лучше всего задавать их в явном виде. Если для флагов можно не указывать никакого значения, то в поле iPixelType обязательно

должно быть установлено значение либо PFD_TYPE_RGBA, либо PFD_TYPE_COLORINDEX, определяющее метод, используемый для отображения цветов, - тройка RGB или индекс в палитре, соответственно. Аналогично, в поле iLayerType в явном виде следует указать одно из возможных значений - PFD_MAIN_PLANE, PFD_OVERLAY_PLANE или

PFD_UNDERLAY_PLANE, определяющих "рабочий слой". Значения, зада-

ваемые в полях cColorBits, cAlphaBits, cAccumBits, cDepthBits, cStencilBits и cAuxBuffer, должны быть больше или равны нулю. Значения в остальных полях при поиске не учитываются. В случае успешного завершения функция возвращает индекс формата пикселей (начиная с 1), наиболее полно удовлетворяющего заданным параметрам. В случае ошибки возвращается 0.

Вызов этой функции гарантирует, что OpenGL будет работать с форматом пикселей, поддерживаемым устройством, на которое будет осуществляться вывод изображения. Например, если хотелось бы использовать 24-разрядный буфер RGB цветов, а контекст устройства поддерживает только 8-разрядный, то функция возвратит формат пикселей именно с 8-разрядным буфером RGB цветов.

После того как найден формат пикселей, наиболее полно совпадающий с требуемым, можно (и нужно) установить его в контексте устройства:

BOOL SetPixelFormat( HDC hdc,

int iPixelFormat,

CONST PIXELFORMATDESCRIPTOR *ppfd);

Рассмотрим фрагмент кода, демонстрирующий установку наиболее типичных значений формата пикселей:

//Объявление функции с аргументами, задаваемыми по умолчанию

BOOL Create //Класс COpenGL

( CWnd* pWnd,

//Работаем с тройками цветов, а не с палитрами

int iPixelType

= PFD_TYPE_RGBA,

 

 

DWORD dwFlags

= PFD_DOUBLEBUFFER

| //

Двойная буферизация

 

PFD_SUPPORT_OPENGL

| //

Поддержка OpenGL

 

PFD DRAW_TO_WINDOW

//

Рисуем в ОКНО

);

BOOL COpenGL::Create (CWnd* pWnd, int iPixelType, DWORD dwFlags)

{

//Если не создано окно, то рисовать будет некуда

ASSERT(pWnd) ;

//Обязательно нужно указать,

//в каком виде представляются цвета

ASSERT ((iPixelType == PFD_TYPE_RGBA) || (iPixelType == PFD_TYPE_COLORINDEX));

//Создаем структуру

PIXELFORMATDESCRIPTOR pfd;

//Поскольку не все поля этой структуры значимы,

//устанавливаем их в 0

memset(&pfd, 0, sizeof(PIXELFORMATDESCRIPTOR));

// Заполняем значимые поля структуры PIXELFORMATDESCRIPTOR

//

 

 

pfd.nSize

= sizeof(PIXELFORMATDESCRIPTOR);

pfd.nVersion

= 1;

// Номер версии

pfd.dwFlags

= dwFlags;

 

pfd.iPixelType

= iPixelType;

pfd.cColorBits

= 64;

// красный, зеленый и синий цвета

47

pfd.cAlphaBits

= 64;

// компонента альфа цвета

pfd.cAccumBits

=64;

// буфер аккумулятора

pfd.cDepthBits

=64;

// буфер глубины

pfd.cStencilBits

= 64;

// трафарет

pfd.iLayerType

= PFD_MAIN_PLANE; // тип плоскости

...

//Создаем контекст устройства

//m_pdc = new CClientDC (pWnd);

//Выбираем наиболее подходящий формат пикселей

int nPixelFomat = ChoosePixelFormat (m_pdc->m_hDC, &pfd); if(nPixelFormat == 0)

{

MessageBox{"Ошибка при выборе формата пикселей"); return FALSE;

}

//После того как от системы получен формат пикселей, наиболее

//точно совпадающий с запрошенным, устанавливаем его

//

BOOL bResult = SetPixelFormat (m_pdc->m_hDC, nPixelFormat, &pfd);

if(!bResult)

{

MessageBox("Ошибка при установке формaта пикселей"); return FALSE;

}

...

return TRUE;

}

Две оставшиеся функции DescribePixelFormat и GetpixelFormat

позволяют получить информацию о текущих параметрах и индексе формата пикселей соответственно

int DescribePixelFormat( HDC hdc,

int iPixelFormat, UINT nBytes,

LPPIXELFORMATDESCRIPTOR ppfd);

Функция позволяет получить информацию о параметрах формата пикселей, заданного индексом iPixelFormat, для контекста устройства hdc. Полученная информация записывается в структуру PIXELFORMATDESCRIPTOR, определенную указателем ppfd и имеющую размер nBytes. При успешном завершении функция возвращает максимальный доступный индекс формата пикселей и нулевое значение в противном случае. Если требуется определить только максимальное значение индекса, то в качестве параметра ppfd можно использовать NULL.

int GetPixcelFormat(HDC hdc)

При успешном завершении функция возвращает индекс текущего формата пикселей в контексте устройства hdc и 0 - в случае неудачи.

УСТАНОВКА ТЕКУЩЕГО КОНТЕКСТА ВОСПРОИЗВЕДЕНИЯ

Для работы с контекстом воспроизведения в Win32 API реализованы следующие функции

HGLRC wglCreateContext(HDC hdc);

Функция создает новый контекст воспроизведения OpenGL, который подходит для рисования на устройстве, определенном дескриптором hdc. При успешном завершении функция возвращает дескриптор созданного контекста воспроизведения OpenGL и NULL - в случае неудачи.

Создавать можно произвольное число контекстов воспроизведения, но для того, чтобы можно было работать с графикой OpenGL, необходимо установить единственный текущий контекст воспроизведения потока. Сделать это можно при помощи функции:

BOOl wglMakeCurrent(

HDC hdc,

HGLRC hglrc);

Параметр hdc определяет контекст устройства. Это необязательно тот же самый контекст, который использовался при создании контекста воспроизведения, но он должен иметь тот же самый формат пикселов. Второй параметр hglrc определяет контекст воспроизведения ОреnGL. Перед тем как установить новый текущий контекст воспроизведения, ОреnGL сбрасывает предыдущий контекст воспроизведения и заменяет его на новый. Этот механизм задействован для того, чтобы жестко выполнялось требование о том, что текущим в потоке может быть только один контекст воспроизведения. Более того, попытка сделать один и тот же контекст воспроизведения текущим для нескольких потоков приведет к ошибке. Приложение может осуществлять рисование в нескольких потоках. При этом оно должно использовать для каждого из них различные текущие контексты воспроизведения.

Самое удобное место для создания контекста воспроизведения - это обработчик сообщения WM_CREATE, где эти две функции обычно и используются.

BOOL COpenGL::Create (CWnd* pWnd, int iPixelType, DWORD dwFl.ags)

{

// Создаем и делаем текущим контекст воспроизведения if (CreateGLContext (m_pdc) ==FALSE) return -1; return 0;

}

BOOL CPrimView::CreateGLContext (HDC hdc)

{

HGLRC hrc;

// Создаем контекст воспроизведения

if((hrc =::wglCreateContext(m_pdc->m_hDC)) == NULL)

//He удалось создать контекст воспроизведения return FALSE;

//Делаем контекст воспроизведения текущим if(::wglMakeCurrent(hdc, hrc) == FALSE) return FALSE; return TRUE;

}

При желании можно сделать так, что ни один из контекстов воспроизведения не будет текущим. Эта ситуация возникает, например, перед завершением работы - прежде чем удалить контекст воспроизведения, необходимо, чтобы он никем не использовался. Для этого

48

достаточно выполнить следующий вызов:

::wglMakeCurrent (NULL, NULL);

ЗАВЕРШЕНИЕ РАБОТЫ С OPENGL

Как уже не раз отмечалось, одним из правил программирования для Windows является следующее: прежде чем закончить работу - "убери" за собой. В применении к рассматриваемому вопросу это означает, что перед окончанием работы с потоком необходимо удалить контекст воспроизведения. Для этой цели используется функция:

BOOL wglDeleleContext(HGLRC hglrc)

В качестве параметра hglrc используется дескриптор контекста воспроизведения, который необходимо удалить.

После того как удален контекст воспроизведения, следует удалить и ассоциированный с ним контекст устройства.

Текущий контекст воспроизведения можно узнать, если воспользоваться функцией:

HGLRC wglGetCurrentContext()

которая возвращает дескриптор текущего контекста воспроизведения или NULL, если такового нет.

Дескриптор контекста устройства, ассоциированного с контекстом воспроизведения можно получить при помощи функции

HOC wglGetCurrentDC()

Если поток не имеет текущего контекста воспроизведения, функция возвращает NULL.

Ниже приведен фрагмент кода, иллюстрирующий корректное завершение работы с OpenGL.

void COpenGLView::Destroy()

{

if(m_hrc)

{

//Запрашиваем текущий контекст воспроизведения if(m_hrc ==::wglGetCurrentContext())

//Делаем его не текущим

::wglMakeCurrent (NULL, NULL);

//Удаляем контекст воспроизведения

::wglDeleteContext (m_hrc) ; m_hrc = NULL;

}

//Удаляем контекст рабочей области if (m_pdc)

delete m_pdc;

//Для корректного завершения работы

//передаем управления вверх по иерархии

CView::OnDestroy();

}

Структура приложения, использующего OpenGL:

+---------------------------------------

+

¦ - Получить контекст устройства

¦

¦ - Создать контекст воспроизведения, ¦

¦используя этот контекст устройства ¦

¦ - Сделать его текущим

 

¦

 

+----------

^----------------------------

 

 

+

 

 

¦

WM_CREATE

 

 

 

+

----------------

+

+-------------

 

+

¦ Цикл обработки ¦ WM_PAINT

¦Вызовы команд¦

¦

сообщений

+-------------

>

OpenGL

¦

+

----------------

+

+-------------

 

+

 

¦

WM_DESTROY

 

 

 

+----------

V-------------------------

 

 

+

 

¦ - Сделать контекст

 

¦

 

¦

воспроизведения не текущим

 

¦

 

¦ - Освободить контекст устройства,

¦

 

¦

связанный с контекстом

 

¦

 

¦

воспроизведения

 

¦

 

¦ - Удалить контекст воспроизведения ¦

 

+------------------------------------

 

 

 

+

 

Для того чтобы можно было работать с OpenGL в Windows NT и Windows 95, необходимо выполнить следующие требования:

1.В функции PreCreateWindow установить для окна стили

WS_CLIPCHILDREN и WS_CLIPSIBLINGS.

2.В обработчике сообщения WM_CREATE необходимо установить формат пикселей (функции ChoosePixelFormat и SetPixelFormat),

создать контекст воспроизведения (функция wglCreateContext} и сделать его текущим (функция wglMakeCurrent).

3.В обработчике сообщения WM_DESTROY обеспечить удаление контекста воспроизведения (функции wglMakeCurrent и wglDeleteConlext). Кроме перечисленных выше действий необходимо подключить к проекту библиотеки opengl32.1ib и glu32.iib, а также включить заголовочные файлы gl\gl.h и gl\glu.h. Лучше всего это сделать в файле stdafx.h.

ВЕРШИНЫ И СИСТЕМА КООРДИНАТ

Вершина - это точка в трехмерном пространстве. Для описания трехмерного объекта достаточно трех координат. Чтобы учесть влияние перспективы, было предложено описывать точку на плоскости трехэлементным вектором, а в пространстве - четырехэлементным. В этом случае говорят, что точка представлена однородными координатами. Для ее определения в библиотеке реализована команда:

void glVertex[2 3 4][s i f d](type coord) void glVertex[2 3 4][s i f d]v(type coord)

Вызов любой команды glVertex определяется четырьмя координатами: х, у, z и w. При этом соблюдается следующее соглашение: вызов gIVertex2 задает координаты х и у, координата z полагается равной 0, а w - 1; вызов glVertex3 задает координаты х, у и z, a w полагается равной 1; вызов gIVerlex4 задает все четыре координаты.

Примитивы OpenGL

Примитив - это фигура, такая как точка, линия, многоугольник, прямоугольник пикселей или битовый массив, которая рисуется, хранится и которой манипулируют как единым объектом. Другими словами, примитивы - это те элементы, из которых строятся графические образы любой степени сложности. Они определяются группами из одной или нескольких вершин, каждая из которых имеет ассоцииро-

49

ванные с ней данные:

Текущий цвет - задает цвет, который вместе с условиями освещения определяет результирующий цвет вершины. Цвет задается командами glColor для режима RGBA и glIndex для индексного режима.

Текущая позиция растра - используется для определения координат растра при работе с пикселями и битовыми массивами. Задается ко-

мандой glRasterPos.

Текущая нормаль - определяет вектор нормали, ассоциированный с отдельной вершиной, и задает ориентацию содержащей ее поверхности в трехмерном пространстве. Для указания нормали в OpenGL реализована команда gINormal.

Текущие координаты текстуры - определяют местоположение в карте текстуры, которая ассоциируется с вершиной объекта. Задаются ко-

мандой gITexCoord.

Примитив или группа однотипных примитивов, к которым относятся точки, линии, связанные линии, замкнутые линии, треугольники, связанные треугольники с общим ребром, связанные треугольники с общей вершиной, четырехугольники, связанные четырехугольники и многоугольники, определяются внутри командных скобок glBegin/glEnd:

void glBegin (GLenum mode) void glEnd()

Параметр mode указывает примитивы, которые создаются из вершин, определенных между этими командами. Доступными являются следующие символьные константы (n - номер текущей вершины, а N - общее число вершин).

-----------------------------------------------------------------

Значение mode Описание

-----------------------------------------------------------------

GL_POINTS

Каждая

вершина

рассматривается

как

 

отдельная точка, параметры которой

не

 

зависят

от параметров остальных

заданных

 

точек.

При этом вершина n определяет

 

точку n. Рисуется N точек

 

 

GL_LINES

Каждая

пара

вершин

рассматривается

как

 

независимый отрезок. Первые две вершины

 

определяют

первый отрезок, следующие

две

 

- второй отрезок и т- д., вершины (2n -1)

 

и 2n определяют отрезок n. Всего рисуется

 

N/2 линий. Если число вершин нечетно,

то

 

последняя просто игнорируется.

 

 

GL_LINE_STRIP

В этом режиме рисуется последовательность

 

из одного или нескольких связанных

 

отрезков. Первая вершина задает начало

 

первого отрезка, а вторая - конец первого,

 

который является также началом второго.

В

 

общем случае, вершина n {n > 1) определяет

 

начало

отрезка n

и конец отрезка (n-1).

 

Всего рисуется (N-1) отрезок.

 

 

GL_LINE_LOOP

Этот режим

аналогичен предыдущему,

за

 

исключением

того,

что последняя

вершина

 

является

началом отрезка, концом которого

 

служит

первая вершина. Вершины n и

(n+1)

 

определяют

отрезок n. При этом

последний

 

отрезок определяется вершинами N и 1.

 

Всего рисуется N отрезков.

 

 

 

GL_TRIANGLES

Каждая

тройка вершин рассматривается

как

 

независимый треугольник. Если число вершин

 

не кратно 3, то оставшиеся (одна или две)

 

вершины

игнорируются.

Всего рисуется N/3

 

треугольника.

 

 

 

 

 

GL_TRIANGLE_STRIP

В

этом

режиме рисуется группа

связанных

 

треугольников, имеющих общую грань. Первые

 

три вершины определяют первый треугольник;

 

вторая,

третья и четвертая - второй и

т.

 

д. Всего рисуется (N-2) треугольника.

 

GL_TRIANGLE_FAN

В

этом

 

режиме

также

рисуется

группа

 

связанных треугольников. Первые три верши-

 

ны определяют первый треугольник;

 

первая,

 

третья и четвертая - второй и т. д. Верши-

 

ны 1, (n+1) и (n+2) определяют треугольник

 

n. Всего рисуется (N-2) треугольника

 

GL_QUADS

Каждая

 

группа

из

четырех

 

вершин

 

рассматривается как

независимый четыреху-

 

гольник. Вершины (4n-3), (4n-2), (4n-1) и

 

4n определяют четырехугольник n. Если чис-

 

ло вершин не кратно 4,

то оставшиеся (од-

 

на, две или три) вершины игнорируются.

 

Всего рисуется N/4 четырех угольника.

 

GL_QUAD_STRIP

Рисует

 

связанную

 

группу

 

четырехугольников. Первые четыре вершины

 

определяют

первый

четырехугольник;

 

третья, четвертая, пятая и шестая вершины

 

-

второй

и т. д. Всего рисуется

 

(N-2)/2

 

четырехугольника

 

 

 

 

 

GL_POLYGON

Рисует

отдельный выпуклый многоугольник,

 

заданный вершинами от 1 до N

 

 

 

ОСНОВНЫЕ ЭТАПЫ ОБРАБОТКИ ВЕРШИН И АССОЦИИРОВАННЫХ С НИМИ ТЕКУЩИХ ЗНАЧЕНИЙ

После того как установлен формат пикселей, т. е. - библиотека OpenGL присоединена к Windows, необходимо определить такой цвет, который лучше всего воспринимается в качестве фона. Осуществляется это при помощи команды

void glСlеагСоlог(

GLclampf red, GLclampf green, GLclampf blue, GLclampf alpha);

Эта команда определяет красный, зеленый, синий и альфа компоненты цвета, которые используются при очистке буферов цвета. Значения аргументов red, green, blue и alpha ограничены диапазоном [0, 1] и по умолчанию установлены в 0.

После того как значение цвета определено, установить его можно командой

void glClear(GLbitfield mask);

mask - определяет очищаемые буферы, которые могут задаваться при

50

Соседние файлы в предмете [НЕСОРТИРОВАННОЕ]