ЛЕКЦИЯ 1 ВВЕДЕНИЕ .................................................................................................................. 2 Что такое компьютерная графика? ........................................................................................................ 2 ЛЕКЦИЯ 2 АФФИНЫ. .................................................................................................................... 7 Двумерные геометрические (аффинные) преобразования ...................................................... 7 Представление точек и общая схема преобразования с использованием матриц .............................. 7 Преобразование масштабирования ....................................................................................................... 8 Преобразование поворота...................................................................................................................... 9 Преобразование переноса и однородные координаты ...................................................................... 10 Выполнение произвольных преобразований на плоскости. Композиция преобразований .............. 11 Выводы по плоским геометрическим преобразованиям..................................................................... 12 Трехмерные преобразования ............................................................................................................... 13 Преобразования поворота в пространстве .......................................................................................... 13 Коммутативность преобразований....................................................................................................... 14 Преобразования как изменение координатных систем .................................................................................... 14 ЛЕКЦИЯ 3. ДВУМЕРНЫЙ КОНВЕЙЕР. ...................................................................................... 16 Координатные системы двух мерного геометрического конвейера и их преобразование ................ 16 ЛЕКЦИЯ 4. OPENGL. ................................................................................................................... 19 Синтаксис команд OpenGL .................................................................................................................... 19 Настройка библиотеки ........................................................................................................................................ 20 Задание аффинных преобразований ................................................................................................................ 21 Координатные системы ...................................................................................................................................... 22 Задание векторных примитивов......................................................................................................................... 22 Порядок соединения вершин. Вершины .............................................................................................. 23 ЛЕКЦИЯ 5. ПРОЕКЦИИ ............................................................................................................... 26 Проекции .............................................................................................................................................. 26 Параллельные проекции .................................................................................................................................... 27 Центральные проекции ....................................................................................................................................... 29 Реализация проективных преобразований ......................................................................................... 29 Ортографические проекции................................................................................................................................ 30 ЛЕКЦИЯ 6. РЕАЛИЗАЦИЯ ПРОЕКЦИЙ В OPENGL .................................................................. 31 Ортографическая проекция ................................................................................................................. 31 Перспективная проекция ..................................................................................................................... 32 Ориентация в пространстве ................................................................................................................. 33 Построение дополнительных плоскостей отсечения. ......................................................................... 34 ЛЕКЦИЯ 7. ОСВЕЩЕНИЕ И СВЕТ. ............................................................................................ 35 1 Простая модель освещения ............................................................................................................... 35 1.1 Диффузное отражение ................................................................................................................................. 35 1.2 Зеркальное отражение ................................................................................................................................. 36 1.3 Общая модель ............................................................................................................................................... 37 2 Источники света в OpenGL................................................................................................................. 38 2.1 Модель освещения ....................................................................................................................................... 40 2.3 Грани .............................................................................................................................................................. 41 2.2 Свойства материала ..................................................................................................................................... 42 Плоское закрашивание ................................................................................................................................... 43 Закрашивание методом Гуро ......................................................................................................................... 44 Закраска Фонга ............................................................................................................................................... 45 3 Цвет в машинной графике................................................................................................................. 45 3.1 Цветовая модель HSV .................................................................................................................................. 48 ЛЕКЦИЯ 8. ТЕКСТУРЫ. .............................................................................................................. 49 Наложение текстуры ............................................................................................................................ 49 ЛЕКЦИЯ 8. УДАЛЕНИЕ НЕВИДИМЫХ ЛИНИЙ. ........................................................................ 53 Удаление невидимых линий и поверхностей. ..................................................................................... 53 Алгоритм плавающего горизонта ....................................................................................................................... 54 Алгоритм Ньюэла-Нюэла-Санча ........................................................................................................................ 57 Алгоритм использующий Z-буфер ..................................................................................................................... 58 Алгоритм Вейлера— Азертона .......................................................................................................................... 60 Алгоритм определения видимых поверхностей путем трассировки лучей .................................................... 61 1 Лекция 1 Введение Что такое компьютерная графика Области применения компьютерной графики Основные понятия и определения Основные принципы визуализации сложных изображений Геометрическая модель Графический конвейер и его структура Структура интерактивной графической системы Что такое компьютерная графика? За последние несколько десятилетий компьютерная графика прошла путь от вычерчивания простых линий и отрезков, до построения виртуальной реальности и создания полнометражных кинофильмов. Само слово “графика” в его привычном понимании уже не соответствует той области интересов, которую охватывает компьютерная графика. На сегодняшний день компьютерная графика - это область информатики, в сферу интересов которой входят все аспекты формирования изображений с помощью компьютеров. Уточняя, можно сказать, что предметом ее изучения является создание, хранение и обработка моделей и их изображений с помощью ЭВМ. В интерактивной компьютерной графике пользователь может управлять характеристиками объектов модели. Так, он может управлять процессом создания модели (графические редакторы, САПР и пр.) или работать с готовой моделью, изучая ее свойства и поведение (тренажеры, игры и др.). Слово “интерактивная” часто опускают, так как большинство современных графических приложений обладают той или иной степенью интерактивности. Сегодня компьютерная графика находит применение в широком спектре областей человеческой деятельности. С ее помощью решается большой круг задач. Трудно перечислить их все, отменим лишь некоторые. Создание деловой графики – построение диаграмм, структурных схем и т.д. Сложно найти современную систему оформления документов, в которой не реализованы возможности создания деловой графики. Визуализация научных исследований. Здесь пройден путь от простого построения графиков функций до представления на экране компьютера информации, которая не может быть воспринята органами чувств человека. Например, в медицине это результаты томографии, ультразвукового зондирования и других современных методов исследования. В астрономии - это представление информации, полученной с помощью радиотелескопов и других не оптических приборов. Создание зримых геометрических образов помогает лучше понять суть происходящих процессов. Более того, современные средства обработки результатов исследований позволяют увидеть не только статический «снимок» результатов исследований, но и построить на их основе модель процесса и провести изучение. Например, можно смоделировать движение потока жидкости или вихревой процесс в атмосфере. Моделирование фрагментов реального мира. Результаты, полученные в этой области, легли в основу разнообразных тренажеров, применяемых при обучении пилотов, водителей, операторов ядерных реакторов и представителей многих других профессий. Высококачественные симуляции реального мира находят свое применение в кино и на телевидении, для съемок отдельных фрагментов или даже целых фильмов («Шрек» и др.). Автоматизированное проектирование. Это очень важная область человеческой деятельности, без которой невозможна разработка высокотехнологичной продукции, например процессоров для ЭВМ. Системы автоматизированного проектирования (САПР) находят свое применение в машиностроении, электронике, архитектуре и др. областях. Системы проектирования также оснащаются средствами моделирования, позволяющими не только выполнить проектирование изделия, но и проанализировать работу. Создав, скажем, электронную схему, инженер может посмотреть, как она работает, замерить токи 2 и напряжения, возникающие в ней. Затем он может вернуться на этап проектирования и исправить выявленные ошибки. Отдельно можно отметить применение графики в индустрии развлечений. Популярность компьютерных игр известна всем. Высокий потребительский спрос в данной сфере стимулирует развитие, как самой компьютерной графики, так и аппаратных средств, используемых в ней. Различные авторы расходятся во мнении относительно классификации областей применения компьютерной графики. В практических приложениях, как правило, встречаются признаки, позволяющие отнести их к нескольким областям. Наиболее часто выделяют следующие области: Моделирование (Modeling) – создание и представление трехмерных (3D) моделей; Визуализация (Rendering) – создание плоских изображений трехмерных (3D) моделей; Обработка плоских изображений (Imaging); Анимация (Animation) – имитация изменений во времени; Пользовательский интерфейс (User Interface); Каждое из приведенных направлений имеет свою специфику и требует детального изучения. При первом знакомстве нам интересны все знания о предмете, к какому бы разделу они не относились. Поэтому в ходе изложения материала мы будем рассматривать его как единое целое. В реальном мире мы с помощью фотоаппарата легко получаем двумерный образ объекта или какого-либо его фрагмента в виде фотографии. Проведя аналогию, мы можем сформулировать задачу, решение которой позволит создать подобный образ с помощью компьютерной графики. Имеется трехмерная сцена, которую необходимо отобразить на некотором устройстве вывода графической информации, обладающем ограниченной плоской рабочей поверхностью (например, дисплей или принтер). Рисунок 1.1. Процесс, решающий подобную задачу носит название визуализации. Прежде, чем приступить к рассмотрению основных этапов этого процесса, обратим внимание на форму представления исходных данных и результатов. Начнем с исходных данных. Под сценой понимают совокупность моделей в трехмерном пространстве. Модель – совокупность примитивов, представляющая сложный объект. Примитив – простейший неделимый геометрический объект, обрабатываемый системой как единое целое. В различных системах примитивами могут являться разнообразные геометрические объекты. От простого отрезка до сложной поверхности. Рассмотрим подробнее понятие модель, играющее большую роль в компьютерной графике. Модель в том или ином виде присутствует в подавляющем большинстве графических систем. Построить геометрическую модель можно различными способами. Возьмем простой куб и попробуем построить его модель. Простая совокупность координат вершин куба показанная на рисунке 1.2 а) не может служить его моделью т.к. в ней недостаточно информации определения формы объекта. Шесть вершин могут быть соединены линиями несколькими способами. Введя понятия ребер, представляемых линиями, соединяющими пары вершин, мы получаем корректное, однозначно интерпретируемое описание куба. Рисунок 1.2 b). Такое описание носит название каркасной модели. С его помощью мы можем построить и изобразить проволочный каркас куба. Получить заполненный куб с помощью данной модели не удастся, т.к. в ней нет информации о гранях. Добавить эту информацию можно введя в модель еще один уровень иерархии, определяя с помощью каких ребер, формируются грани. Получившаяся модель представлена на рисунке 1.3 c). Она носит название гранично-определенной модели т. к. определяет границы пространства, занимаемого объектом. Существует много различных подходов к созданию геометрических моделей. Например, можно построить модель на основе принципов конструктивной объемной геометрии. В этом случае определяется библиотека стандартных объемных объектов, таких как сфера, цилиндр, куб, конус и т.д. Геометрические параметры объектов могут изменяться, например, для цилиндра определяется высота и радиус основания. Кроме объектов определяется допустимый набор множественных операций, обычно это 3 объединение, пересечение, вычитание. Модель представляет собой дерево, листьями которой являются библиотечные объекты с заданными геометрическими параметрами, а узлы соответствуют операциям. Пример модели построенной на принципах конструктивной объемной геометрии приведен на рисунке 1.2. Кроме геометрического описания объекта, в модели может храниться дополнительная информация о его свойствах или свойствах его составляющих. Например, это информация о цвете объекта, фактуре его поверхности или других свойствах, необходимых при создании реалистического образа объекта, а так же решения других прикладных задач. Остановимся подробнее на том, каким образом формируется плоское представление трехмерной модели. В настоящее время большинство устройств вывода графической информации используют растровый принцип создания изображений. Следовательно, графические системы на выходе должны формировать растровый образ модели. Растр – это массив простейших элементов – пикселей. Каждый пиксель имеет строго определенное положение и одно единственное свойство – цвет. Массив кодов, определяющих цвет пикселей, хранится в специальной области памяти компьютера, называемой буфером кадра. Глубина буфера кадра говорит о количестве бит, выделенном для хранения информации об одном пикселе. Для черно-белого (в общем случае двух градационного) изображения достаточно буфера глубиной один бит. Восьми битный буфер позволяет использовать 256 цветов. Современные системы используют буфер кадра глубиной 24 бита и более. Способы кодирования информации о цвете и цветовые модели мы рассмотрим в одной из последующих лекций. Рассмотрим монитор с электронно-лучевой трубкой, который является типичным представителем устройств вывода графической информации, формирующих изображение на основе растра. Рисунок 1.4. В состав трубки входит электронная пушка, фокусирующая система, отклоняющая система, теневая маска и экран, покрытый слоем люминофора. Поток электронов, испускаемый электронной пушкой проходя через фокусирующую систему, образует тонкий луч, который направляется отклоняющей системой. Луч направляют таким образом, чтобы он последовательно пробегал весь экран строку за строкой. Экран покрывают точками люминофора, который начинает светиться под воздействием потока электронов и сохраняет постсвечение в течение некоторого времени после ухода луча. В электронно-лучевых трубках способных воспроизводить цвет используют три электронных пушки и три типа люминофора, испускающих свечения трех основных цветов – красного, зеленого и синего. Каждый пиксель образуется тремя точками люминофора данных цветов. Теневая маска обеспечивает попадание луча, испускаемого каждой электронной пушкой, только на точки люминофора соответствующего цвета. Размер буфера кадра (количество кодов цвета, хранимое в буфере) должен совпадать с количеством пикселей на экране. При прохождении луча над пикселем из буфера кадра считывается соответствующий ему код, который используется для управления излучением электронных пушек. Синхронность считывания информации из буфера кадра с ходом луча обеспечивается специальным блоком синхронизации. Для того чтобы изображение не исчезло с экрана после окончание времени постсвечения люминофора, его надо непрерывно возобновлять – регенерировать, не менее 30 раз в секунду. Сегодня для представления графической информации используются не только электронно-лучевые трубки. Широкое распространение получили жидкокристаллические дисплеи, плазменные панели и другие устройства. Такие приборы также основываются на растровом принципе формирования изображения, но используют другие технологии. Рассмотрев форму представления исходных данных и результата, перейдем непосредственно к процессу визуализации. В большинстве современных графических систем данная задача решается с помощью графического конвейера. Классический графический конвейер – это последовательность шагов, обеспечивающая преобразование модель – сцена – двумерный образ. Графический конвейер можно представить в виде черного ящика, выполняющего необходимые преобразования, рисунок 1.5. Содержимое нашего черного ящика может быть различным. Выполняемые преобразования зависят от назначения графической системы, требуемого уровня 4 универсальности и многих других факторов. Поэтому мы рассмотрим некоторый абстрактный графический (иногда его называют видовым) конвейер, включающий в себя основные (наиболее часто используемые) преобразования. Структура такого конвейера приведена на рисунке 1.6. Первым этапом нашего конвейера является сборка сцены, выполняемая модельным преобразованием. Этот этап можно рассматривать как часть большого и сложного процесса называемого моделированием. В ходе сборки отдельные фрагменты сцены или модели собираются вместе в единой координатной системе, носящей название мировой системы координат. Необходимость такой сборки возникает из-за того, что отдельные модели удобнее описывать в собственных оригинальных системах координат. Посмотрим на рисунок 1.? а. Рассчитать координаты конечных точек отрезков, образующих рисунок довольно сложно. Однако, задачу можно существенно упростить, описав каждую модель в своей координатной системе, как это показано на рисунках 1.? Б и В. Такие персональные координатные системы носят название модельных координат. После этого достаточно для каждой модели задать необходимые повороты и переносы с тем, чтобы добиться требуемого положения объектов. Графическая система сама выполнит все необходимые расчеты, сведя объекты в единую мировую координатную систему. Изображение, формируемое компьютером, является искусственно созданным и оригинала может не существовать физически. Но при этом используются те же физические законы, которые работают при восприятии человеком реальных физических объектов. Поэтому в ходе курса мы будем часто проводить аналогии с такими «устройствами», как фотокамера или глаз человека. В любом процессе формирования изображения присутствуют две сущности: объект и наблюдатель. Объект существует в пространстве независимо от наблюдателя, следовательно, чтобы однозначно определить каким образом мы увидим сцену, необходимо определить положение наблюдателя, направление наблюдения и другие характеристики наблюдателя. Видовое преобразование (видовая трансформация) геометрического конвейера, обеспечивает требуемое расположение объекта и наблюдателя. Отображение трехмерного описания объекта на плоскость осуществляется с помощью преобразования проецирования. Как вам известно, человек видит мир в перспективе. Видимый размер одинаковых объектов уменьшается по мере увеличения расстояния от них до точки наблюдения. Перспективное зрение позволяет нам воспринимать глубину видимой сцены, оценивать расстояния до объектов. В графической системе мало реализовать только перспективное проецирование. В прикладных задачах часто необходимо точно оценивать истинные размеры объектов, поэтому наряду с перспективными проекциями, широкое применение находят параллельные проекции. Изображения, полученные с помощью параллельного проецирования, менее реалистичны, но дают возможность проводить линейные и угловые измерения (с некоторыми ограничениями). Следующим этапом геометрического конвейера является преобразование нормализации. В ходе преобразования геометрические координаты всех объектов сцены приводятся к фиксированному диапазону. Используемый диапазон может быть различным, например, [0..1] или [-1..1]. В результате нормализации координат решаются такие задачи как преодоление потери точности, защита от переполнения и другие задачи, связанные с реализацией системы. Когда мы смотрим вдаль, то видим все объекты до горизонта, т. е. человеческое зрение, в принципе, не имеет ограничений по глубине. Зона охвата нашего зрения представляет собой бесконечный конус. Реализация подобного механизма в компьютерной системе потребовала бы чрезвычайно больших вычислительных затрат. Поэтому в графических системах присутствует такое понятие как видимый объем. Это замкнутый объем пространства, попадая в который объекты сцены или их фрагменты оказываются видимыми в создаваемом изображении. Соответственно, те объекты или фрагменты, которые оказались вне этого объема, исключаются из дальнейшего рассмотрения. Процесс выделения объектов сцены, попавших в видимый объем, называется отсечением 5 (клиппингом - от английского слова clipping). Такой подход существенно повышает эффективность системы, т.к. существенно снижается количество геометрических примитивов, проходящих через весь конвейер. Форма видимого объема зависит от используемого типа проекций, обычно это параллелепипед или усеченная пирамида. Еще раз напомню, что мы рассматриваем некоторый гипотетический конвейер ради понимания принципов его работы. В реальных системах некоторые этапы могут быть опущены, переставлены местами или совмещены, исходя из соображений эффективности, удобства реализации или по другим причинам. Результатом рассмотренных выше преобразований может являться двухмерное изображения фрагмента сцены, однако, в большинстве систем это не так. На данном этапе мы не можем полностью отказаться от трехмерного представления. Это вызвано тем, что для работы алгоритмов удаления невидимых линий и поверхностей необходима информация о расстоянии от объектов до точки наблюдения (глубина по сцене). На основе этой информации принимается решение о видимости объектов или их фрагментов. Многие алгоритмы удаление невидимых линий и поверхностей работают на следующем этапе видового конвейера, поэтому результатом проецирования, как правило, является промежуточный 2D/3D образ. Аббревиатуры 2D и 3D, соответственно, произошли от английских словосочетаний two dimensional – двухмерный и three dimensional – трехмерный. В этом образе сочетается описание положения объектов на плоскости с дополнительными характеристиками, определяющими положение этих объектов по глубине сцены. В двумерной части сформированного образа все объекты представлены своими характеристическими (контрольными, управляющими) точками. Например, в модели трехмерный отрезок определяется двумя вершинами, определяющими его концы. Каждая вершина описывается тройкой координат. После проецирования двумерный образ нашего отрезка так же описывается парой вершин, каждая из которых характеризуются только двумя координатами. Для вывода изображения данного отрезка необходимо, основываясь на координатах его вершин, определить точки растра, наилучшим образом отображающие внутреннюю часть отрезка. Процесс формирования промежуточных точек графического образа объекта составляет основу растрового преобразования или просто – растеризации (rasterization, scan convertion). Как уже говорилось, параллельно с растеризацией, может решаться вопрос о видимости выводимых пикселей. Кроме того, на этом этапе выполняется закрашивание (shading). Для каждого пикселя изображения необходимо определить его цветовые характеристики. В реальном мире видимый цвет объекта зависит от свойств материала, из которого состоит его поверхность, характеристик падающего на него света и состояния окружающей среды (наличие тумана и др. факторов). Свет имеет волновую природу и физика процесса очень сложна. Реализация в графической системе модели, близкой к реальности, привела бы к огромным вычислительным затратам. На практике для закраски изображений используется ряд упрощенных моделей и подходов. Упрощенная модель освещения рассматривает отдельно рассеянный или диффузно отраженный свет и зеркально отраженный. Ключевыми параметрами, влияющими на процесс, являются интенсивности источников света и геометрические характеристики, такие как угол падения света и угол между направлением на наблюдателя и отраженным лучом света. Другие сложные факторы, влияющие на процесс, представляются константами, подбираемыми эмпирически – опытным путем. Безусловно, такое упрощение дает результаты далекие от совершенства. Для придания большей реалистичности создаваемым сценам используются разнообразные специальные методы, такие как текстурирование – наложение изображения на поверхность объекта, покрытие поверхности микрорельефом, создание иллюзии тумана, прозрачности и др. 6 Лекция 2 Аффины. Двумерные геометрические (аффинные) преобразования В этой лекции мы начинаем изучать математический аппарат машинной графики. В процессе визуализации объекта его необходимо представить в заданном масштабе, повернуть, переместить в требуемую позицию или выполнить другое более сложное преобразование в соответствии с требованиями решаемой задачи. Эти преобразования можно выполнить с помощью рассматриваемого ниже математического аппарата. Изучение мы начнем с более простых двумерных преобразований, а затем обобщим их, рассмотрев трехмерные преобразования. Представление точек использованием матриц и общая схема преобразования с Так как в компьютерной графике большинство объектов определяются с помощью точек или вершин, то начнем именно с них. Как известно, точка на плоскости представляется двумя своими координатами (x y). Эту пару можно представить в виде x y матрицы [x y] размером 1*2 называемой вектор-строка или матрицы размером 2*1 называемой вектор-столбец. Данные матрицы часто называют координатными векторами. В трехмерном пространстве, точка определяется тройкой координат, и координатный вектор увеличивают свой размер на единицу. Например, вектор-строка будет иметь размер 1*3 - [x y z] . Правила матричной алгебры определяют набор допустимых операций над координатным вектором. Если геометрическое преобразование представить в виде матрицы, то результат преобразования точки можно представить следующей формулой: Р*М = Р’ , где М – матрица геометрического преобразования; Р – вектор-строка представляющая исходную точку; Р’- вектор-строка полученная в результате преобразования. Другими словами мы представили применение геометрического преобразования как произведение матриц. Рассмотрим данное произведение подробнее. a b c d [(ax+cy) (bx+dy)] = [x’ y’] Р*М =[x y] т.е. координаты преобразованной точки формируются суммой исходных координат умноженных на соответствующие коэффициенты: x’= ax+cy; y’= bx+dy; Если в матрице преобразования a=d=1 и c=b=0 то x’= 1x + 0y = x; y’= 0x+1dy = y; 1 0 0 1 Результат преобразования совпадает с исходными значениями. Матрица соответствующая такому преобразованию называется единичной (т.е. квадратная матрица любого размера, главная диагональ, которой заполнена единицами). Умножение на такую матрицу подобно умножению на единицу в традиционной алгебре. Несмотря на кажущуюся 7 бесполезность, единичные матрицы находят широкое применение при работе с геометрическими преобразованиями. В ходе выполнения преобразований нам потребуется решать две задачи. Прямую задачу – находить координаты преобразованного объекта на основе координат исходного объекта и матрицы трансформации. Собственно ее решение рассмотрено нами выше. И обратную задачу – находить координаты исходного объекта на основе координат преобразованного объекта и матрицы трансформации. Р’* М-1 = Р , где М-1 - это матрица обратная к матрице трансформации. Методы получения таких матриц рассматриваются в матричной алгебре. Мы рассмотрим одно важное свойство такой матрицы. Если применить к объекту некоторое преобразование, а затем преобразование, обратное данному, то исходный объект останется неизменным. Р*М* М-1= Р Такой же эффект мы получали при умножении на единичную матрицу. Следовательно, произведение М* М-1 дает единичную матрицу. Преобразование масштабирования Вернемся к общей схеме преобразования и рассмотрим ряд частных случаев преобразования и их геометрический смысл. Положим c=b =0, a0 и d 0, тогда a 0 0 d [(ax+0y) (0x+dy)] =[(ax) (dy)]= [x’ y’] Р*М =[x y] Таким образом x’= ax y’= dy Следовательно, мы получили преобразование масштабирования. Коэффициенты a и d являются масштабирующими коэффициентами по осям x и y. Обычно их обозначают Sx и Sy, а соответствующая матрица носит название матрицы масштабирования. Sx 0 0 Sy S = Если 0 < Sx = Sy < 1 имеет место сжатие, в противном случае при Sx = Sy > 1 расширение. Обратите внимание, что при масштабировании геометрических объектов происходит не только изменение их размеров, но и смещение относительно начала координат. Начало координат остается инвариантным как к преобразованию масштабирования, так и к другим преобразованиям, выполняемым по рассматриваемой схеме. В этом легко убедится: a 0 0 d [(a*0+0*0) (0*0+d*0)] =[(0) (0)]= [0 0] [0 0] Если Sx Sy , то координаты масштабируются различным образом и происходит искажение пропорций объектов. Для обращения преобразования необходимо произвести масштабирование с коэффициентами, обратными заданным. Обратная матрица представляется следующим 0 1 / Sx 0 1 / Sy образом: S-1 = Интересный эффект возникает при разрешении отрицательных значений коэффициентов в матрице масштабирования. В этом случае, наряду с масштабированием, происходит отображение объектов относительно различных осей. Положим Sx = -2, а Sy = 1. 8 2 0 0 1 S= x’= -2*x y’= 1*y Очевидно, что координата y останется неизменной, а координата x увеличится вдовое и поменяет свой знак, т.е. наряду с масштабированием произойдет отображение относительно оси y. При единичных величинах коэффициентов масштабирования не будет, а знаки будут 1 0 0 1 определит отображение относительно оси определять оси отображения. Матрица 1 0 0 1 х, а матрица - отображение относительно оси y. Если отклониться от условий масштабирования, положив с = b =1 и a=d=0, тогда 0 1 1 0 [(0x+1y) (1x+0y)] =[(y) (x)]= [x’ y’] приведет к преобразование [x y] перестановке координат x’= y, y’= x, что геометрически можно представить как отражение относительно прямой x=y, делящей первый квадрант на октанты. 0 1 1 0 приводит к отображению относительно прямой y = -x. Преобразование Преобразование поворота 0 1 1 0 Его результат можно рассматривать Рассмотрим следующее преобразование. как поворот на 90 градусов против часовой стрелки относительно начала координат. 0 1 1 0 и 270 градусов Нетрудно определить другие частные случаи поворота: на 180 - 0 1 1 0 . Но как определить преобразование поворота относительно начала координат на произвольный угол? Рассмотрим схему такого поворота, представленную на рисунке 2.9. Введем следующие обозначения: r – радиус поворота. Отрезок ОР, соединяющий начала координат О с поворачиваемой точкой Р; - угол между осью x и начальным положением отрезка ОР; - угол, на который выполняется поворот. Определим начальное положение точки Р и ее положение после поворота Р’. Р = [x y] = [r cos r sin ] (1) Р’ = [x’ y’] = [r cos(+) r sin(+)] Применив формулы косинуса и синуса суммы, получим: Р’ = [x’ y’] = [r(cos cos - sin sin) r(sin cos + cos sin )] Раскрывая скобки и учитывая формулу (1) получаем: Р’ = [x’ y’] = [(xcos - y sin ) (x sin + y cos )] т.е. точка после поворота имеет координаты x’ = x cos - y sin y’ = x sin + y cos Переходя к матричному представлению, получаем матрицу преобразования поворота на произвольный угол относительно начала координат: 9 cos sin R = sin cos Для обращения преобразования необходимо выполнить поворот в противоположную сторону на тот же угол. cos (- ) sin(- ) sin(- ) cos(- ) = R-1 = cos sin - sin cos Преобразование переноса и однородные координаты В ходе обработки модели часто возникает необходимость переместить объект, не изменяя его размеров и формы. Такое перемещение обычно задается вектором, называемым вектором переноса. Его направление определяет направление переноса, а проекции на координатные оси задают перемещение вдоль этих осей. Такое преобразование можно представить следующим образом: x’ = x + dx y’ = y + dy, где dx и dy - проекции вектора на оси x и y. Рисунок 2.10. Определить такое преобразование в рамках рассмотренной выше схемы, использующей матрицу размером 2*2, не удается. Преодолеть данное затруднение можно с помощью перехода в однородные координаты. Точка на плоскости в однородных координатах определяется тройкой [X Y W], где W – масштабирующий коэффициент, а X и Y координаты точки, получаемые из декартовых координат посредством следующих соотношений X = x*W, Y = y*W. По однородным координатам с помощью деления на масштабирующий коэффициент всегда можно найти декартовы координаты. x = X/W, y = Y/W. Очевидно, что коэффициент не должен быть равен 0. Однородные координаты не обладают однозначностью. Точки [2 3 1], [4 6 2], [6 9 3] соответствуют одной и той же точке [2 3] в декартовых координатах. Рассмотрим однородные координаты при W = 1. В этом случае однородные координаты точки будут совпадать с декартовыми. Что же мы выиграли, увеличив размерность вектора? Мы увеличили размер матрицы преобразования. Общая схема преобразования в однородных координатах выглядит следующим образом: a b 0 c d 0 m n 1 Р*М =[x y 1] [(a*x+c*y+m) (b*x+d*y+n) (1)] = [x’ y’ 1] В рамках новой схемы мы легко можем представить как все рассмотренные ранее преобразования (для этого необходимо обнулить коэффициенты m и n), так и преобразование переноса. Коэффициенты m и n собственно и определяют величины перемещения по осям x и y. Матрица переноса представляется следующим образом: 1 0 0 0 1 0 dx dy 1 D= где dx и dy как уже говорилось, проекции вектора переноса. 1 0 0 0 1 0 dx dy 1 Р*D =[x y 1] [(1*x+0*y+dx) (0*x+1*y+dy) (1)] = [x’ y’ 1] 10 Для обращения преобразования необходимо выполнить перенос на те же величины, но в противоположном направлении. 0 0 1 0 1 0 dx dy 1 D= Обратите внимание. Начало координат не является инвариантным к преобразованию переноса. Все определенные ранее матрицы преобразований легко приводятся к размеру 3*3. Добавляем строку и столбец, заполненные нулями, а затем в главную диагональ, на место их пересечения ставим 1. S= Sx 0 0 0 Sy 0 0 0 1 R= cos - sin 0 sin cos 0 0 0 1 Выполнение произвольных преобразований на плоскости. Композиция преобразований Рассмотренные нами ранее преобразования поворота выполнялись только относительно начала координат. Так же и отражение проводилось только относительно специальных осей. Как же выполнить поворот вокруг произвольной точки, отражение относительно произвольной оси или масштабирование относительно произвольной точки? Ключевая идея состоит в приведении сложного преобразования к более простому частному случаю. Общая схема выполнения такого преобразования следующая: С помощью преобразований переноса, поворота и масштабирования преобразовать исходную сцену так, чтобы требуемое произвольное преобразование свелось к частному случаю, решение которого известно; Выполнить требуемое преобразование; Применить к сцене преобразования, обратные сделанным в первом пункте, что бы вернуть ее в исходное состояние. Рассмотрим данный подход на примере. Повернем отрезок, заданный своими конечными точками P1 и P2 , вокруг точки Р1 на угол 90 градусов. Как выполнить поворот объекта вокруг произвольной точки, мы не знаем. Однако нам известно как поворачивать объекты вокруг начала координат. На первом этапе преобразуем сцену так, что бы точка Р1 совпала с началом координат (в нашем случае сцена состоит только из одного объекта, но мы используем этот термин, чтобы не терять общности схемы). Для этого используем преобразование переноса, определяемое вектором, соединяющим точу Р1 с началом координат. x1 x2 Р’ = P*T = y1 1 y 2 1 Т где Р - матрица объединяющая координатные вектора конечных точек отрезка, а Т – матрица переноса. На втором этапе выполним поворот отрезка на требуемый угол. Р’’= P’R Где R – матрица поворота на угол 90 градусов относительно начала координат. Для преобразования сцены в исходное состояние применим трансформацию переноса, обратную использованной на первом этапе. Напомним, что обратный перенос формируется вектором, имеющим длину, равную вектору прямого переноса, но противоположным по направлению. В данном примере это вектор из начала координат в точку Р1. Получаем конечное положение отрезка. Р’’’ = Р’’T-1 11 Одной из главных причин использования представления преобразования в матричной форме является возможность получать сложные матрицы путем композиции более простых матриц. Или другими словами – мы можем получать матрицы сложных геометрических преобразований, перемножая матрицы элементарных преобразований, рассмотренных нами выше. Сведем рассмотренные преобразования в общую формулу Р’’’ = ((P*T)*R)*T-1 = P*T*R* T-1= P*M где матрица М является композицией (объединением, соединением, конкатенацией) матриц. Остановимся на свойствах композиции, в частности на коммутативности. В общем случае произведение матриц не коммутативно. То же можно сказать о композиции геометрических преобразований. В рассмотренном примере поменяем местами матрицы преобразования переноса и поворота K = P *R*T * T-1= P*R Таким образом, мы пришли к простому повороту относительно начала координат. А прямая и обратная матрицы переноса при умножении дали единичную матрицу, т.е. аннулировали преобразование. Полученные результаты преобразований не совпадают К Р’’’, следовательно, одни и те же матрицы в зависимости от порядка перемножения дают разные композиции. Кроме того, необходимо обратить внимание на порядок умножения координатного вектора на матрицы преобразования. Мы умножали вектор-строку на матрицу. В некоторых источниках встречается обратный порядок – проводится умножение матрицы преобразования на координатный вектор. Чтобы перейти к этому способу необходимо координатный вектор представить как вектор-столбец, а матрицу преобразования транспонировать. Другим примером использования рассмотренной схемы построения композиций может служить создание преобразования отражения относительно произвольной прямой. Для перехода к частному случаю достаточно переместить прямую так, что бы она проходила через начало координат и повернуть ее до совпадения с одной из главных координатных осей. Рассмотренные принципы построения композиций для сложных преобразований широко используются в машинной графике. Мы вернемся к нему при решении задач отсечения, удаления невидимых линий и др. Выводы по плоским геометрическим преобразованиям Подводя итог изучению двумерных преобразований, еще раз обратим внимание на структуру матрицы преобразования. a c e М = b d f k m s Элементы a,b,c и d определяют коэффициенты поворота, масштабирования и сдвига. Элементы е и f служат для формирования переноса. Смысл трех оставшихся элементов необходимо прояснить. Начнем с k и m. Обычно, мы устанавливали им нулевое значение. Теперь положим их отличными от нуля, элементы главной диагонали приравняем к единице, а остальные элементы обнулим. Применим получившееся преобразование к произвольной точке заданной в однородных координатах с w =1. 1 0 k 0 1 m 0 0 1 [x’ y’ w’] = [x y 1] = [x y kx+my+1] x’ = x, y’=y Для того, чтобы понять результат, обратимся к геометрической интерпретации однородных координат. Точка в однородных координатах определяется тройкой, 12 следовательно, мы имеем дело с трехмерной координатной системой, определенной в пространстве. Две оси системы нам привычны это X и Y, а третья – W, ось масштабных коэффициентов. Зафиксировав значение W, установив его равным единице, мы перешли от пространства к плоскости параллельной плоскости XOY. Установив элементы k и m отличными от нуля, мы сняли данное ограничение и полученная в результате преобразования точка расположена в пространстве. При этом ее третья координата определяется по формуле kx+my+1 т.е. зависит от значений x и у. Следовательно, точки, подвергшиеся данному преобразованию, будут лежать в некоторой плоскости не параллельной плоскости XOY. Вернем точку на плоскость W=1 путем проецирования лучами, проходящими через начало координат. Из подобия треугольников x’’= x’/w’= x/( kx+my+1) и аналогично y’’= y’/w’= y/( kx+my+1). Таким образом, математически подобное проецирование выразится в простой нормализации. x kx my 1 [x’’ y’’ 1] = y 1 kx my 1 Для выяснения смысла элемента s матрицы преобразования, проведем рассуждения по аналогичной схеме. Умножим произвольную точку на соответствующую матрицу с ненулевым значением s. 1 0 0 0 1 0 0 0 s [x y 1] = [x y s] Все точки, подвергшиеся такому преобразованию будут лежать в плоскости W=s которая параллельна плоскости W=1. Нормализация будет приводить к простому масштабированию с одинаковыми коэффициентами по осям. x [x’ y’ 1] = s y 1 s Основное отличие такого масштабирования от рассмотренного ранее состоит в том, что при s<1 будет происходить растяжение, а при s>1 – сжатие. Трехмерные преобразования При переходе в пространство добавляется координата Z и, следовательно, размерность матриц увеличивается на единицу. Точки в пространстве представляются четверками [x y z 1], размерность матриц преобразований становится 4*4. В главную диагональ матрицы масштабирования добавляется масштабирующий коэффициент по оси Z, а в матрицу переноса добавляется проекция вектора переноса на ось Z. Отображение в пространстве производится относительно плоскостей. Так при отображении относительно плоскости XOY поменяют знаки только координаты Z. Матрица такого преобразования будет выглядеть следующим образом. М = Аналогично для других плоскостей. С поворотами ситуация более сложная. 1 0 0 0 0 0 1 0 0 1 0 0 0 0 0 1 . Преобразования поворота в пространстве Повороты в пространстве производятся вокруг осей. Рассмотрим повороты вокруг главных координатных осей. Положительными считаются повороты против часовой стрелки, если смотреть с конца положительной полуоси. Изученный нами ранее поворот 13 относительно начала координат на плоскости XOY можно рассматривать как поворот в пространстве относительно оси Z. Для получения матриц поворота относительно других координатных осей можно использовать ту же схему рассуждений, что приводилась нами для определения поворота на плоскости XOY. Повороты вокруг произвольных осей строятся за счет композиции поворотов вокруг главных координатных осей. Схема такого подхода нами уже разбиралась. Применим ее на практике еще раз. Сначала уточним исходные данные. Для задания произвольного поворота в пространстве недостаточно определить только ось. При этом невозможно определить направление поворота. Необходимо задать направляющий вектор и точку его привязки. Так же необходимо задать величину угла поворота . Для выполнения заданного преобразования необходимо: Совместить точку привязки с началом координат за счет преобразования переноса Т, задаваемого вектором, соединяющим начало координат с этой точкой. Выполнить поворот вокруг оси X на угол , переводящий направляющий вектор в плоскость XOZ . Выполнить поворот вокруг оси Y на угол , совмещающий направляющий вектор с положительной полуосью Z. Выполнить поворот вокруг оси Z на требуемый угол . Выполнить обратные преобразования, приводящие сцену в исходное состояние. Коммутативность преобразований Преобразования как изменение координатных систем На первой лекции мы рассматривали геометрический конвейер и говорили о различных координатных системах и переходах между ними. В данной лекции мы говорим о преобразованиях геометрических объектов. Как же устранить данное противоречие? Рассмотрим любое преобразование объекта, например перенос точки. Перенесем точку в соответствии с заданным вектором. Точка Р с координатами (2 3) преобразуется в точку Р’ с координатами (4 5). Данную ситуацию можно трактовать иначе. Точка осталась неизменной, а изменению подверглась координатная система. Таким образом, мы с помощью преобразования сдвига преобразовали координатную систему С1 в координатную систему С2. Такой взгляд можно рассматривать как метафору, потому что для реализации перевода сцены из одной координатной системы в другую необходимо подвергнуть преобразованию каждый объект сцены. Мы используем такую нотацию, так как в терминах координатных систем и их преобразований легче объяснять устройство и работу графических систем, а так же писать программы. В этом мы убедимся позже при написании программ с использованием OpenGL. Рассмотрим еще один пример. В исходной координатной системе С1 с помощью преобразования масштабирования ( Sx=0.5 Sy=0.5 ) определим координатную систему C2=C1*S21. На ее основе с помощью преобразований переноса (Dx=4 Dy=2) и поворота (=45є) определим координатную систему C3=C2*T23*R23. С учетом композиции запишем С3=С2*M23 Очевидно, что отношения между координатными системами С3 и С1 описываются формулой C3= C1*S21*T23*R23 =С1*М31. Таким образом, мы определили три координатные системы и установили отношения между ними. Нарисуем в координатных системах С2 и С3 два одинаковых домика и перейдем в координатную систему С1. Изображения подверглись масштабированию, повороту и смещению согласно установленных нами отношений. Этот простой пример демонстрирует важный этап визуализации – сборку сцены. В процессе сборки мы определяем фрагменты сцены в координатных системах, удобных для построения. Обычно такие координатные системы в графическом конвейере носят название модельных координат. В некоторых источниках, дающих более строгое математическое обоснование, используют термин фрейм. 14 После определения всех необходимых фрагментов производят преобразование всех модельных координатных систем в единую систему, носящую название мировых координат. 15 Лекция 3. Двумерный конвейер. Координатные системы двух конвейера и их преобразование мерного геометрического Мы рассмотрели набор базовых геометрических преобразований на плоскости и в пространстве. Теперь перейдем к рассмотрению основного механизма визуализации – геометрического конвейера. Почему собственно конвейер? С этим словом, у нас ассоциируется Генри Форд, впервые применивший конвейер при производстве автомобилей. Геометрический конвейер использует главный принцип любого конвейера – параллельность выполнения всех этапов технологического цикла. Так же как на сборочном конвейере крупного завода одновременно находятся десятки автомобилей на разной стадии готовности, в геометрическом конвейере могут одновременно обрабатываться несколько сцен. Когда одни из них только собираются, другие могут растеризоваться и демонстрироваться пользователю. Более того, составляющие одной сцены могут обрабатываться параллельно на разных ветках конвейера. Знакомство начнем с двумерного конвейера, имеющего относительно простую внутреннюю структуру, так как все преобразования выполняются на плоскости и проецирование отсутствует. Модельные координаты опустим в силу того, что были рассмотрены нами ранее и в некоторых источниках явно не выделяются. В двухмерном видовом конвейере используются декартовы системы координат, их три: Мировые координаты (World coordinate - WC). Координатная система пользователя. Используется прикладным программистом для описания графического ввода и вывода, ее размеры зависят от реальных размеров моделируемых объектов. Нормализованные координаты устройства (Normalize device coordinate - NDC). Независимая от устройств декартова система координат, приведенная к диапазону от 0 до 1. Используется для хранения данных, обеспечивает защиту от переполнения и потери точности. Координаты устройства (Device coordinate – DC). Координатная система, определяемая конкретным устройством вывода графической информации. WC Преобразование нормализации NDC Преобразование устройства DC Устройство вывода графической информации в большинстве случаев имеет ограниченное рабочее пространство прямоугольной формы. Следовательно, мы не можем произвести вывод всех объектов, произвольно расположенных в координатной системе устройства. Часть объектов может оказаться за пределами рабочего пространства. Для преодоления данной проблемы определим в координатной системе устройства прямоугольную область и введем ограничение – на устройство будут выведены только примитивы, попавшие в заданную область. Это прямоугольник носит название поля вывода (ViewPort). Поле вывода не обязательно должно занимать всю рабочую область устройства. Например, мы можем определить в рабочей зоне устройства несколько непересекающихся полей вывода с тем, чтобы создать в них различные изображения (в принципе, можно и пересекающиеся, но это уже спецэффекты). Введение данного ограничения делает нецелесообразным преобразование всех объектов сцены из одной координатной системы в другую. Зачем делать лишнюю работу, преобразовывая объекты, которые не попадут в поле вывода? Зададим в исходной координатной системе прямоугольную область, называемую окном (Window). Объекты или 16 части объектов, принадлежащие этой области, необходимо подвергнуть преобразованию. Объекты и части объектов, не принадлежащие этой области, необходимо исключить из рассмотрения. Данная операция носит название отсечения (clipping). Таким образом, мы пришли к следующему: преобразование на плоскости между координатными системами задается двумя прямоугольниками: окном и полем вывода. DC NDC Window2 WC ViewPort2 1Window ViewPort1 Window Window1 В рассматриваемом нами конвейере два преобразования: WC – NDC (из Window1 во ViewPort1) и NDC – DC (из Window2 во ViewPort2). Оба преобразования выполняются по одинаковой схеме. Рассмотрим ее. Определим, как найти в поле вывода точку, соответствующую точке, заданной в окне. Для этого используем простую пропорцию Х координату поля вывода X v X v. min X w X w. min X v X v. min X w. max X w. min X v. max X v. min X v. max X v. min ( X w X w. min ) X w. max X w. min в этой формуле выражение X v. max X v. min X w. max X w. min X v X v. min S x ( X w X w. min ) коэффициент. X v X v. min S x X w S x X w. min X v S x X w X v. min S x X w. min очевидно, через Х откуда, выразим координату окна можно рассматривать как масштабирующий что X v. min S x X w. min формируют перенос. Обозначив его как Тх, приходим к конечной формуле простой X v S x X w Tx . Проведя аналогичные рассуждения можно получить формулу для координаты Y И переходя к матричной форме Pv=PwST=PwM Yv S y Yw T y . Sx 0 0 0 Sy 0 Dx Dy 1 [x’ y’ 1] = [x y 1] Обратное преобразование, из поля вывода в окно, нам потребуется для выполнения лабораторных работ. Его необходимо найти самостоятельно. 17 Обратите внимание на то, что прямоугольники, определяющие окно и поле вывода должны быть подобны, т.е. иметь одинаковые пропорции между высотой и шириной (подобны), в противном случае масштабирующие коэффициенты по осям x и y будут различны. Следовательно, будут нарушаться пропорции всех отображаемых объектов. С введением рассмотренных ограничений наш конвейер приобрел новые полезные свойства. Для упрощения примера, зафиксируем размер поля вывода и будем производить изменения окна. При переносе окна мы видим различные фрагменты сцены, т.е. происходит «прокрутка» изображения в поле вывода. При изменении размеров окна происходит изменение масштаба выводимого изображения, естественно с изменением видимой области фрагмента. Подобным образом в графических системах реализуется функция изменения масштаба (Zoom). Сложность возникает в интерактивных системах, где пользователь задает область сцены, которую хочет видеть увеличенной. Так как поле вывода зафиксировано, видимая область определяется только окном. Следовательно, пользователь задает образ нового окна, но делает это в координатах устройства. Для того, чтобы определить новое преобразование надо преобразовать образ окна из координат устройства в исходные координаты (в нашем случае в нормализованные). Сделать это можно с помощью преобразования, обратного рассмотренному преобразованию. Y Окно Window Y Поле вывода ViewPort (Xv.max,Yv.max) (Xw.max,Yw.max) (Xv,Yv) (Xw,Yw) (Xv.min,Yv.min) (Xw.min,Yw.min) O X X O 18 Лекция 4. OpenGL. Что такое OpenGL – дословно, Open Graphics Library, открытая графическая библиотека. OpenGL включает в свой состав около 200 команд. Набор команд и их интерфейс определяется стандартом, разработанным фирмой Silicon Graphics. Существует много реализаций этой библиотеки, отличающихся операционной системой, языком программирования, для которого они предназначены, и авторами. Если вас не устраивает конкретная реализация, вы можете создать собственную, более эффективную. Большинство реализаций OpenGL использует одинаковую последовательность стадий обработки выводимого изображения, которая называется конвейером визуализации OpenGL. Данный порядок не является обязательным, но может служить для изучения принципов работы конвейера. Основное предназначение OpenGL - программирование трехмерной графики. С ее помощью вы можете визуализировать каркасные модели, закрашивать их, удалять невидимые линии и поверхности, освещать одним или несколькими источниками, создавать тени, накладывать текстуры и многое другое. Однако, данная библиотека не является полноценным ядром графической системы, так как основное внимание уделено процессу визуализации. Две другие немаловажные компоненты - ввод информации и ее хранение, практически отсутствуют. Стандарт OpenGL не определяет концепций графического ввода и хранения графической информации. Прикладному программисту приходится реализовывать эти функции самому или использовать дополнительные библиотеки, расширяющие возможности OpenGL. Среди наиболее известных: библиотека утилит OpenGL (GLU OpenGL Utility Library), инструментарий утилит библиотеки OpenGL (GLUT – Graphics Library Utility Toolkit) расширение OpenGL для X Window System (GLX – OpenGL Extention to the X Window System), библиотека для работы с оконной системой MS Windows (GlAux – OpenGL Auxilary) и другие. Синтаксис команд OpenGL Обычно команды OpenGL реализуются в виде процедур или функций. Их имена начинаются с префикса gl, затем следует название команды, в котором каждое слово начинается с большой буквы. Это особенно важно для языков, учитывающих регистр букв в тексте программы, например для Java. После названия может присутствовать суффикс, определяющий количество и тип параметров. Так команда, определяющая вершину, может иметь несколько реализаций. Например: glVertex2f – задает вершину на плоскости, имеет два параметра каждый из которых представляет собой 32-разрядное число с плавающей точкой; glVertex3i – задает вершину в пространстве, имеет три параметра каждый из которых представляет собой 32-разрядное целое число. В общем виде интерфейс команды можно определить следующим образом: glCommandName[1 2 3 4][b s i f d ub us ui][v](список параметров), где CommandName – имя команды; [1 2 3 4] – допустимые значения числа аргументов команды; [b s i f d ub us ui] – допустимые типы аргументов: Симв Тип OpenGL Описание ол b GLbyte 8 разрядов, целое s GLshort 16 разрядов, целое i GLint,GLsizei 32 разряда, целое f GLfloat 32 разряда, плавающая точка d GLdouble,GLcla 64 разряда, плавающая 19 mpd ub GLubyte,GLbool ean us GLushort ui GLuint,LGenum точка 8 разрядов, беззнаковое целое 16 разрядов, беззнаковое целое 32 разряда, беззнаковое целое Появление в суффиксе символа v означает, что в качестве аргумента используется указатель на массив. Количество и тип элементов массива определяется другими символами суффикса. При написании программ можно использовать соответствующие типы данных используемого языка программирования, но лучше этого не делать. Используя только типы данных, объявленные в OpenGL, вы обеспечиваете переносимость кода между различными реализациями библиотеки и избегаете ряда ошибок, вызванных неправильно установленным соответствием типов. Конкретные реализации библиотек могут отклоняться от приведенной схемы использования суффиксов. Некоторые языки программирования поддерживают перегрузку процедур (overload), родовые функции (generic function) или иной механизм, позволяющий создавать несколько реализаций одной процедуры, различающихся типом и количеством параметров. В реализации библиотек для этих языков суффиксы могут быть опущены. Если команды принадлежат библиотекам, расширяющим возможности OpenGL, то они имеют префиксы, отражающие название библиотеки. Например, команды, начинающиеся с префикса glu или glut, находятся, соответственно, в библиотеках GLU или GLUT. Мы будем использовать команды из этих библиотек для сокращения объема вспомогательного кода в примерах. Константы в OpenGL начинаются с префикса GL и пишутся заглавными буквами. Но, в отличие от команд, слова в имени константы разделяются символами подчеркивания. Префикс также отделяется от имени. Примерами могут служить константы GL_LINE_STRIP и GL_COLOR_BUFFER_BIT. Настройка библиотеки Как уже говорилось, работа OpenGL основана на базе конвейера визуализации. Позднее мы будем подробно рассматривать большинство этапов этого конвейера. Для начала, абстрагируясь от деталей, представим его в виде черного ящика, на вход которого подается описание моделей в виде совокупности геометрических примитивов, а на выходе, в буфере кадра, получается двумерный образ сцены. Очевидно, что конвейер должен работать в различных режимах: закрашивать образы моделей или оставлять их каркасными, учитывать освещение или нет, использовать сглаживание или оставлять линии ступенчатыми и многих других. Представим, что в нашем черном ящике скрывается конечный автомат. Следовательно, исходя из свойств автомата, мы можем сказать следующее: Существует множество возможных состояний; При изменении состояния автомата изменяются выполняемые им преобразования; Существует некоторое начальное состояние автомата. Состояние нашего автомата определяется совокупностью значений переменных. Назовем их переменными состояния. Для каждой из них определено значение по умолчанию (начальное значение, заносимое в переменную при инициализации библиотеки). Совокупность этих значений определяет начальное состояние автомата. Некоторые из переменных принадлежат к логическому типу и их значения показывают, включен или нет один из режимов. Как правило, изменение значений этих переменных производится с помощью команд glEnable() – разрешить и glDisable() – запретить. Например, команда glEnable(GL_LINE_SMOOTH) переводит систему в состояние (включает режим), в котором производится сглаживание линий. 20 Другие переменные определяют свойства преобразований. Они хранят числа, вектора и даже матрицы. Значения таких переменных устанавливаются различными специальными процедурами. Так команда glСolor3f(0.5, 0.5, 0.5) изменяет текущее значение переменной, отвечающей за цвет выводимых примитивов. В любой момент времени можно запросить у системы текущие значения переменных состояния. Для этого используется одна из команд начинающаяся с glGet, например, glGetBoolean(), glGetFloatv(), glGetError(). Полный список переменных состояния, значения по умолчанию и связанные с ними команды можно узнать в справочном руководстве. Часто мы хотим временно изменить значение переменных. Для этого опрашиваем и запоминаем текущее состояние, устанавливаем новое, затем производим вывод и восстанавливаем исходное состояние. Для облегчения данной процедуры и увеличения эффективности работы в библиотеке предусмотрен стек атрибутов. Занести значения в стек можно при помощи команд glPushAttrib() и glPushClientAttrib(), а для восстановления из стека используются команды glPopAttrib() и glPopClientAttrib. Отдельно остановимся на переменных, определяющих матричные преобразования. В OpenGL используются четыре матрицы: Матрица видового преобразования - GL_MODELVIEW; Матрица проецирования - GL_PROJECTION; Матрица текстуры - GL_TEXTURE; Матрица цвета – GL_COLOR_MATRIX. По умолчанию все матрицы являются единичными. С каждым типом матриц связан свой стек. Текущей является матрица, находящаяся в вершине стека соответствующего типа. Количество матриц, которые можно поместить в стек, зависит от типа матрицы и конкретной реализации библиотеки. Механизм доступа к матрицам единый, следовательно, для того, чтобы изменить конкретную матрицу, нужно установить режим изменения матриц этого типа с помощью команды glMatrixMode(). Так команда glMatrixMode(GL_MODELVIEW) выбирает для изменения матрицу видового преобразования. Рассмотрим некоторые разрешенные операции: glLoadIdentity() - заменяет текущую матрицу выбранного типа единичной; glPushMatrix() - заносит в стек копию текущей матрицы. glPopMatrix() - извлекает матрицу из стека, делая ее текущей (можно рассматривать как удаление верхней матрицы из стека). Задание аффинных преобразований Начнем с команды, определяющей преобразование масштабирования glScale[f d] (sx, sy, sz). Здесь, может возникнуть недоразумение. Из названия интуитивно кажется, что эта команда должна выполнять масштабирование геометрических примитивов, но мы только настраиваем конвейер и о примитивах даже не упоминали! Все правильно, в OpenGL мы сначала задаем требуемые преобразования, а затем указываем примитивы, которые должны им подвергнуться. Данная команда формирует матрицу масштабирования относительно начала координат S, перемножает ее с текущей матрицей M, и заменяет текущую матрицу полученным результатом. То есть выполняет композицию M=M*S. Обратите внимание на то, что схема композиции отличается от рассмотренной нами. Сравним схемы. Наша схема p’= ((p*M1)*M2)*M3. Схема OpenGL p’= M3*(M2*(M1*p)). Очевидно, что основное отличие в порядке включения матриц в композицию. В OpenGL преобразования будут выполняться в порядке обратном порядку их объявления, т.е. трансформация, объявленная первой, будет применена к объекту последней. Такой подход оказывается более удобным при создании сцен, в чем мы убедимся при рассмотрении примера программы. Еще раз оговорим, что данная команда изменяет текущую матрицу выбранного типа. Обычно это матрица видового преобразования - GL_MODELVIEW, так как мы чаще всего используем геометрические преобразования для сборки модели. Однако если вы выберете текущим типом матрицу проецирования, то произойдет композиция преобразования масштабирования с преобразованием проецирования. Необходимо обладать глубокими 21 знаниями принципов работы геометрического конвейера, чтобы получить осмысленный результат от такого действия. Остальные команды работают по той же схеме. glRotate[f d](angle, x, y, z) - рассчитывает матрицу поворота на угол angle относительно вектора, определяемого тройкой (x, y, z), с точкой привязки в начале координат. glTranslate[f d] (x, y, z) – рассчитывает матрицу переноса на вектор, определяемый тройкой (x, y, z), с точкой привязки в начале координат. Координатные системы OpenGL безусловно предназначена для работы с трехмерными моделями. Но знакомиться с принципами моделирования проще, манипулируя объектами на плоскости (мы без труда распространим полученные знания на пространственные модели). Поэтому, по возможности, отложим рассмотрение работы с 3D графикой до изучения принципов проецирования. Как мы уже знаем, двумерный видовой конвейер должен выполнять преобразование объектов из окна в поле вывода. Давайте приоткроем черный ящик и заглянем внутрь его. Основные внутренние преобразования и координатные системы, используемые при обработке вершин, представлены на рисунке 4.1. Проецирование и перспективное деление будут рассматриваться нами детально на следующих лекциях. Поэтому не будем на них останавливаться, отметим только, что в видовом конвейере OpenGL эти преобразования включают в себя преобразование нормализации. Координатная система устройства вывода нам уже знакома. Так как устройством вывода изображения чаще всего является окно, предоставляемое операционной системой, то для данных координат используют термин – оконные координаты. Именно в них определяется поле вывода. Описания объектов, поступая в конвейер, подвергаются видовому преобразованию, выполняемому с помощью одноименной матрицы. Видовое преобразование в конвейере OpenGL несет двойную нагрузку. Оно включает в себя преобразование модели и собственно видовое преобразование. Остановим наше внимание на преобразовании модели (видовое преобразование будет рассмотрено позже, согласно договоренности). С помощью данного преобразования мы можем произвести сборку сцены. Матрица видового преобразования (в данном контексте можно читать как матрица модельного преобразования) формируется не только перед выводом объектов, но и в его ходе. Следовательно, разные объекты или группы объектов могут преобразовываться поразному. Другими словами, мы можем определить фрагмент сцены в собственных координатных системах, а за счет данного преобразования свести их вместе в единую координатную систему. В этой координатной системе определяется окно конвейера, задающее область видимости. Только попадающие в окно объекты или их фрагменты пройдут обработку в конвейере и будут отображены в поле вывода. Обычно собственные координатные системы фрагментов носят название модельных координат, а единая координатная система называется мировой системой координат. В OpenGL за счет двойной нагрузки на видовое преобразование мировые координаты названы видовыми. Задание векторных примитивов В OpenGL векторными примитивами являются точки, линии и многоугольники. Они описываются в терминах их вершин – совокупностей координат. Как мы знаем, в разных координатных системах вершина может описываться парой, тройкой или четверкой координат. Смысл используемых понятий точки, линии и многоугольника отличается от математического. Это связано с ограниченными возможностями машинных вычислений, в частности с округлением и растеризацией. Под термином прямая имеется ввиду отрезок прямой, а многоугольник обязательно должен быть выпуклым. Область называется выпуклой областью, если отрезок, соединяющий любые две ее точки, полностью находится внутри этой области. 22 Предоставляемый библиотекой набор примитивов является достаточным для создания сложных моделей. Любые кривые или поверхности могут быть получены путем аппроксимации. В прикладных программах, использующих OpenGL, каждый геометрический объект описывается как упорядоченный набор вершин. Вершины задаются командой glVertex[2 3 4][s i f d](координаты) glVertex[2 3 4][s i f d][v](координаты). Набор вершин ограничивается операторными скобками glBegin(mode) и glEnd(), а тип объекта, который он определяет, задается параметром mode. glBegin(); Команды задания вершин и их атрибутов, например цвета glEnd; mode – вид примитива, может принимать следующие значения: GL_POINTS – каждая вершина задает точку. Вершина n задает точку n. Всего будет выведено N точек; GL_LINES – две вершины образуют отрезок прямой линии. Вершины 2n-1 и 2n задают линию n. Всего будет выведено N/2 линий. Если число вершин нечетно, то последняя игнорируется; GL_LINE_STRIP - последовательность соединенных отрезков прямых, называемых полилинией. Вершины n и n+1 задают линию n. Всего будет выведено N-1 линий; GL_LINE_LOOP - замкнутая полилиния. Вершины n и n+1 задают линию n. Вершины N и 1 задают последний отрезок полилинии. Всего будет выведено N линий; GL_TRIANGLES - тройка вершин образует независимый треугольник. Вершины 3n-2, 3n-1 и Зn задают треугольник n. Если число вершин не кратно 3, то оставшиеся (одна или две) вершины игнорируются. Всего отобразится N/3 треугольников; GL_TRIANGLE_STRIP - связанные треугольники. Треугольник задается каждой вершиной, начиная с третьей. Для нечетного n вершины n, n+1 и n+2 задают треугольник n. Для четной вершины n вершины n+1, n и n+2 задают треугольник n. Всего будет выведено N - 2 треугольников; GL_TRIANGLE_FAN - веер треугольников. Треугольник задается каждой вершиной, начиная с третьей. Вершины n, n+1 и n+2 задают треугольник n. Всего будет выведено N-2 треугольников; GL_QUADS - четверка вершин задает независимый четырехугольник. Вершины 4n-3, 4n-2, 4n-1 и 4n задают четырехугольник n. Если число вершин не кратно 4, то оставшиеся (одна. две или три) вершины игнорируется. Всего нарисуется N/4 четырехугольников; GL_QUAD_STRIP - связанные четырехугольники. Четырехугольник задается для каждой, кроме двух первых, пары вершин. Вершины 2n-1, 2n, 2n+2 и 2n+1 задают четырехугольник n. Всего отобразится (N-2)/2 четырехугольников. Заметим, что порядок сборки связных четырехугольников отличается от порядка, применяемого для независимых четырехугольников; GL_POLYGON – вершины от 1 до N задают один многоугольник. Порядок соединения вершин. Вершины Порядок соединения вершин разного вида треугольников и четырехугольников приведен на рисунках ХХХХХХ. 23 4 2 4 2 2 6 3 5 6 1 3 3 5 4 1 5 1 6 б) а) в) Рисунок - Порядок обхода вершин при построении треугольников: а) – независимые треугольники; б) – связанные треугольники; в) – веер связанных треугольников Режим формирования независимых треугольников - GL_TRIANGLES (рисунок ХХ, а) очевиден – берутся тройки вершин и соединяются между собой. В режиме формирования связанных треугольников - GL_TRIANGLE_STRIP (рисунок ХХ, б) входящие в примитив треугольники составляют единую группу, в которой каждая пара соседних треугольников имеет общую сторону. В режиме формирования веера связанных треугольников - GL_TRIANGLE_FAN (рисунок ХХ, в) входящие в примитив треугольники также образуют единую группу, но при этом все входящие в нее треугольники имеют общую вершину. 2 1 5 3 4 а) 4 6 2 8 7 6 1 5 3 8 7 б) Рисунок – Порядок обхода вершин при построении четырехугольников: а – независимые четырехугольники; б – связанные четырехугольники Общая схема формирования сцены с помощью библиотеки OpenGL будет включать в себя следующие этапы: 1. Инициализация библиотеки; 2. Задание общих параметров сцены; 3. Задание параметров фрагмента сцены; 4. Вывод описания фрагмента; 5. Повторение пунктов 3 и 4 до полного формирования сцены; 6. Закрытие библиотеки. При инициализации библиотеки обязательно устанавливается связь с устройством вывода, обычно это окно, предоставляемое операционной системой. Для нормальной работы необходимо получить контекст устройства, настроить для него параметры, связанные с обработкой пикселей (в основном это параметры используемых при 24 формировании буферов), создать контекст воспроизведения OpenGL и установить его текущим для данного устройства. Мы не будем вникать в детали такой настройки и ограничимся использованием процедуры InitOpenGL из библиотеки GLUtils. Как мы уже знаем, большинство переменных состояния конвейера имеет значение по умолчанию и изменение их значений можно производить только при необходимости. Однако, ряд свойств требует обязательной настройки. Прежде всего, это поле вывода и окно. От данных свойств, как вы знаете, зависит выполнение геометрических преобразований в конвейере. Поле вывода задается явно, специальной командой glViewPort. Окно преобразования определяется неявно в команде, определяющей тип проекции. Более того, поскольку библиотека рассчитана на работу с объемом, окно самостоятельно не определяется и не используется, а является составной частью определения видимого объема, но об этом речь пойдет позже. Значения этих свойств, как впрочем, и любых других, могут изменяться программистом в ходе формирования сцены. Другими свойствами, часто устанавливаемыми для всей сцены в целом, являются характеристики источников света, цвет фона и т.п. Собственно процесс формирования сцены сводится к описанию составляющих ее объектов в терминах примитивов OpenGL. Перед заданием описания примитива вы можете изменять любые свойства конвейера, чтобы достичь желаемого внешнего вида и положения объекта на сцене. Обратим особое внимание на определение положения объектов. Вы можете рассчитать координаты вершин, образующих объекты сцены, в мировой системе координат и таким образом избежать процесса сборки сцены. Но такой подход имеет два существенных недостатка: Большой объем предварительных вычислений, выполняемых вручную; Сложность изменения взаимного расположения объектов сцены. При любом изменении требуется перерасчет координат всех вершин, определяющих объект. Рассмотрим реализацию процесса сборки сцены с помощью конвейера OpenGL. Композиция всех геометрических преобразований, определяемых пользователем, накапливается в матрице видового преобразования. Следовательно, можно сказать, что связь между мировой координатной системой и координатной системой, в которой будет описываться вывод в данной точке программы, определяется состоянием матрицы видового преобразования (композицией преобразований накопленных в матрице к моменту достижения данной точки программы). Например, если мы выполним команду glLoadIndentity, предварительно установив текущей матрицу видового преобразования, то можно сказать, что вывод будет производиться в координатной системе, совпадающей с мировой. Если после этого с помощью команды glTranslate сформировать преобразование переноса на вектор T, то вывод будет осуществляться в новой координатной системе, начало которой сдвинуто относительно начала мировой системы координат на вектор Т. Таким образом, каждое геометрическое преобразование, определенное в программе можно рассматривать как переход к новой координатной системе (в некоторых источниках для таких систем используется термин фрейм). Часто взаимосвязь между координатными системами устанавливается с помощью последовательности геометрических преобразований поворота, переноса и масштабирования. В этом случае всю последовательность можно рассматривать как один переход, игнорируя не используемые промежуточные системы. Рассмотрим небольшой пример, иллюстрирующий вышесказанное. 25 Лекция 5. Проекции Проекции Процесс вывода трехмерной графической информации сложнее соответствующего двумерного процесса. В двумерном случае просто задаются окно в двумерном мировом координатном пространстве и поле вывода на двумерной видовой поверхности. При выводе пространственных объектов, описанных в мировых координатах, они отсекаются по границе видимого объема, а после этого преобразуются в поле вывода для дисплея. Несоответствие между пространственными объектами и плоскими изображениями устраняется путем введения проекций, которые отображают трехмерные объекты на двумерной проекционной (картинной) плоскости. В общем случае проекции преобразуют точки, заданные в системе координат размерностью п, в точки системы координат размерностью, меньшей, чем n. Проекция трехмерного объекта (представленного в виде совокупности точек) строится при помощи прямых проецирующих лучей (проекторов), которые выходят из центра проекции, проходят через каждую точку объекта и, пересекая картинную плоскость, образуют проекцию. рис. 1 и 2. Рис. 1. Отрезок АВ и его центральная проекция А'В'. Рис. 2. Отрезок АВ и его параллельная проекция А'В'. Проекторы АА’ и ВВ’ параллельны. Определенный таким образом класс проекций известен под названием плоских геометрических проекций, поскольку проецирование в этом случае производится на плоскость, а не на искривленную поверхность и в качестве проекторов используются прямые, а не кривые линии. В отличие от них многие картографические проекции являются либо неплоскими, либо негеометрическими. Плоские геометрические проекции можно подразделить на два основных класса: центральные и параллельные. Различие между ними определяется соотношением между центром проекции и проекционной плоскостью. Если расстояние между ними конечно, то 26 проекция будет центральной (рис. 1), если же оно бесконечно, то проекция будет параллельной (рис. 2). Параллельные проекции названы так потому, что центр проекции бесконечно удален и все проекторы параллельны. При описании центральной проекции мы явно задаем центр проекции, в то время как, определяя параллельную проекцию, мы указываем направление проецирования. В ходе проективных преобразований, проецируемые объекты могут изменять свою форму. Это вызывается укорачиванием. Приведем простой пример. Для большей наглядности, рассмотрим проецирование отрезков лежащих в плоскости перпендикулярной проекционной плоскости и проходящей через центр проецирования. Начнем с параллельных проекций. Из рисунка видно, что проекции отрезков могут иметь меньший размер, чем сами отрезки. Величина укорачивания зависит от угла наклона отрезка к проекционной плоскости. Следовательно, отрезки параллельные одной плоскости имеют одинаковые коэффициенты укорачивания. Для отрезков параллельных проекционной плоскости коэффициент укорачивания равен 1. Отметим, что величина укорачивания не зависит от расстояния до точки наблюдения. Обычно говорят, что на параллельных проекциях можно производить измерения с точностью до скалярного множителя. Проекции параллельных прямых остаются параллельными. Теперь рассмотрим центральное проецирование. Центральная проекция дает более реалистическое представление модели. Но даже из простого примера понятно, что коэффициент укорачивания при центральном проецировании зависит не только от угла наклона, но и от расстояния до центра наблюдения (центра проекции). В этом случае имеет место перспективное укорачивание. В общем случае, проводить линейные измерения нельзя. Объекты будут иметь одинаковые коэффициенты укорачивания только в случае если они лежат в плоскости параллельной плоскости проецирования. Углы также искажаются. При центральном проецировании проекции параллельных линий пересекаются, если они не лежат в плоскости параллельной плоскости проецирования. Параллельные проекции Параллельные проекции разделяются на два типа в зависимости от соотношения между направлением проецирования и нормалью к проекционной плоскости. В орто'графических параллельных проекциях эти направления совпадают, а в косоугольных параллельных проекциях они не совпадают. То есть в ортографических проекциях направление проецирования является нормалью к проекционной плоскости. Рис. 8.7. Построение трех ортографических проекций. Наиболее широко используемыми видами ортографических проекций являются вид спереди, вид сверху (план) и вид сбоку. В них картинная плоскость перпендикулярна главным координатным осям, совпадающим вследствие этого с направлением проецирования. Эти проекции часто применяются в инженерной графике для описания машиностроительных деталей, агрегатов и сооружений, так как по ним можно измерять расстояния и углы. В случае аксонометрических ортографических проекций используются проекционные плоскости, не перпендикулярные главным координатным осям, поэтому на них изображаются сразу несколько сторон объекта, так же как и при центральном проецировании, однако в аксонометрии укорачивание постоянно, тогда как в случае 27 центральной проекции оно связано с расстоянием от центра проекции. При аксонометрическом проецировании сохраняется параллельность прямых, а углы изменяются; расстояния же можно измерить вдоль каждой из главных координатных осей (в общем случае с различными масштабными коэффициентами). Широко используемым видом аксонометрической проекции является изометрическая проекция. В ней нормаль к проекционной плоскости (а следовательно, и направление проецирования) составляет равные углы с каждой из главных координатных осей. Изометрическая проекция обладает следующим свойством: все три главные координатные оси одинаково укорачиваются. Поэтому можно проводить измерения с одним и тем же масштабом (отсюда название: изо, что означает «равно», и метрия — «измерение»). Кроме того, главные координатные оси проецируются так, что их проекции составляют равные углы друг с другом . Косоугольные проекции (второй тип параллельных проекций) сочетают в себе свойства ортографических проекций (видов спереди, сверху и сбоку) со свойствами аксонометрии. В этом случае проекционная плоскость перпендикулярна главной координатной оси, поэтому сторона объекта, параллельная этой плоскости, проецируется так, что можно измерять углы и расстояния. Проецирование других сторон объекта также допускает проведение линейных измерений (но не угловых) вдоль главных осей. Отметим, что нормаль к проекционной плоскости и направление проецирования не совпадают. Двумя важными видами косоугольных проекций являются проекции кавалье (cavalier) и кабине (cabinet)". В проекции кавалье направление проецирования составляет с плоскостью угол 45°. В результате проекция отрезка, перпендикулярного проекционной плоскости, имеет ту же длину, что и сам отрезок, т. е. укорачивание отсутствует. На рис. 8.11 приведено несколько проекций кавалье единичного куба на плоскость Проекция кабине, показанная на рис. 8.12, имеет направление проецирования, которое составляет с проекционной плоскостью угол arcctg (1/2) При этом отрезки, перпендикулярные проекционной плоскости, после проецирования составляют 1/2 их действительной длины. Проекции кабине являются более 28 реалистичными, чем проекции кавалье, поскольку укорачивание с коэффициентом 1/2 больше согласуется с нашим визуальным опытом Центральные проекции Рис. 3. Одноточечные центральные проекции куба на плоскость, пересекающую ось г, а также точка схода прямых, перпендикулярных проекционной плоскости Центральные проекции любой совокупности параллельных прямых, которые не параллельны проекционной плоскости, будут сходиться в точке схода. Параллельные прямые в трехмерном пространстве пересекаются лишь в бесконечности, поэтому точку схода можно представить себе как проекцию точки, находящейся в бесконечности. Существует бесконечное число точек схода. Если совокупность прямых параллельна одной из главных координатных осей, то их точка схода называется главной точкой схода. Имеются только три такие точки. Центральные проекции классифицируются в зависимости от числа главных точек схода, которыми они обладают, а следовательно, и от числа координатных осей, которые пересекает проекционная плоскость. Рис. 4. Двухточечная центральная проекция куба. Проекционная плоскость пересекает оси х и y. Двухточечная центральная проекция широко применяется в архитектурном, инженерном и промышленном проектировании и в рекламных изображениях, в которых вертикальные прямые проецируются как параллельные и, следовательно, не сходятся. Трехточечные центральные проекции почти совсем не используются, во-первых, потому, что их трудно конструировать, а во-вторых, из-за того, что они добавляют мало нового с точки зрения реалистичности по сравнению с двухточечной проекцией. Реализация проективных преобразований При реализации проективных преобразований можно использовать два подхода. Первый подход предполагает, что точка зрения и центр проекции зафиксированы, а проекционная плоскость перпендикулярна направлению взгляда. Центр проекции обычно располагают на положительной полуоси Z. Взгляд направляют в сторону начала 29 координат, а проекционную плоскость совмещают с плоскостью Z=0. Для получения требуемого вида манипулируют объектом, поворачивая, отображая или скашивая его. Рисунок. Этот процесс похож на то, как мы рассматриваем небольшой объект, вертя его в руках. Второй подход напоминает наши действия при изучении большого объекта, который мы не имеем возможности повернуть. Например, изучая дом мы перемещаемся сами, обходя его с разных сторон. Таким образом, объект остается неподвижным, а перемещается точка зрения и проекционная плоскость, по прежнему, остающаяся перпендикулярной направлению взгляда. Математически оба подхода эквивалентны и легко преобразовываются один в другой. Для перехода от второго подхода к первому необходимо выполнить следующие преобразования: Определить преобразование переноса, совмещающее точку пересечения линии взгляда и проекционной плоскости с началом координат; Определить преобразование поворота, совмещающее вектор взгляда с положительной полуосью Z; Применить к сцене полученные преобразования исходной сцене; Выполнить проецирование на плоскость Z=0. Мы будем использовать первый подход. Ортографические проекции Как уже говорилось при простом ортографическом проецировании одна из главных координатных осей перпендикулярна плоскости проецирования. Следовательно, плоскость проекций совпадает с одной из главных координатных плоскостей x=0, y=0 или z=0. Матрица проецирования на плоскость z=0 имеет следующий вид 30 Лекция 6. Реализация проекций в OpenGL Ортографическая проекция Ортографическая проекция в OpenGL определяется командой glOrtho. В результате выполнения данной команды происходит перемножение текущей матрицы с матрицей ортографической проекции, определяемой данной командой. Результирующая матрица становится текущей матрицей. Синтаксис команды следующий: glOrtho(left GLdouble, right GLdouble, bottom GLdouble, top GLdouble, near GLdouble, far GLdouble); Как вы помните, для определения ортографического проецирования необходимо определить положение проекционной плоскости, направление проецирования и видимый объем. Рассмотрим рисунок, иллюстрирующий определение данных величин в мировой координатной системе. В OpenGL проекционная плоскость совпадает с плоскостью z=0. Направление проецирования параллельно оси z. Взгляд наблюдателя считается направленным в сторону отрицательной полуоси z. Видимый объем имеет форму параллелепипеда. Параметр top определяет положение плоскости, ограничивающей его сверху. Данная плоскость перпендикулярна проекционной плоскости. Параметры bottom, left, right определяют плоскости, ограничивающие видимый объем соответственно снизу, слева и справа. Эти плоскости также перпендикулярны проекционной плоскости. near, far - определяют расстояние от начала координат до передней (ближней) и задней (дальней) плоскостей отсечения видимого объема. Расстояния могут быть отрицательными. Обратите внимание на то, что near всегда меньше far. В геометрической интерпретации данное условие можно определить следующим образом: вектор наблюдения сначала пересекает переднюю секущую плоскость, а затем заднюю секущую плоскость. Используя термины ближняя и дальняя секущие плоскости, имеют ввиду положение этих плоскостей относительно наблюдателя, а не начала координат. При определении данных плоскостей, положительными считаются расстояния от начала координат в сторону отрицательной полуоси z, а отрицательными расстояния, отложенные от начала координат в сторону положительной полуоси z. Почему все вывернуто наоборот? Ответ очевиден, видимый объем формируется в левосторонней видовой системе координат. Посмотрим, как определена видовая система координат. Опорная точка VRP имеет координаты (0, 0, 0), вектор v (проекция VUP) совпадает с осью Y, a VPN совпадает с отрицательной полуосью Z. В видовой системе координат положительные направления откладываются вдоль положительной полуоси VPN. Все стало на свои места. Таким образом, с помощью OpenGL нельзя определить произвольный видимый объем. Секущие плоскости всегда параллельны главным координатным плоскостям. Для создания произвольной проекции сцену придется поворачивать и переносить с помощью преобразования вида, так чтобы она попала в видимый объем требуемым образом. Изменяя параметры команды, мы можем произвести параллельный перенос видимого объема вдоль главных координатных осей и изменить его размеры. Следовательно, мы можем определить, какие преобразования выполняет матрица проецирования. В библиотеке используется канонический объем, определяемый следующими плоскостями: u = -1, u = 1, v = -1, v = 1, vpn = -1, vpn = 1. Для приведения определенного нами объема видимости к каноническому, необходимо произвести масштабирование и перенос, а для перехода к левосторонней системе координат поменять знак координаты z. Соответствующая матрица выглядит следующим образом: 31 2 r l 0 P 0 0 0 0 2 t b 0 0 0 2 f n 0 r l r l t b t b f n f n 1 Для краткости мы обозначили переднюю и заднюю секущие плоскости первыми буквами их названий. В главной диагонали данной матрицы, как вы помните, лежат масштабирующие коэффициенты, а в правом столбце коэффициенты переноса. (матрица дана в формате, используемом в OpenGL ). В рассматриваемом ранее материале мы говорили, что при ортографическом проецировании на плоскость z=0 третий столбец, а в нашем случае третью строку, надо обнулить. Для чего же мы рассчитываем координату z? Для определения видимости объектов. При совпадении координат x и y будет видна точка того объекта, который расположен ближе к наблюдателю, т.е. имеет меньшее значение координаты z. Для принятия решения нам важны не величины координат, а их отношения. Следовательно, при проецировании мы можем задавать любые преобразования этой координаты. Главное, чтобы они не нарушали отношения между точками. То есть, если перед преобразованием точка P1 имеет большее значение координаты z, чем точка p2, то это отношение должно остаться в силе и после преобразования. Обратите внимание. По умолчанию матрица GL_PROJECTION установлена единичной, а параметры видимого объема следующие: left = -1, right = 1, bottom = -1, top = 1, near = 1, far = 1. Как же выполняется проецирование в этом случае? Подставим указанные параметры видимого объема в матрицу ортографического проецирования. Так как это канонический для OpenGL объем, то все масштабирующие коэффициенты будут равны единице, а сдвиги по осям равны 0. Получившаяся матрица отличается от единичной матрицы только знаком у масштабирующего множителя по координате Z. Следовательно, при использовании единичной матрицы переход к левосторонней системе координат не производится, и объекты рассматриваются в неправильном порядке. Перспективная проекция Перспективная проекция определяется командой glFrustum. Результат выполнения данной команды аналогичен предыдущему - происходит перемножение текущей матрицы с матрицей перспективной проекции, определяемой данной командой. Результирующая матрица становится текущей матрицей. Синтаксис команды следующий: GlFrustum (left GLdouble, right GLdouble, bottom GLdouble, top GLdouble, near GLdouble, far GLdouble), где left, right - определяют соответственно левую и правую плоскости отсечения; top, bottom - определяют соответственно верхнюю и нижнюю плоскости отсечения; near, far - определяют расстояние до передней (ближней) и задней (дальней) плоскостей отсечения видимого объема. Эти величины могут быть только положительными. Это ограничение не позволяет заключить в видимый объем объекты, имеющие положительные значения координаты Z. Поэтому при работе с центральными проекциями часто приходится формировать перенос сцены в сторону отрицательной полуоси Z мировой системы координат. 32 Как вы помните, при центральном проецировании, коэффициент укорачивания зависит от расстояния до центра проекции. Поэтому проекции объектов, расположенных близко к центру проекции, выглядят неестественно, так как при небольшом изменении глубины сильно изменяется коэффициент укорачивания (разница между расстояниями до центра проекции сравнима с самим расстоянием). Для устранения данного эффекта необходимо перенести модель вместе с видимым объемом в сторону отрицательной полуоси Z. Матрица перспективного проецирования выглядит следующим образом: 2n r l 0 P 0 0 0 2n t b 0 0 r l r l t b t b f n f n 1 0 2 fn f n 0 0 В библиотеке GLU существует альтернативная команда для задания перспективной проекции: gluPerspective( fovy GLdouble, aspect GLdouble, near GLdouble, far GLdouble ); где fovy – определяет угол зрения в плоскости yoz, его значение принадлежит диапазону [0.0..180.0]; aspect– определяет aspect ratio сечения видимого объема (отношение ширины к высоте). near, far - определяют расстояние до передней (ближней) и задней (дальней) плоскостей отсечения видимого объема. Они также должны быть только положительными. Команда создает матрицу симметричного перспективного преобразования и перемножает ее с текущей матрицей. При использовании данной команды необходимо следить за совпадением величин aspect ratio поля вывода и данной команды. glViewport(0, 0, ClientWidth, ClientHeight); gluPerspective(30.0, ClientWidth/ClientHeight, 2.0, 10.0); Очевидно, что параметры двух преобразование, легко преобразуются тригонометрических зависимостей. команд, друг в определяющих друга, исходя перспективное из простых Ориентация в пространстве Произвольная ориентация в пространстве определяется командой из дополнительной библиотеки qlu - gluLookAt. Результат выполнения данной команды аналогичен предыдущему - происходит перемножение текущей матрицы с матрицей видового преобразования, определяемой данной командой. Результирующая матрица становится текущей матрицей. Синтаксис команды следующий: gluLookAt(eyex GLdouble, eyey GLdouble, eyez GLdouble, centerx GLdouble, centery GLdouble, centerz GLdouble, upx GLdouble, upy GLdouble, upz GLdouble); где eyex, eyey, eyez – координаты точки наблюдения (VRP). centerx, centery, centerz – точка, определяющая центр сцены. Эта точка после проецирования окажется в центре поля вывода (ViewPort). При формировании видовой 33 системы координат вектор, соединяющий VRP с данной точкой, будет рассматриваться как VPN. upx, upy, upz – точка, совместно с VRP определяющая VUP вектор (т.е. где будет верх проекции). При изучении основ проецирования мы говорили о двух подходах к созданию проекций: с фиксированной проекционной плоскостью (точкой наблюдения) и с фиксированной сценой. Так же рассматривали композицию преобразований, приводящую один подход к другому. Параметры данной команды определяют произвольную видовую систему координат. Создаваемая матрица, представляющая собой композицию преобразований переноса и поворота, приводит заданную систему к фиксированной системе координат, используемой в OpenGL. Подобные композиции мы определяли сами при формировании простых ортографических проекций (фронтальной, вида сверху, сзади и др.). Построение дополнительных плоскостей отсечения. Для создания различных специальных эффектов в OpenGL предусмотрена возможность определения шести дополнительных отсекающих плоскостей, уточняющих форму видимого объема. Типичным примером использования таких плоскостей является создание сечений. glClipPlane( plane GLenum, const equation GLdouble ); параметр plane – указывает, какую из шести плоскостей мы определяем, equation – является указателем на массив, задающий коэффициенты уравнения плоскости. glEnable and glDisable, and called with the argument GL_CLIP_PLANEi, Ax+By+Cz+D= 0 34 Лекция 7. Освещение и свет. 1 Простая модель освещения Световая энергия, падающая на поверхность, может быть поглощена, отражена или пропущена. Объект можно увидеть, только если он отражает или пропускает свет; если же объект поглощает весь падающий свет, то он невидим и называется абсолютно черным телом. Если объект отражает весь падающий свет, то он называется идеальной отражающей поверхностью (зеркалом). Количество поглощенной, отраженной или пропущенной энергии зависит от длины волны света. При освещении белым светом, если поглощается почти весь свет, то объект кажется черным, а если только небольшая его часть — белым. Если поглощаются лишь определенные длины волн, то у света, исходящего от объекта, изменяется распределение энергии и объект выглядит цветным. Цвет объекта определяется поглощаемыми длинами волн. Свойства отраженного света зависят от строения, направления и формы источника света, от ориентации и свойств освещаемой поверхности. Отраженный от объекта свет может быть диффузным или зеркальным. 1.1 Диффузное отражение Диффузное отражение света происходит, когда свет как бы проникает под поверхность объекта, поглощается, а затем вновь испускается. При этом положение наблюдателя не имеет значения, так как диффузно отраженный свет рассеивается равномерно по всем направлениям. Свет точечного источника отражается от идеального рассеивателя по закону косинусов Ламберта: интенсивность отраженного света пропорциональна косинусу угла между направлением света и нормалью к поверхности, т. е. Id = Il Kd cos 0 /2 где Id — интенсивность диффузно отраженного света, Il — интенсивность точечного источника, Kd — коэффициент диффузного отражения (0 Kd 1), — угол между направлением света и нормалью к поверхности (рис. 1). Рис. 1 Схема диффузного отражения. Если > /2, то источник света расположен за объектом. Коэффициент диффузного отражения Kd зависит от материала и длины волны света, но в простых моделях освещения обычно считается постоянным. Поверхность предметов, изображенных при помощи модели освещения с ламбертовым диффузным отражением, выглядит блеклой и матовой. Предполагается, что источник точечный, поэтому объекты, на которые не падает прямой свет, кажутся черными. Однако на объекты реальных сцен падает еще и рассеянный свет, отраженный от окружающей обстановки, например от стен комнаты. Рассеянному свету соответствует распределенный источник. Поскольку для расчета таких источников требуются большие вычислительные затраты, в машинной графике они заменяются на коэффициент рассеяния — константу, которая входит в формулу в линейной комбинации с членом Ламберта: 35 Id = Ia Ka + Il Kd cos 0 /2 , где Ia — интенсивность рассеянного света, Ka — коэффициент диффузного отражения рассеянного света (0 Ka 1). Пусть даны два объекта, одинаково ориентированные относительно источника, но расположенные на разном расстоянии от него. Если найти их интенсивность по данной формуле, то она окажется одинаковой. Это приводит к тому, что, в случае перекрытия предметов, их невозможно различить. Интенсивность света обратно пропорциональна квадрату расстояния от источника, следовательно, объект, лежащий дальше от него, должен быть темнее. В случае перспективного преобразования сцены в качестве коэффициента пропорциональности можно взять расстояние d от центра проекции до объекта. Но если центр проекции лежит близко к объекту, то 1/d2 изменяется очень быстро, т. е. у объектов, лежащих примерно на одинаковом расстоянии от источника, разница интенсивностей чрезмерно велика. Как показывает опыт, большей реалистичности можно добиться при линейном затухании. В этом случае модель освещения выглядит так: Id = Ia Ka + Il Kd cos /(d+K), где К — произвольная постоянная, а d - расстояние от центра проекции до объекта. Если предполагается, что точка наблюдения находится в бесконечности, то d определяется положением объекта, ближайшего к точке наблюдения. Это означает, что ближайший объект освещается с полной интенсивностью источника, а более далекие — с уменьшенной. Для цветных поверхностей модель освещения применяется к каждому из трех основных цветов. 1.2 Зеркальное отражение Интенсивность зеркально отраженного света зависит от угла падения, длины волны падающего света и свойств вещества отражающей поверхности. Зеркальное отражение света является направленным. Угол отражения от идеальной отражающей поверхности (зеркала) равен углу падения, в любом другом положении наблюдатель не видит зеркально отраженный свет (рис. 2). Это означает, что вектор наблюдения S совпадает с вектором отражения R, и угол равен нулю. Если поверхность не идеальна, то количество света, достигающее наблюдателя, зависит от пространственного распределения зеркального отраженного света. У гладких поверхностей распределение узкое или сфокусированное, а у шероховатых более широкое. Рис. 2. Схема зеркального отражения Благодаря зеркальному отражению на блестящих предметах появляются световые блики. Из-за того, что зеркально отраженный свет сфокусирован вдоль вектора отражения, блики при движении наблюдателя тоже перемещаются. Более того, так как свет отражается от внешней поверхности (за исключением металлов и некоторых твердых красителей), то отраженный луч сохраняет свойства падающего. Например, при освещении блестящей синей поверхности белым светом, возникают белые, а не синие блики. Так как физические свойства зеркального отражения очень сложны, в простых моделях освещения обычно пользуются эмпирической моделью Буи-Туонга Фонга: Is = Il w(,)cosn , 36 где w(,) — кривая отражения, представляющая отношение зеркально отраженного света к падающему как функцию угла падения и длины волны (рис. 3), а cosn — функция, аппроксимирующая пространственное распределение зеркально отраженного света (рис. 4.). Большие значения n дают сфокусированные пространственные распределения характеристик металлов и других блестящих поверхностей, а малые — более широкие распределения для неметаллических поверхностей, например бумаги. 100 100 Серебро Al Ag Сталь Золото 50 50 Диэлектрик 0 2 8 6 4 -3 Длина волны ( x 10 ) a) 0 30 60 Угол падения 90 б) Рис. 3. Кривые отражения Рис. 4. Приближенные функции пространственного распределения для зеркального отражения. Коэффициент зеркального отражения зависит от угла падения, однако даже при перпендикулярном падении зеркально отражается только часть света, а остальное либо поглощается, либо отражается диффузно. Эти соотношения определяются свойствами вещества и длиной волны. Коэффициент отражения для некоторых неметаллов может быть всего 4%, в то время как для металлических материалов — более 80%. 1.3 Общая модель Объединяя формулы диффузного отражения и зеркального отражения, получим модель освещения: I = Ia Ka + Il(Kd cos + w(i,)cosn )/(d+K). Поскольку функция w(i,) довольно сложна, ее обычно заменяют константой Ks, выбираемой экспериментально из эстетических соображений: I = Ia Ka + Il(Kd cos + Ks cosn )/(d+K). В машинной графике эта модель часто называется функцией закраски и применяется для расчета интенсивности или тона точек объекта или пикселов изображения. Чтобы получить цветное изображение, нужно найти функции закраски для каждого из трех основных цветов. Если имеется несколько источников света, то их эффекты суммируются. В этом случае модель освещения определяется как 37 m I = Ia Ka + I lj (Kd cos j + Ks cosn j )/(d+K) J= 1 , где m – количество источников. Косинусы углов, входящие в формулу, можно представить как произведения двух векторов cos = n*L / |n||L| = n*L , где n и L – соответсвенно, единичные векторы нормали к поверхности и направления на источник. Аналогично cos = R*S / |R||S| = R*S , где R и S – соответсвенно, единичные векторы, определяющие направление отраженного луча и наблюдения. Общее уравнение модели освещения определится следующим образом: I = Ia Ka + Il(Kd (n*L) + Ks (R*S)n)/(d+K). 2 Источники света в OpenGL В OpenGL используется два типа источников света - направленные и позиционные. Под направленным понимается источник, удаленный от освещаемой сцены на бесконечное расстояние. Следовательно, все лучи, падающие на сцену, параллельны, затухание отсутствует. Примером такого источника в реальном мире может служить солнце. Для данного типа источников необходимо определить только направление лучей и характеристики светового потока. Расчет освещения в этом случае относительно прост, так как угол падения света одинаков для всех точек одной плоскости. Позиционный источник, напротив, располагается в непосредственной близости от объектов сцены, и на две точки одной плоскости будет падать свет разной силы и под разными углами. Для изучения свойств позиционных источников света используем метафору фонаря (рис. __), достаточно хорошо соответствующую реальным свойствам источника света OpenGL. Рис. __. Модель источника освещения Напомним хорошо знакомые нам действия с фонарем. Прежде всего, мы располагаем его в пространстве, затем направляем в нужную сторону и включаем. Отражатель формирует конус света, исходящий от фонаря. При необходимости можно сфокусировать световое пятно, вращая отражатель. В крайних положениях отражателя световой поток или фокусируется, создавая яркое пятно в центре и оставляя границы светового конуса почти не освещенными, или равномерно распределяется по всему световому конусу. При освещении фонарем объекты, расположенные ближе к нам, освещаются лучше удаленных. В природе световой поток ослабевает согласно квадрату расстояния до объекта. 38 Теперь рассмотрим, как эти и другие параметры источника света устанавливаются в OpenGL. Источник света с номером i, включается или выключается командами glEnable или gIDisable с аргументом GL_LIGHTi, который определяется как GL_LIGHTi = GL_LIGHT0 + i, , где i лежит в диапазоне от 0 до GL_MAX_LIGHTS - которое не может быть больше восьми. Общее число источников зависит от реализации. Источники можно включать или выключать в любое время, но лучше перед включением установить их параметры. Установка параметров источников света производится командой gILight, значения аргументов которой зависят от того, работаем с ее скалярной или векторной версией: gILight[i f]v(light GLenum, pname GLenum, param GLfloat) Аргумент light определяет номер источника света, аргумент рnате является символической константой, определяющей устанавливаемый параметр. Аргумент param определяет значение, которое устанавливается для параметра рnате источника с именем light. Скалярной версией команды можно установить следующие значения pname: GL_SPOT_EXPONENT - Параметр param содержит единственное целое или вещественное значение, которое задает распределение интенсивности света внутри светового конуса. Доступны значения из диапазона [0, 128]. Эффективность интенсивности света ослабевает пропорционально косинусу угла между направлением от источника и нормалью в вершине (рис. 2). Чем больше это значение, тем более сфокусирован источник света. По умолчанию установлено значение 0, что соответствует равномерному рассеянию по всему световому конусу. В нашей метафоре этот параметр соответствует вращению отражателя. GL_SPOT_CUTOFF - Параметр раrат является целым или вещественным значением, которое определяет максимальный угол разброса источника света (световой конус). Доступны значения из диапазона [0, 90] и 180. По умолчанию используется значение 180, что соответствует рассеянному свету. В нашей метафоре этот параметр определяет конструкцию отражателя. При значении 180 происходит смена метафоры. Фонарь заменяется на лампочку (без абажура). GL_CONSTANT_ATTENUATION, GL_LINEAR_ATTENUATION, GL_QUADRATIC_ATTENUATION Параметр раrат задает единственное целое или вещественное значение, определяющее один из трех факторов ослабления — постоянного, линейного или квадратичного. Допустимыми являются только неотрицательные значения. Интенсивность источника света ослабевает в соответствии с суммарным значением: постоянного фактора, линейного фактора, умноженного на расстояние между источником и вершиной, и квадратичного фактора, умноженного на квадрат того же расстояния: ______1______ , k0i+k1iSi+k2iS2i 39 где ki - соответствующие коэффициенты ослабления, a Si - расстояние от источника. По умолчанию факторы ослабления имеют значения (1, 0, 0). С помощью векторной версии команды glLight[i f]v можно задать дополнительные значения параметра pname: GL_AMBIENT - Параметр params содержит четыре целых или вещественных значения RGBA, которые определяют интенсивность фонового освещения. По умолчанию значение рассеянного света равно (0.0, 0.0, 0.0, 1.0). GL_DIFFUSE - Параметр params содержит четыре целых или вещественных значения RGBA, которые определяют интенсивность диффузного освещения. По умолчанию значение интенсивности диффузного света равно (0.0, 0.0, 0.0, 1.0) для всех источников кроме нулевого, для которого эта интенсивность равна (1.0, 1.0, 1.0, 1.0). GL_SPECULAR -Параметр params содержит четыре целых или вещественных значения RGBA, которые определяют интенсивность освещения зеркального отражения. По умолчанию значение интенсивности зеркального отражения равно (0.0, 0.0, 0.0, 1.0) для всех источников кроме нулевого, для которого она равна (1.0, 1.0, 1.0, 1.0) В OpenGL общая, диффузная и зеркальная составляющие света насчитываются отдельно, а затем суммируются. GL_POSITION - Параметр params содержит четыре целых или вещественных значения, задающих координатный вектор [x, y, z, w], смысл которого определяет значение масштабирующего коэффициента w. Обратите внимание, этот вектор преобразуется видовой матрицей и сохраняется в видовых координатах. Если компонент w равен 0, то данный источник рассматривается как направленный источник. А диффузное и зеркальное освещение рассчитываются в зависимости от направления, определяемого вектором, соединяющим точку, определяемую тройкой (x, y, z) c началом мировой системы координат. Ослабление заблокировано. В противном случае, при w = 1, данный источник рассматривается как позиционный. Координатный вектор определяет положение источника света в однородных мировых координатах. Вектор так же преобразуется видовой матрицей и сохраняется в видовых координатах. Параметры освещения рассчитываются на основе действительного расположения источника в видовых координатах, ослабление разрешено. По умолчанию координатный вектор равен [0, 0, 1, 0], что соответствует удаленному в бесконечность источнику света, лучи которого направлены в сторону отрицательной полуоси Z мировой системы координат. GL_SPOT_DIRECTION - Параметр params содержит три целых или вещественных значения (x, y, z), определяющие вектор направления света позиционного источника в однородных мировых координатах. Направление света источника по умолчанию задается значениями (0, 0, -1). Так же обратим внимание, на то, что этот вектор преобразуется видовой матрицей и сохраняется в видовых координатах. Рассмотрим подробнее смысл этой важного замечания. То есть в момент вызова команды glLight с соответствующими параметрами, формируется координатный вектор, который умножается на матрицу видового преобразования, переводится в видовые координаты и запоминается. Таким образом, положение источника и направление света, подобно геометрическим примитивам, подвергается повороту, переносу и другим геометрическим преобразованиям, накопленным в матрице видового преобразования на данный момент. Матрица проекций не оказывает влияния на эти свойства источника. Используя данный подход, легко сохранять неподвижность источника при движении сцены, или наоборот, организовать движение источника относительно неподвижной сцены. Включение режима расчета освещения производиться командой glEnable с параметром GL_LIGHTING. 2.1 Модель освещения Параметры модели задаются командой: glLightModel[i f] v(GLenum pname, GLenum param) Аргумент pname определяет единственное значение параметра модели освещения и может принимать следующие значения: 40 GL_LIGHT_MODEL_LOCAL_VIEWER - Параметр param содержит единственное булевское значение, определяющее местоположение наблюдателя. Если param = GL_FALSE, то направление наблюдения считается параллельным оси -z и направленным вдоль нее, независимо от действительного положения в видовых координатах. В противном случае (GL_TRUE) предполагается, что наблюдатель находится в начале видовой системы координат. По умолчанию параметр param установлен в GL_FALSE. Использование локальной точки наблюдения позволяет создать более реалистичную картину зеркального освещения, так как для каждой точки поверхности формируется вектор, направленный на наблюдателя. В случае наблюдателя, расположенного в бесконечности, данный вектор для всех точек одинаков и направлен вдоль оси Z. GL_LIGHT_MODEL_TWO_SIDE - Параметр param представляет единственное булевское значение, которое определяет расчет освещенности многоугольников для одной или двух граней. Этот параметр не влияет на расчет освещенности для точек, линий или битовых массивов. Если param = FALSE, то задано одностороннее освещение, и расчет освещенности производится только для лицевой грани. В противном случае (TRUE) задается двухстороннее освещение и, на ряду с лицевыми гранями, рассчитывается освещенность вершин обратных граней многоугольников. Их нормали направлены в противоположные стороны. По умолчанию FALSE. Если сцену составляют только замкнутые пространственные объекты (сферы, кубы и пр.), без сечений то целесообразно использовать расчет освещения только лицевых граней, что существенно ускоряет визуализацию объектов сцены. GL_LIGHT_MODEL_COLOR_CONTROL Параметр param может определятся символической константой GL_SEPATARE_SPECULAR_COLOR, заставляющей конвейер отделять вычисление зеркально отраженного света от других составляющих. В этом случае для каждой вершины рассчитываются два значения цвета: первое значение образуется совокупность всех не зеркальных составляющих, а второе суммой зеркальных составляющих. Данный режим важен при наложении текстур. При расчете результирующего цвета сначала первое значение комбинируется с цветовыми характеристиками текстуры, а затем результат объединяется со вторым значением. Такой подход позволяет получить более ярко выраженные зеркальные блики на текстурированной поверхности. Для возврата к значению, установленному по умолчанию, необходимо воспользоваться константой GL_SINGLE_COLOR . Кроме того, для векторной версии команды доступно еще одно значение параметра pname. GL_LIGHT_MODEL_AMBIENT - Параметр param содержит четыре целых или вещественных значения, которые задают полную фоновую интенсивность света. По умолчанию значение фонового цвета равно (0.2, 0.2,0.2, 1.0). 2.3 Грани Остановимся немного подробнее на понятии грани, используемом в OpenGL. Гранью называется сторона многоугольника. Причем в качестве многоугольника могут выступать как простейший треугольник, так и сложный многоугольник, лежащий в одной плоскости. Все сложные трехмерные объекты в OpenGL апроксимируются многоугольниками. Каждый многоугольник имеет две стороны, т. е. две грани, — лицевую и обратную. Очевидно, что только одна грань может быть видима в окне в текущий момент времени. Для того, чтобы не тратить время на воспроизведение невидимых граней, в OpenGL реализован механизм, позволяющий различать лицевые и обратные грани. При рассмотрении многоугольных примитивов уже говорилось о важности порядка обхода вершин. Грани различают после того, как многоугольник спроецирован в окно. Рассматривается, в какой последовательности обходятся вершины многоугольника и принимается решение о типе грани. Если они обходятся по часовой стрелке, то видимой является одна из граней; если против часовой стрелки, то другая. Выбор, какую грань считать лицевой, а какую обратной, осуществляется при помощи команды 41 glFrontFace(Glenum mode), которая позволяет определить тип грани в зависимости от направления обхода многоугольника — по часовой стрелке или против. Направление обхода задается параметром mode, который может принимать значения GL_CW — по часовой стрелке и GL_CCW — против часовой стрелки (установлено по умолчанию). Команда: glCullFace(GLenum mode) позволяет указать какие грани - лицевые или обратные будут исключены из рассмотрения. Параметр mode может принимать одно из двух значений: GL_FRONT — для лицевых и GL_BACK — для обратных граней (последнее используется по умолчанию). Для того, чтобы разрешить OpenGL отбирать изображаемые грани, необходимо выполнить команду glEnable с аргументом GL_CULL_FACE. Блокировка этого режима как обычно осуществляется командой gIDisable с тем же аргументом. 2.2 Свойства материала Прежде, чем переходить к описанию способов задания свойств материалов, отметим различный смысл похожих параметров у источников света и материалов. В обоих случаях мы определяем цветовые характеристики. Однако у источников света эти характеристики соответствуют процентному отношению цветов в конкретной составляющей светового потока, испускаемого источником. Например, если мы определили диффузную составляющую источника как (1,1,1,0), то это означает, что в световом потоке, исходящем от источника, присутствует свет, способный диффузно отразиться от поверхности. В его состав входят красный, синий и зеленый цвета в равных пропорциях и при максимальной интенсивности. В общем, такой свет можно охарактеризовать как белый. У материалов аналогичные характеристики определят степень отражения составляющих цветов. Так если мы зададим диффузную компоненту материала как (0.5,0,0,0), то данное определение будет означать, что данный материал диффузно отражает только красный свет и с половинной интенсивностью. А зеленый и синий цвета будут полностью поглощены поверхностью объекта. В результате освещения этого объекта рассмотренным источником поверхность объекта будет выглядеть темно-красной. Если осветить данный объект источником с диффузной составляющей равной (0,1,1,0), то он будет выглядеть черным. Таким образом, общая, диффузная и зеркальная составляющие отраженного поверхностью света будут рассчитываться по следующей схеме (LR*MR, LG*MG, LB*MB). Где (LR, LG, LB) – цветовые характеристики составляющей падающего света, а (MR, MG, MB) – характеристики отражения поверхностью данной составляющей. Как уже говорилось, различные материалы по-разному отражают свет. Металлические поверхности, как правило, отражают свет лучше, чем неметаллические. Некоторые материалы сами излучают свет, например фосфор и различные люминофоры. В OpenGL существует несколько возможностей для задания свойств материалов объектов сцены. Рассмотрим команду: glMaterial[i f] [v]( face GLenum, pname GLenum, params GLtype). Параметры материала, как и во многих других случаях, различаются для лицевой и обратной поверхностей. Параметры лицевой грани используются для точек, линий, битовых массивов и всех многоугольников, когда заблокировано двустороннее освещение, или только для лицевых, если двустороннее освещение разрешено. К каким поверхностям применяются задаваемые параметры, определяется аргументом face, который может принимать следующие значения: GL_FRONT, GL_BACK, GL_FRONT_AND_BACK. Аргумент pname определяет, какие параметры материала будут обновляться. Для скалярной версии команды он может принимать только одно значение — GL_SHININESS, задающее степень зеркального отражения материала. Для векторной версии можно использовать следующие значения: GL_AMBIENT - Параметр params содержит четыре целых или вещественных значения цветов RGBA, которые определяют рассеянный цвет материала. По умолчанию значение рассеянного цвета равно (0.2, 0.2, 0.2, 1.0); 42 GL DIFFUSE - Параметр params содержит четыре целых или вещественных значения RGBA, которые определяют цвет диффузного отражения материала. По умолчанию значение диффузного цвета равно (0.8, 0.8, 0.8,1.0); эта составляющая оказывает наибольшее влияние на результирующий цвет объекта. Обратите внимание. При смешивании цветов значения альфа компоненты всех других параметров игнорируется. Учитывается только альфа компонента, заданная для диффузного отражения. GL SPECULAR - Параметр params содержит четыре целых или вещественных значения RGBA, которые определяют цвет зеркального отражения материала. По умолчанию значение зеркального цвета равно (0.0, 0 0, 0.0, 1.0). GL_EMISSION - Параметр params содержит четыре целых или вещественных значения RGBA, которые определяют интенсивность излучаемого света материалом. По умолчанию значение излучаемого света равно (0.0, 0.0, 0.0, 1.0). Данное свойство используется для имитации фосфора и люминофоров, а так же для отображения источников света. GL_SHININESS - Параметр params содержит одно целое или вещественное значение, которые определяют степень зеркального отражения материала. Можно использовать только значения от 0 до 128. По умолчанию установлено значение 0. Напомним что интенсивность зеркального отражения расчитывается на основе модели Фонга Is = Ilw(,)cosn и данный параметр определяет n — степень, аппроксимирующую пространственное распределение зеркально отраженного света. GL_AMBIENT_AND_DIFFUSE - Эквивалентно двум вызовам команды с аргументами рnате, равными GL_AMBIENT и GL_DIFFUSE, и одинаковыми значениями параметра params GL_COLOR_INDEXES - Параметр params содержит три целых или вещественных значения, определяющих индексы цветов для рассеянного, диффузного и зеркального отражения соответственно. Из приведенного описания видно, что, задавая параметры материала, можно управлять тем, насколько блестящим будет выглядеть материал, и будет ли он самостоятельно излучать свет. Другими словами, можно определять отражающие свойства материала. Наиболее часто учитываемыми в различных моделях являются диффузный и зеркальный отраженный свет, поскольку диффузное отражение придает объекту его естественный цвет, а зеркальное определяет отражающие свойства поверхности: на очень блестящей поверхности зеркальное отражение приводит к появлению резко очерченных бликов, а для менее блестящих объектов выглядит более тускло. Таким образом, чтобы объект выглядел блестящим, необходимо сузить угол зеркального отражения, а для тусклых поверхностей наоборот расширить его. Наряду с только что рассмотренной командой, для установки параметров материала в OpenGL реализована еще одна: glColorMaterial(face GLenum, mode GLenum) У этой команды аргумент face может принимать те же значения, что и в команде gIMaterial, а аргумент mode — только значения GL_AMBIENT_AND_DIFFUSE, GL_AMBIENT, GL_EMISSION, GL_DIFFUSE и GL_SPECULAR. По умолчанию используется GL_AMBIENT_AND_DIFFUSE. Если разрешен режим GL_COLOR_MATERIAL (вызовом команды glEnable с соответствующим аргументом), то параметры поверхностей материала, заданные аргументами mode и face, принимают значения текущего цвета. В этом случае можно изменять параметры материала для каждой вершины, используя только команду glColor, без дополнительного вызова gIMaterial, что в некоторых случаях является более удобным. Определение нормалей и функции закрашивания Плоское закрашивание Для расчета интенсивности освещения поверхности в заданной точке, согласно рассмотренной модели, необходимо определить четыре вектора: направления на источник, направления на наблюдателя, отраженного света и нормаль. Определение первых трех векторов достаточно очевидно, а вычисление нормалей вызывает определенные трудности. Если окрашиваемая поверхность задана явным уравнением, то определение нормалей можно произвести классическими математическими методами. Нас больше 43 интересуют частные случаи и приближенные методы вычислений, так как строгие расчеты требуют огромного объема вычислений. Как вы помните, поверхности при визуализации чаще всего аппроксимируются множеством малых плоских многоугольников (треугольниками или четырехугольниками). Нормали для всех точек плоскости совпадают и могут быть рассчитаны, исходя из координат любых трех точек плоскости, не лежащих на одной прямой. N = (p2-p0)*(p1-p0). Порядок сомножителей определит направление нормали относительно плоскости. При перестановке сомножителей получаются коллинеарные вектора (имеющие противоположное направление). Если для всех точек многоугольника мы примем одинаковыми три оставшиеся вектора, то получим так называемое плоское или равномерное закрашивание (источник освещения направленный и наблюдатель удален в бесконечность). При этом все точки многоугольника считаются освещенными одинаково. Такой подход естественно дает максимальную эффективность, но визуально окрашиваемые поверхности выглядят неестественно. При аппроксимации явно видны переходы между отдельными многоугольниками. Ситуацию усугубляет появление полос Маха. Из за особенностей зрительной системы человека очень чувствительной к малым изменениям оттенков соседних участков изображения при резком переходе от светлого участка к более темному, мы видим дополнительные полосы вдоль линии перехода. То есть вдоль линии перехода светлый многоугольник кажется более светлым, чем он есть на самом деле, а темный еще темнее. Для того, чтобы устранить данный эффект, необходимо сгладить переход между оттенками соседних участков. Закрашивание методом Гуро Метод сглаживания, предложенный Гуро, предполагает усреднение нормалей и билинейную интерполяцию интенсивностей, рассчитанных для каждой вершины многоугольника. Вектора нормалей определяются для всех вершин многоугольников аппроксимирующих поверхность. Для усреднения нормали к некоторой вершине суммируются нормали ко всем многоугольникам, пересекающимся в этой вершине. Полученный результат нормализуется. Например, для вершины, в которой пересекаются четыре многоугольника, нормаль может быть посчитана следующим образом n n1 n2 n3 n4 n1 n2 n3 n4 . В некоторых случаях нормаль к вершине можно получить значительно легче. Например, при аппроксимации сферы нормаль к любой ее точке определится вектором, соединяющим центр сферы и данную точку. Необходимо только произвести его нормализацию. Сложность реализации расчета нормалей по методу Гуро сводится к разработке модели, отражающей топологию объекта. То есть, исходя из данной модели, мы должны определять для каждой вершины все многоугольники, стыкующиеся в ней. Для проведения билинейной интерполяции рассчитывают интенсивности в вершинах многоугольника, а для определения интенсивностей всех других точек проводят интерполяцию с помощью сканирующей строки. Рассмотрим участок полигональной поверхности, приведенный на рисунке. Интенсивность в точке P определяется линейной интерполяцией интенсивностей рассчитанных для точек Q и R. Линейная интерполяция производится на основе параметрического уравнения прямой, проходящей через две точки P = P1t+(1-t)P2 . Очевидно, что при t=0 получаем точку P1, а при t=1 точку P2. Аналогично интенсивность в точке P определиться как IP = tIq+(1-t)Ir где 0 t 1 t= QP/QR. Для получение интенсивности в точке Q интерполируем интенсивности в точках А и В. Iq = uIa+(1-u)Ib где 0 u 1 u= AQ/AB. Из этих же рассуждений находим интенсивность в точке R. Ir = wIb+(1-w)Ic где 0 w 1 w= BR/BC. 44 Таким образом, проводя дважды линейную интерполяцию, мы получаем интенсивность произвольной точки многоугольника. В силу линейности интерполирующей функции мы можем получать значения интенсивностей вдоль сканирующей строки инкрементально (основываясь на результате вычисления интенсивности в предыдущей точке). Рассчитаем интенсивность для двух произвольных точек сканирующей строки. IP1 = t1Iq+(1-t1)Ir, IP2 = t2Iq+(1-t2)Ir Найдем разность интенсивностей и выразим интенсивность во второй точке через интенсивность в первой точке: IP2 = IP1+( Iq-Ir)(t2-t1)= Ip1+dIdt. Другими словами, при постоянном шаге по параметру приращение интенсивности постоянно. Закраска Гуро дает более реалистичное представление поверхности, однако не устраняет полностью полос Маха, так как обеспечивает только непрерывность значений интенсивностей вдоль границ многоугольников, не обеспечивая непрерывности изменения интенсивности (функция непрерывна, но производная имеет разрыв). Вторая проблема метода связана с тем, что усреднение нормалей может давать одинаковый результат для различно ориентированных многоугольников, что приводит к искажению изображения. Рассмотрим пример. Выходом из данной ситуации является введение дополнительных многоугольников. Закраска Фонга Закраска Фонга предполагает интерполяцию не рассчитанных значений интенсивностей, а векторов нормалей. Такой подход требует значительно больших объемов вычислений, но при этом получается более реалистичное изображение. nQ=unA+(1-u)nB 0 u 1 nR=wnB+(1-w)nC 0 w 1 nP=tnQ+(1-t)nR 0 t 1 где u=AQ/AB, w=BR/BC, t=QP/QR nP2 = nP1+(nQ-nR)(t2-t1) = nP1+dndt 3 Цвет в машинной графике Цвет — чрезвычайно сложная проблема, т. к. он имеет как психофизиологическую, так и физическую природу. Другими словами, цвет предмета зависит не только от самого предмета, но также и от источника света, освещающего предмет, и от системы человеческого видения. Более того, одни предметы отражают свет (доска, бумага), а другие его пропускают (стекло, вода). Если поверхность, которая отражает только синий свет, освещается красным светом, она будет казаться черной. Аналогично, если источник зеленого света рассматривать через стекло, пропускающее только красный свет, от тоже покажется черным. Самым простым является ахроматический цвет, т. е. такой, какой мы видим на экране черно-белого телевизора. При этом белыми выглядят объекты, ахроматически отражающие более 80% света белого источника, а черными — менее 3%. Промежуточные значения дают различные оттенки серого. Единственным атрибутом такого цвета является интенсивность или количество. С интенсивностью можно сопоставить скалярную величину, определяя черное как 0, а белое как 1. Тогда среднесерому цвету будет соответствовать значение 0.5. Если воспринимаемый свет содержит длины волн в произвольных неравных количествах, то он называется хроматическим. При субъективном описании такого цвета 45 обычно используют три величины: цветовой тон, насыщенность и светлота. Цветовой тон позволяет различать цвета, такие как красный, зеленый, желтый и т. д. Насыщенность характеризует чистоту, т. е. степень ослабления (разбавления) данного цвета белым светом, и позволяет отличать розовый цвет от красного, изумрудный от ярко-зеленого и т. д. Другими словами, по насыщенности судят о том, насколько мягким или резким кажется цвет. Светлота отражает представление об интенсивности, как о факторе, не зависящем от цветового тона и насыщенности. В основе трехкомпонентной теории света лежит предположение о том, что в центральной части сетчатки глаза находятся три типа чувствительных к цвету колбочек. Первый воспринимает зеленый цвет, второй — красный, а третий — синий цвет. Относительная чувствительность глаза максимальна для зеленого цвета и минимальна для синего. Если на все три типа колбочек воздействует одинаковый уровень энергетической яркости, то свет кажется белым. Ощущение белого цвета можно получить, смешивая любые три цвета, если ни один из них не является линейной комбинацией двух других. Такие цвета называют основными. Человеческий глаз способен различать около 350 000 различных цветов. В компьютерной графике применяются две системы смешивания основных цветов: аддитивная — красный, зеленый, синий (RGB) и субтрактивная — голубой, пурпурный, желтый (CMYK). Цвета одной системы являются дополнительными к цветам другой: голубой — к красному, пурпурный — к зеленому, а желтый — к синему. Дополнительный цвет — это разность белого и данного цветов. Субтрактивная система цветов CMYK применяется для отражающих поверхностей, например, типографских красок, пленок и несветящихся экранов. Аддитивная цветовая система RGB удобна для светящихся поверхностей, например экранов ЭЛТ или цветных ламп и т.д. Цветовые пространства RGB и CMYK трехмерны, и их условно можно изобразить в виде куба. Началом координат в кубе RGB служит черный цвет, а в СMYK — белый. Рис. __. Цветовые кубы: RGB (a), CMY (б) Ахроматические, т. е. серые цвета в обеих моделях расположены по диагонали от черного до белого, а дополнительные лежат в противоположных вершинах. Преобразование между пространствами RGB и CMY выражается следующим образом: [RGB] = [1 1 1]-[CMY]. В OpenGL используется цветовая модель RGB. Художники пользуются иными принципами и характеризуют цвета как различные разбелы, оттенки и тона предельно насыщенных или чистых пигментов. Разбел получается при добавлении белого пигмента к чистому пигменту; при этом уменьшается насыщенность. Оттенок получается при добавлении черного пигмента к чистому пигменту, в результате чего снижается светлота. Тона получаются при добавлении черного и белого пигментов к чистому пигменту. Во всех этих случаях получаются различные цвета одного и того же цветового тона, отличающиеся насыщенностью и светлотой. При смешении только черного и белого пигментов получаются серые цвета. На рис. 17.9 показаны соотношения между разбелами, оттенками и тонами. Можно было бы предложить измерять цвет процентным содержанием пигментов, смешение которых дает интересующий нас цвет. 46 Разбелы Белый "Чистящий" цвет Тона Серый Оттенки Черный Рис. ___. Разбелы, тона и оттенки V Зеленый Желтый 1, 0 Голубой Белый Красный Пурпурный Синий H S 0, 0 Черный Рис. __. Одиночный шестигранный конус цветовой модели HSV. Зеленый Желтый Белый Голубой Синий Красный Пурпурный Рис. __. Цветовой куб модели RGB, если на него смотреть вдоль главной диагонали. Видимые ребра куба изображены сплошными линиями, а невидимые – штриховыми. 47 3.1 Цветовая модель HSV Цветовые модели RGB, CMYK являются аппаратно-ориентированными. В отличие от них предложенная Смитом модель HSV ориентирована на пользователя. В ее основу положены интуитивно принятые художниками понятия разбела, оттенка и тона. Подпространство, определяемое моделью, представляет собой шестигранный конус (рис. 2). Верхняя часть шестигранного конуса соответствует значению V=1; цвета при этом выражены с наибольшей интенсивностью. Отметим, что дополнительные цвета расположены друг против друга, т. е. отличаются один от другого на угол H=180°. Этот угол отсчитывается вокруг вертикальной оси, причем начало отсчета совпадает с красным цветом. Значением S является отношение, изменяющееся в диапазоне от 0 на осевой линии (ось V) до 1 на треугольных боковых гранях шестигранного конуса. Насыщенность измеряется относительно цветового охвата, задаваемого моделью. Высота шестигранного конуса составляет единицу по координате V, а вершина конуса лежит в начале координат. Точка, в которой находится вершина, соответствует черному цвету; ее координата V=0. С точкой V=0 может быть связано любое значение координаты S в диапазоне 0—1. Точка с координатами S=0, V=1 соответствует белому цвету. Промежуточные значения координаты V при S=0 (т. е. на осевой линии) соответствуют серым цветам. При S=0 значение H считается неопределенным. Если же S не равно нулю, значение H уже определено. Например, чистому красному цвету соответствуют координаты H=0, S=1, V=1. В самом деле, любой цвет с координатами V=1, S=1 похож на чистый пигмент, который художники используют в качестве начального приближения при смешении цветов. Добавление белого пигмента соответствует уменьшению V (без изменения S). Тона получаются путем уменьшения как S, так и V. И наконец, меняя координату H, можно выбрать чистый пигмент, с которым будем работать. Таким образом, координаты H, S и V взаимно однозначно соответствуют понятиям цветовой системы художника. 48 Лекция 8. Текстуры. Наложение текстуры Для чего нужны текстуры Текстуры являются важным средством создания реалистических изображений. Они позволяют избежать кропотливой работы по прорисовке мелких деталей делающих изображения легко узнаваемыми. Как бы мы не закрашивали поверхность параллелепипеда, он не будет выглядеть сделанным из дерева, пока мы не нанесем характерную для дерева фактуру. Создание изображения кирпичной стены из отдельных примитивов, имитирующих кирпичи, является достаточно трудоемким занятием и получившийся результат будет не очень хорошим, из-за излишней правильности. Гораздо проще наложить текстуру, полученную из фотографии реальной стены на единственный прямоугольник. Подобных примеров можно привести очень много. Текстуры используются при изображении элементов поверхности земли – растительности, гор, водоемов, с их помощью создают иллюзии различных материалов – камня, пластмассы, тканей, на основе текстур создаются различные спецэффекты, такие как отражение одних объектов сцены в других и многое другое. Что же такое текстуры? Текстуры можно рассматривать как прямоугольные массивы данных, хранящие информацию о цвете. Массивы могут быть одно, двух, трех или четырех мерными. Данные для текстуры могут быть взяты из отсканированного или созданного в графическом редакторе изображения, а так же сгенерированны программно. Для изучения рассмотрим сначала наложение двумерных текстур, так как оно интуитивно более понятно. Массив данных часто называют картой текстуры. А элемент массива по аналогии с пикселем называют текселем. Давайте разберемся, каким же образом накладывается текстура на геометрический объект. Прежеде всего необходимо задать функцию отображения с помощью которой можно определить тексель текстуры который будет использоваться для тонирования каждой точки объекта. Мы уже говорили о том, что геометрические примитивы задаются координатами вершин, а все внутренние точки (пиксели), визуализирующие объект, определяются в процессе растеризации примитива. Цвет внутренних точек определяется за счет билинейной интерполяции значений рассчитанных для вершин. Представим координаты текстуры как линейные параметрические функции от параметров s и t, приведенных к диапазону от 0 до 1. Тогда левому нижнему углу текстуры будут соответсвовать параметры s=0, t=0 Обратное отображение. glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_DECAL); Разрешение и запрещение наложения текстур производится с помощью команд glEnable glDisable, в аргументе которых указывается тип используемой текстуры. Допустимыми значениями являются GL_TEXTURE_1D и GL_TEXTURE_2D. Команда glTexCoord [1 2 3 4][ s i f d ub us ui][v](s,t,r,q) позволяет связать координаты текстуры с координатами вершин многоугольника. Обратите внимание на то, что данная команда изменяет текущие значения координат текстуры. Все вершины определенные после данной команды будут связываться с текущими значениями, пока они вновь не будут изменены рассматриваемой командой. Другими словами, если вы хотите задать для вершин различные значения координат текстуры, необходимо установить требуемые координаты перед определением вершины. Двумерная текстура определяется командой glTexImage2D( GLenum, level GLint, 49 intrnalFormat GLint, width GLsizei, height GLsizei, border GLint, format GLenum, type GLenum, *texels ); Где параметр target может принимать одно из двух значений GL_TEXTURE_2D или GL_PROXY_TEXTURE_2D. В случае использования первого значения создается двумерная текстура иначе производится тестирование возможности системы обработать двумерную текстуру с указанными далее характеристиками. Параметр level задает уровень детализации для создаваемой текстуры. Значения этого параметра задаются отличными от 0, только при задании многоуровневых текстур для MIPотображения. IntrnalFormat – показывает какую информацию и в каком виде вы хотите хранить в текселе. Допустимыми для использования являются 38 символических констант. Например, GL_RGBA требует хранения величин трех основных цветов и альфа канала, GL_ALFA а константа GL_R3_G3_B2 запрашивает по 3 бита для хранения величит красного и зеленого цветов, а так же 2 бита для хранение голубого цвета. OpenGL не гарантирует совпадения внутреннего формата, с тем форматом который вы запрашиваете, но выбранный системой формат, обеспечит корректное хранение вводимых вами данных. Параметры width и height задают ширину и высоту текстуры. Величины этих параметров должны иметь значения определяемые выражением 2m + 2(border), где m целое положительное число. К нашему сожалению, максимально допустимые размеры текстур не велики (64, 128 или 256 в зависимости от реализации). Параметр *texels задает указатель на массив, хранящий данные для текстуры. Параметр type указывает базовый тип массива, а параметр format говорит о том, в каком формате хранятся данные в массиве. Допустимыми значениями определяются константами GL_ALPHA, GL_RGB, GL_RGBA и другими. Режимы фильтрации в OpenGL задаются командой glTexParameter[f, i][v]( target GLenum, pname GLenum, param) где параметр target определяет тип используемой текстуры GL_TEXTURE_1D, GL_TEXTURE_2D, GL_TEXTURE_3D. Параметр pname определяет, какой из фильтров мы задаем, используемый при уменьшении - GL_TEXTURE_MIN_FILTER или применяемый при увеличении текстуры -GL_TEXTURE_MAG_FILTER. Параметр парам определяет конкретный метод фильтрации. При увеличении допустимы следующие константы: GL_NEAREST – при фильтрации выбирается тексель, расположенный ближе всего к отображению центра пикселя; GL_LINEAR - при фильтрации используется средневзвешенное значение четырех текселей лежащих вокруг отображения центра пикселя. При увеличении всегда используется текстура нулевого уровня, не зависимо от того, определено MIP-отображение или нет. При уменьшении также используются рассмотренные методы фильтрации. Кроме того если полностью определено MIP-отображение, то можно использовать дополнительные фильтры: GL_NEAREST_MIPMAP_NEAREST – фильтрация производится аналогично методу GL_NEAREST, но выбор текселя производится не на нулевом уровне, а на уровне выбранном системой исходя из размеров текстурируемого объекта; GL_LINEAR_MIPMAP_NEAREST – фильтрация производится аналогично методу GL_LINEAR, но выбор текселя производится не на нулевом уровне, а на уровне выбранном системой исходя из размеров текстурируемого объекта; GL_NEAREST_MIPMAP_LINEAR – при данном методе выбирается ближайший тексель в двух картах, заданных MIP-отображением, а результирующее значение находится линейной интерполяцией; GL_LINEAR_MIPMAP_LINEAR – метод фильтрации требующий наибольших вычислительных затрат, но дающий самое высокое качество. На двух картах производится линейная интерполяция по методу GL_LINEAR, а результирующее значение получается 50 линейной интерполяцией между значениями, полученными для каждой из двух карт. Обратите внимание, последние два метода смягчат резкую смену изображений при переходе с одной карты на другую. Этой же командой можно определять поведение текстуры при выходе параметра за диапазон [0..1]. Задав значение pname одной из констант: GL_TEXTURE_WRAP_S, GL_TEXTURE_WRAP_T или GL_TEXTURE_WRAP_R, мы выбираем поведение какого параметра текстуры будет определяться. Для рaram допустимы следующие символические константы: GL_CLAMP (фиксация) – при выходе из диапазона значение соответствующего параметра заменяется граничным значением. Если параметр текстуры превысил единицу его значение заменяется на единицу, если параметр меньше нуля он заменяется на 0. Это приводит к тому, что текстурировании пикселей изображения, для которых параметры текстуры выходят из указанного диапазона используются граничные пиксели текстуры; GL_REPEAT (повторение) – при выходе из диапазона, указанный параметр, нормируется (отбрасывается целая часть), что приводит к повторению текстуры. Способ наложения текстуры на объект выбирается командой GlTexEnv[i, f][v](target GLenum, pname GLenum, params). Параметр target должен быть константой GL_TEXTURE_ENV. Параметр pname указывает на то, определяем мы функцию (режим) текстурирования - GL_TEXTURE_ENV_MODE или дополнительный цвет - GL_TEXTURE_ENV_COLOR, использующийся в режиме смешивания (только для векторной версии команды). В первом случае params может принимать следующие значения: GL_REPLACE, GL_MODULATE, GL_DECAL и GL_BLEND, устанавливающие соответствующие функции текстурирования. При задании дополнительного цвета params содержит указатель на массив, определяющий R-,G-,B-, и A-компоненты. Остановимся подробнее на функциях текстурирования. Константа GL_REPLACE устанавливает замещающую функцию, которая проводит простую замену цвета объекта на цвет текстуры. Обратите внимание, что работа всех функций зависит от внутреннего формата данных текстуры (смотри параметр IntrnalFormat в команде glTexImage). Так, при замещении, если внутренний формат текстуры определен как GL_RGB, произойдет замещение R-,G-, и B-компонент, а значение альфа канала останется неизменным. В текстуре не хранится информация о альфа канале. И наоборот если внутренний формат текстуры GL_ALPHA, то произойдет замещение только значений альфа канала, так как в текстуре нет информации о цвете. При создании реальных сцен чаще всего требуется использовать несколько текстур. Удобнее сначала подготовить необходимые текстуры, а в процессе вывода просто переключаться между ними, чем постоянно загружать требуемые текстуры. Процесс создания текстуры довольно длительный, поэтому данный подход существенно повышает эффективность программы при создании анимированных сцен. OpenGL предоставляет возможность работы с текстурными объектами. Основной командой для работы с текстурными объектами служит команда связывания текстурного объекта. glBindTexture(target GLenum, textureName GLuint). Параметр target определяет тип текстуры, допустимые значения задаются константами GL_TEXTURE_1D, GL_TEXTURE_2D, GL_TEXTURE_3D. Аргумент textureName определяет имя текстурного объекта. В качестве имени текстуры может служить целое число. Во избежание повторения имен реализована специальная процедура glGenTextures, генерирующая список не занятых имен. Аргументы процедуры указывают требуемое количество имен и массив, в котором сгенерированные имена будут размещены. Обратите внимание на то, что вызов процедуры glBindTexture с одинаковыми параметрами может иметь различный смысл. При первом вызове команды происходит создание текстурного объекта выбранного типа с указанным именем. Повторный вызов процедуры связывания, для объекта с тем же именем, устанавливает выбранный текстурный объект текущим. После этого связанная с данным объектом текстура будет 51 использоваться для текстурирования выводимых объектов. Вызов процедуры со значением параметра textureName равным 0, устанавливает текущей текстурный объект, используемый библиотекой по умолчанию (этот объект используется в том случае когда пользователь не выполняет явного создания текстурных объектов). Явное связывание координат объекта с текстурой не всегда удобно. Предположим, что ваш объект состоит из нескольких десятков (а возможно и сотен) маленьких многоугольников и необходимо наложить на объект одну большую текстуру. Согласитесь, что объем требуемых расчетов координат текстуры довольно велик. OpenGL предоставляет возможность автоматически рассчитать координаты текстуры исходя из координат объекта. Включение (выключение) автоматической генерации координат текстуры производится командой glEnable (glDisable), в аргументе которой указывается параметр текстуры для которого разрешается генерация. Допустимыми значениями являются с аргументами GL_TEXTURE_GEN_S, GL_TEXTURE_GEN_T, GL_TEXTURE_GEN_R, GL_TEXTURE_GEN_Q. Способы расчета задаются командой glTexGen[d f i][v](coord GLenum, pname GLenum, param GLdouble). Первый аргумент команды определяет координату текстуры для которой проводится определение, допустимые значения GL_S, GL_T, GL_R, или GL_Q. Параметр pname указывает какой параметр генерации задается. Если значение данного параметра равно GL_TEXTURE_GEN_MODE то данная команда будет устанавливать режим генерации текстуры, в противном случае (значения параметра GL_OBJECT_PLANE или GL_EYE_PLANE) будут задаваться свойства выбранного режима. Сначала рассмотрим допустимые режимы расчета координат текстуры, их три: GL_OBJECT_LINEAR – в этом режиме расчет координат текстуры производится исходя из координат вершин в координатной системе объекта. То есть тех значений которые вы определили при выводе объекта, между операторными скобками glBegin – glEnd. Для получения значений координат текстуры для внутренних точек объекта используется линейная интерполяция. Координаты текстуры рассчитываются по формуле g = p 1xo + p2yo+p3zo+p4wo где xo,yo,zo,wo – координаты вершины, а p1, p2, p3, p4 - коэффициенты, механизм назначения которых мы рассмотрим немного ниже. По умолчанию для ………. Использование данного режима приводит к тому, то всем преобразованиям, накапливаемым в матрице преобразования модели, подвергаются как объекты так и связанные с ними параметры текстуры. Например, если мы подвергнем объект преобразованию поворота, то наложенная на него текстура повернется вместе с объектом. В геометрической интерпретации приведенную формулу можно рассматривать как уравнение плоскости, тогда значение координаты текстуры определиться как расстояние от плоскости до вершины. С другой точки зрения, можно рассмотреть данную формулу как функцию, отображающую координаты вершины в координату текстуры. Коэффициенты p 1, p2, p3 рассматривать как масштабирующие множители, а коэффициент p 4 – будет определять величину сдвига (переноса), так как в однородных координатах обычно w = 1. Предположим, что мы накладывает текстуру на квадрат с единичной стороной, центром которого является начало координат. Для упрощения примера расположим его параллельно плоскости z=0. , GL_EYE_LINEAR, or GL_SPHERE_MAP. 52 Лекция 9. Удаление невидимых линий. 1 Задача преодоление неоднозначности 2 Алгоритмы удаления невидимых линий и поверхностей 2.1 Алгоритм плавающего горизонта 2.2 Алгоритм Ньюэла М., Ньюэла Р.и Санча 2.3 Алгоритм, использующий Z-буфер 2.4 Алгоритм Вейлера— Азертона 2.5 Алгоритм определения видимым поверхностей методом трассировки лучей В процессе визуализации объектов, представленных геометрическими моделями возникает задача ликвидации неоднозначностей в создаваемом представлении. Данная задача может быть решена различными способами. Рассмотрим простой пример визуализации пирамиды, представленной каркасной моделью, рис. a) b) с) Рисунок . Ликвидация неоднозначности визуального представления модели По представленному на рисунке a) образу мы не можем точно сказать, как прирамида ориентирована в пространстве. Использование простейшего метода ореола, рисунок b), улучшает ситуацию, теперь мы можем однозначно сказать, как расположена пирамида. Однако, при визуализации сложных моделей данный метод не дает хороших результатов. Для получения хорошего решения необходимо удалить невидимые для наблюдателя линии и поверхности, рисунок c). Удаление невидимых линий и поверхностей. Удаление невидимых линий и поверхностей это одна из сложнейших задач решаемых при визуализации графических моделей. Алгоритмы удаления невидимых линий и поверхностей служат для определения видимости линий, ребер, поверхностей или объемов с точки зрения наблюдателя расположенного в заданной точке пространства. Наилучшего общего решения данной задачи несуществует. Создано большое количество различных способов решения задачи ориентированных на специализированные приложения. Выбор подходящего алгоритма зависит от нескольких факторов: Требуемой эффективности алгоритма и качества получаемого изображения. Безусловно, получение хорошего качества требует больших вычислительных затрат, соответственно для создания анимированных и статических сцен необходимо использовать различные методы. Используемой геометрической модели. Требуемая для работы алгоритмов исходная информация может отличаться. Необходимости создания различных визуальных эффектов – освещения, прозрачности, зеркального отражения и др. Как правило, простые, эффективные алгоритмы удаления невидимых линий и поверхностей не дают возможности реализовать зеркальное отражение объектов сцены друг от друга и др. сложные эффекты. 53 Рассматриваемые алгоритмы можно классифицировать по системе координат в которой они работают: Алгоритмы работающие в объектном пространстве имеют дело с физической системой координат в которой заданы объекты. (например мировые координаты). Они обладают высокой точностью, возможностью масштабирования, но не высокой эффективностью; Алгоритмы работающие в пространстве изображения имеют дело с экранными координатами и как следствие обладают точностью вычислений до пиксела, при высокой эффективности. Большинство алгоритмов включают в себя сортировку. Обычно она проводится по геометрическому расстоянию от объекта до точки наблюдения. Чем дальше расположен от точки наблюдения объект, тем больше вероятность того, что он будет полностью или частично заслонен другими объектами. Для точного определения перекрытия необходимы дополнительные сортировки по горизонтали и вертикали. Рассмотрим принципы построения нескольких алгоритмов удаления невидимых линий и поверхностей. Алгоритм плавающего горизонта Алгоритм плавающего горизонта чаще всего используется для удаления невидимых линий трехмерного представления функций, описывающих поверхность в виде: F(x, у, z) = 0 Подобные функции возникают во многих приложениях в математике, технике, естественных науках и других дисциплинах. Алгоритм обычно работает в пространстве изображения. Главная идея метода заключается в сведении трехмерной задачи к двумерной путем пересечения исходной поверхности последовательностью параллельных секущих плоскостей, имеющих постоянные значения координат х, у или z. На рисунке 1 приведен пример, где указанные параллельные плоскости определяются постоянными значениями z. Функция F(x, у, z) = 0 сводится к последовательности кривых, лежащих в каждой из этих параллельных плоскостей, например к последовательности функций вида у = f(x, z) где z постоянно на каждой из заданных параллельных плоскостей. Итак, поверхность теперь складывается из последовательности кривых, лежащих в каждой из этих плоскостей, как показано на рисунке 3. Здесь предполагается, что полученные кривые являются однозначными функциями независимых переменных. 54 Если спроецировать полученные кривые на плоскость z=0, как показано на следующем рисунке, то сразу становится ясна идея алгоритма удаления невидимых участков исходной поверхности. Алгоритм сначала упорядочивает плоскости z = const по возрастанию расстояния до них от точки наблюдения. Затем для каждой плоскости, начиная с ближайшей к точке наблюдения, строится кривая, лежащая на ней, т. е. для каждого значения координаты х в пространстве изображения определяется соответствующее значение у. Алгоритм удаления невидимой линии заключается в следующем: если на текущей плоскости при некотором заданном значении х соответствующее значение у на кривой больше значения у для всех предыдущих кривых при этом значении х, то текущая кривая видима в этой точке; в противном случае она невидима. Невидимые участки показаны пунктиром на рисунке 3. Реализация данного алгоритма достаточно проста. Для хранения максимальных значений у при каждом значении х используется массив, длина которого равна числу различимых точек (разрешению) по оси х в пространстве изображения. Значения, хранящиеся в этом массиве, представляют собой текущие значения “горизонта”. Поэтому по мере рисования каждой очередной кривой этот горизонт “всплывает”. Фактически этот алгоритм удаления невидимых линий работает каждый раз с одной линией. Алгоритм работает очень хорошо до тех пор, пока какая-нибудь очередная кривая не окажется ниже самой первой из кривых. Подобные кривые, естественно, видимы и представляют собой нижнюю сторону исходной поверхности, однако алгоритм будет считать их невидимыми. Нижняя сторона поверхности делается видимой, если модифицировать этот алгоритм, включив в него нижний горизонт, который опускается вниз по ходу работы алгоритма. Это реализуется при помощи второго массива, длина которого равна числу различимых точек по оси х в пространстве изображения. Этот массив содержит наименьшие значения у для каждого значения х. Алгоритм теперь становится таким: если на текущей плоскости при некотором заданном значении х соответствующее значение у на кривой больше максимума или меньше минимума по у для всех предыдущих кривых при этом х, то текущая кривая видима. В противном случае она невидима. Ньюэл М., Ньюэл Р.и Санча При реализации всех обсуждавшихся алгоритмов удаления невидимых линий и поверхностей устанавливались приоритеты, т. е. глубины объектов сцены или их расстояния от точки наблюдения. Алгоритмы, использующие список приоритетов, пытаются получить преимущество посредством предварительной сортировки по глубине или приоритету. Цель такой сортировки состоит в том, чтобы получить окончательный список элементов сцены, упорядоченных по приоритету глубины, основанному на расстоянии от точки наблюдения. Если такой список окончателен, то никакие два элемента не будут взаимно перекрывать друг друга. Тогда можно записать все элементы в буфер кадра поочередно, начиная с элемента, наиболее удаленного от точки наблюдения. Более близкие к наблюдателю элементы будут затирать информацию о более далеких элементах в буфере кадра 55 Для простых элементов сцены, например для многоугольников, этот метод иногда называют алгоритмом художника, поскольку он аналогичен тому способу, которым художник создает картину. Сначала художник рисует фон, затем предметы, лежащие на среднем расстоянии, и, наконец, передний план. Тем самым художник решает задачу об удалении невидимых поверхностей, или задачу видимости, путем построения картины в порядке обратного приоритета. Рис 1. Установление приоритетов для многоугольников. Для простой сцены, вроде той, что показана на рис. 1, а, окончательный список приоритетов можно получить непосредственно. Например, эти многоугольники можно упорядочить по их максимальному или минимальному значению координаты z. Однако уже для сцены, показанной на рис.1, b, окончательный список приоритетов по глубине невозможно получить простой сортировкой по z. Если Р и Q с рис. 1, b упорядочены по минимальному значению координаты z (zmin), окажется, что P в списке приоритетов по глубине будет стоять перед Q. Если их записать в буфер кадра в таком порядке, то получится, что Q частично экранирует Р. Однако фактически Р частично экранирует Q. Правильный порядок в списке приоритетов будет тогда, когда Р и Q поменяются местами. Другие трудности показаны на рис. 2. Здесь многоугольники циклически перекрывают друг друга. На рис. 2, а Р находится впереди Q, который лежит впереди R, который, в свою очередь, находится впереди Р. На рис. 2, b Р экранирует Q, a Q экранирует Р. Аналогичное циклическое экранирование возникает при протыкании многоугольников. В обоих примерах окончательный список приоритетов невозможно установить сразу. Выход из положения заключается в циклическом разрезании многоугольников по линиям, образованным пересечениями их плоскостей до тех пор, пока не будет получен окончательный список приоритетов. Такие линии показаны пунктиром на рис. 2. Ньюэл М., Ньюэл Р.и Санча предложили специальный метод сортировки для разрешения конфликтов, возникающих при создании списка приоритетов по глубине. Этот метод включен в состав алгоритма Ньюэла - Ньюэла - Санча, который излагается ниже. В алгоритме динамически вычисляется новый список приоритетов перед обработкой каждого кадра сцены. Не накладывается никаких ограничений на сложность сцены и на тип многоугольников, используемых для описания элементов сцены. Первоначальный алгоритм Ньюэла - Ньюэла - Санча был предназначен для обработки трехмерных тел. Это расширение не ограничено рамками многогранников. Оно может, кроме того, обрабатывать тела смешанных типов в рамках одной сцены. 56 Рис. 2. Циклически перекрывающиеся многоугольники. Алгоритм Ньюэла-Нюэла-Санча Это представитель класса алгоритмов основанных на точной сортировке по глубине. Если удается получить точно отсортированный список, то никакие два объекта не будут взаимно перекрывать друг друга. Сформировать предварительный список приоритетов по глубине, используя в качестве ключа сортировки значение zmin для каждого многоугольника. Первым в списке будет многоугольник с минимальным значением zmin. Этот многоугольник лежит дальше всех от точки наблюдения, расположенной в бесконечности на положительной полуоси z. Обозначим его через Р, а следующий в списке многоугольник - через Q. Для каждого многоугольника Р из списка надо проверить его отношение с Q: 1. если ближайшая вершина Р (Рzmax) будет дальше от точки наблюдения, чем самая удаленная вершина Q (Qzmin), т.е. Qzmin >= Рzmax и никакая часть Р не может экранировать Q. Занести Р в буфер кадра (рис.1, а); 2. если Qzmin < Рzmax потенциально P экранирует не только Q, но также и любой другой многоугольник типа Q из списка, для которого Qz min < Рzmax. Тем самым образуется множество [Q]. Однако Р может фактически и не экранировать ни один из этих многоугольников. Если последнее верно, то Р можно заносить в буфер кадра. Для ответа на этот вопрос используется серия тестов, следующих по возрастанию их вычислительной сложности. Эти тесты ниже формулируются в виде вопросов. Если ответ на любой вопрос будет положительным, то Р не может экранировать {Q}. Поэтому Р сразу же заносится в буфер кадра. Вот эти тесты: a. Верно ли, что прямоугольные объемлющие оболочки Р и Q не перекрываются по х ? b. Верно ли, что прямоугольные оболочки Р и Q не перекрываются по у ? c. Верно ли, что Р целиком лежит по ту сторону плоскости, несущей Q, которая расположена дальше от точки наблюдения (рис.3,а)? d. Верно ли, что Q целиком лежит по ту сторону плоскости, несущей P, которая ближе к точке наблюдения (рис. 3, b)? e. Верно ли, что проекции Р и Q не перекрываются? Каждый из этих тестов применяется к каждому элементу {Q}. Если ни один из них не дает положительного ответа и не заносит Р в буфер кадра, то Р может закрывать Q. Поменять Р и Q местами, пометив позицию Q в списке. Повторить тесты с новым списком. Это дает положительный результат для сцены с рис. 1, b. 57 Рис. 3. Тесты для перекрывающихся многоугольников. Если сделана попытка вновь переставить Q значит обнаружена ситуация циклического экранирования (рис.2). В этом случае Р разрезается плоскостью, несущей Q, исходный многоугольник Р удаляется из списка, а его части заносятся в список. Затем тесты повторяются для нового списка. Этот шаг предотвращает зацикливание алгоритма. Взятые вместе, первые два из приведенных выше вопросов образуют обычный габаритный тест для прямоугольных оболочек. Поскольку многие сцены не являются квадратными, то прямоугольные объемлющие оболочки будут с большей вероятностью перекрываться в одном из двух возможных направлений. Когда многоугольники преимущественно горизонтальны или вертикальны, то использование одного из этих двух тестов оказывается более эффективным. В алгоритме, в той форме, в которой он записан выше, предполагается, что ширина сцены больше ее высоты, т. е. многоугольники преимущественно являются горизонтальными. Если высота сцены больше ее ширины, то тесты следует поменять местами. Если же сцена является квадратной или ее структура изоморфна, то порядок применения этих тестов не имеет значения. Третий и четвертый тесты можно реализовать с использованием некоторых из ранее обсуждавшихся тестов видимости. Поскольку уравнение несущей плоскости или нормаль к ней часто известны для каждого многоугольника, то удобно применить простой тест подстановки. Если исследуется отношение многоугольника Q к многоугольнику Р, то координаты вершин Q подставляются в уравнение плоскости, несущей Р. Если все знаки результатов подстановки совпадают, то Q целиком лежит по одну сторону от Р. Здесь, так же как и в других алгоритмах удаления невидимых поверхностей, обсуждавшихся ранее, если это нужно, производится предварительное удаление нелицевых граней Алгоритм использующий Z-буфер Впервые он был предложен Кэтмулом. Работает этот алгоритм в пространстве изображения. Главное преимущество алгоритма - его простота. Кроме того, этот алгоритм решает задачу об удалении невидимых поверхностей и делает тривиальной визуализацию пересечений сложных поверхностей. Сцены могут быть любой сложности. Поскольку габариты пространства изображения фиксированы, оценка вычислительной трудоемкости алгоритма не более чем линейна. Так как элементы сцены или картинки можно заносить в буфер кадра или в z-буфер в произвольном порядке, их не нужно предварительно сортировать по приоритету глубины. Поэтому экономится вычислительное время, затрачиваемое на сортировку по глубине. Основной недостаток алгоритма - большой объем требуемой памяти. Если сцена подвергается видовому преобразованию и отсекается до фиксированного диапазона координат z значений, то можно использовать z-буфер с фиксированной точностью. Информацию о глубине нужно обрабатывать с большей точностью, чем координатную информацию на плоскости (x, у); обычно бывает достаточно 20 бит. Буфер кадра размером 512х512х24 бит в комбинации с z-буфером размером 512х512х20 бит требует почти 1.5 мегабайт памяти. Альтернативой созданию специальной памяти для z -буфера является использование для этой цели оперативной памяти. Уменьшение требуемой памяти достигается 58 разбиением пространства изображения на 4, 16 или больше квадратов или полос. В предельном варианте можно использовать z -буфер размером в одну строку развертки. Для последнего случая имеется интересный алгоритм построчного сканирования . Поскольку каждый элемент сцены обрабатывается много раз, то сегментирование zбуфера, вообще говоря, приводит к увеличению времени, необходимого для обработки сцены. Однако сортировка на плоскости, позволяющая не обрабатывать все многоугольники в каждом из квадратов или полос, может значительно сократить этот рост. Другой недостаток алгоритма z-буфера состоит в трудоемкости и высокой стоимости устранения лестничного эффекта, а также реализации эффектов прозрачности и просвечивания. Поскольку алгоритм заносит пикселы в буфер кадра в произвольном порядке, то нелегко получить информацию, необходимую для методов устранения лестничного эффекта, основывающихся на предварительной фильтрации. При реализации эффектов прозрачности и просвечивания , пикселы могут заноситься в буфер кадра в некорректном порядке, что ведет к локальным ошибкам. Более формальное описание алгоритма z-буфера таково: заполнить буфер кадра фоновым значением интенсивности или цвета. заполнить z-буфер минимальным значением z; преобразовать каждый многоугольник в растровую форму в произвольном порядке; для каждого Пиксел(x, y) в многоугольнике вычислить его глубину z(x, у); сравнить глубину z(x, у) со значением Z буфер( x, у), хранящимся в z -буфере в этой же позиции; если z(х, у) > Z буфер (х, у), то записать атрибут этого многоугольника (интенсивность, цвет и т. п.) в буфер кадра и заменить Z буфер( х, у) на z ( х, у); в противном случае никаких действий не производить; в качестве предварительного шага там, где это целесообразно, применяется удаление нелицевых граней ; Интервальный алгоритм построчного сканирования В алгоритме построчного сканирования с использованием z-буфера глубина многоугольника вычисляется для каждого пиксела на сканирующей строке. Количество вычислений глубины можно уменьшить, если использовать понятие интервалов, впервые введенных в алгоритме Ваткинса. На рис. 1, а показано пересечение многоугольников со сканирующей плоскостью. Решение задачи удаления невидимых поверхностей сводится к выбору видимых отрезков в каждом из интервалов, полученных путем деления сканирующей строки проекциями точек пересечения ребер. Из рисунка видно, что возможны только три варианта: Рис. 1. Интервалы для построчного сканирования. Интервал пуст, как, например, интервал 1 на рис. 1.а. - изображается фон. Интервал содержит лишь один отрезок, как, например, интервалы 2 и 4 на рис. 1.а. изображаются атрибуты многоугольника, соответствующего отрезку. Интервал содержит несколько отрезков, как, например, интервал 3 на рис. 1.а. В этом случае вычисляется глубина каждого отрезка в интервале. Видимым будет отрезок с максимальным значением г. В этом интервале будут изображаться атрибуты видимого отрезка. Если многоугольники не могут протыкать друг друга, то достаточно вычислять глубину каждого отрезка в интервале на одном из его концов. Если два отрезка касаются, но не проникают в концы интервала, то вычисление глубины производится в середине 59 интервала, как показано на рис. 1.b. Для интервала 3 вычисление глубины, проведенное на его левом конце, не позволяет принять определенное решение. Реализация вычисления глубины в центре интервала дает уже корректный результат, как показано на рис. 1.b. Если многоугольники могут протыкать друг друга, то сканирующая строка делится не только проекциями точек пересечения ребер со сканирующей плоскостью, но и проекциями точек их попарного пересечения, как показано на рис. 1.с. Вычисление глубины в концевых точках таких интервалов будет давать неопределенные результаты. Поэтому здесь достаточно проводить вычисление глубины в середине каждого интервала, как показано для оси х на рис. 1.с. Используя более сложные меептоды порождения интервалов, можно сократить их число, а следовательно, и вычислительную трудоемкость Алгоритм Вейлера— Азертона Выходными данными этого алгоритма, который для достижения необходимой точности работает в пространстве объекта, служат многоугольники. Поскольку выходом являются многоугольники, то алгоритм можно легко использовать для удаления как невидимых линий, так и невидимых поверхностей. Алгоритм удаления невидимых поверхностей состоит из четырех шагов. Предварительная сортировка по глубине. Отсечение по границе ближайшего к наблюдателю многоугольника, называемое сортировкой многоугольников на плоскости. Удаление многоугольников, экранированных многоугольником, ближайшим к точке наблюдения. Если требуется, то рекурсивное подразбиение и окончательная сортировка для устранения всех неопределенностей. Предварительная сортировка по глубине нужна для формирования списка приблизительных приоритетов. Предположим, что точка наблюдения расположена в бесконечности на положительной полуоси z, тогда ближайшим к ней и первым в списке будет тот многоугольник, который обладает вершиной с максимальной координатой z. Рис. 4.44. Отсечение многоугольников по приоритетам для алгоритма удаления невидимых поверхностей Вейлера — Азертона. В качестве отсекающего многоугольника используется копия первого многоугольника из предварительного списка приоритетов по глубине. Отсекаться будут остающиеся в этом списке многоугольники, включая и первый многоугольник. Вводятся два списка: внутренний и внешний. С помощью алгоритма отсечения Вейлера — Азертона все многоугольники отсекаются по границам отсекающего многоугольника. Фактически это двумерная операция отсечения проекций отсекающего и отсекаемого многоугольников. Та часть каждого отсекаемого многоугольника, которая оказывается внутри отсекающего, если она имеется, попадает во 60 внутренний список. Оставшаяся часть, если таковая есть, попадает во внешний список. Этот этап алгоритма является сортировкой на плоскости или ху -сортировкой. Затем, сравниваются глубины всех вершин многоугольнов из внутреннего списка с глубиной отсекающего многоугольника. Если глубина ни одной из этих вершин не будет больше Zmin отсекающего, то все многоугольники из внутреннего списка экранируются отсекающим многоугольником. Эти многоугольники удаляются, и изображается внутренний список. Заметим, что во внутреннем списке остался лишь отсекающий многоугольник. Работа алгоритма затем продолжается с внешним списком. Если координата z. какого-либо многоугольника из внутреннего списка окажется больше, чем Zmin отсекающего, то такой многоугольник по крайней мере частично экранирует отсекающий многоугольник. В подобном случае результат предварительной сортировки по глубине ошибочен. Многоугольник, нарушивший порядок, выбирается новым отсекающим многоугольником. Отсечению подлежат многоугольники из внутреннего списка, причем старый отсекающий многоугольник теперь сам будет подвергнут отсечению новым отсекающим многоугольником. Подчеркнем, что новый отсекающий многоугольник является копией исходного многоугольника, а не его остатка после первого отсечения. Использование копии неотсеченного многоугольника позволяет минимизировать число разбиений. Более полной иллюстрацией этого алгоритма послужит следующий простой пример Рис. 4.46. Условие возникновения ошибочного результата в предварительной сортировке по z. Заслуживает внимание еще одна дополнительная деталь этого алгоритма. Когда некоторый многоугольник циклически перекрывается с отсекающим, т. е. когда он лежит как впереди, так и позади отсекающего (рис. 4.48, а), то в рекурсивном разбиении необходимости нет. Дело в том, что все экранируемое циклическим многоугольником уже было удалено на предыдущем шаге отсечения. Необходимо лишь произвести отсечение исходного многоугольника по границам циклического многоугольника и изобразить результат. Ненужное рекурсивное разбиение можно предотвратить, если создать список многоугольников, которые уже использовались как отсекающие. Тогда, если при рекурсивном разбиении текущий отсекающий многоугольник появляется в этом списке, значит, обнаружен циклически перекрывающийся многоугольник. Следовательно, не требуется никакого дополнительного разбиения. Заметим, что данный алгоритм непосредственно обрабатывает случаи циклического перекрытия сразу нескольких многоугольников, как показано на рис. 4.48, b. Алгоритм определения видимых поверхностей путем трассировки лучей Трассировка лучей является методом грубой силы. Главная идея, лежащая в основе этого метода, заключается в том, что наблюдатель видит любой объект посредством испускаемого неким источником света, который падает на этот объект и затем каким-то путем доходит до наблюдателя. Свет может достичь наблюдателя, отразившись от поверхности, преломившись или пройдя через нее. Если проследить за лучами света, 61 выпушенными источником, то можно убедиться, что весьма немногие из них дойдут до наблюдателя. Следовательно, этот процесс был бы вычислительно неэффективен. Аппель первым предложил отслеживать (трассировать) лучи в обратном направлении, т. е. от наблюдателя к объекту, как показано на рис. 4 Этот алгоритм может учитывать эффекты отражения одного объекта от поверхности другого, преломления, прозрачности и затенения, а также устранение ступенчатости. Предполагается, что наблюдатель находится на положительной полуоси z- Картинная плоскость, т. е. растр, перпендикулярна оси z. Задача состоит в том, чтобы построить одноточечную центральную проекцию на картинную плоскость. Рис. 4 Наиболее важным элементом алгоритма определения видимых поверхностей путем трассировки лучей, является процедура определения пересечений. В состав сцены можно включать любой объект, для которого можно создать процедуру построения пересечений. Объекты сцены могут состоять из набора плоских многоугольников, многогранников или тел, ограниченных или определяемых квадратичными или биполиномиальными параметрическими поверхностями. Чтобы избавиться от ненужного поиска пересечений, производится проверка пересечения луча с объемной оболочкой рассматриваемого объекта. И если луч не пересекает оболочки, то не нужно больше искать пересечений этого объекта с лучом. В качестве оболочки можно использовать прямоугольный параллелепипед или сферу, рис. 5. Факт пересечения трехмерного луча со сферой определяется очень просто. В частности, если расстояние от центра сферической оболочки до луча превосходит радиус этой сферы, то луч не пересекает оболочки. Следовательно, он не может пересечься и с объектом. Рис. 5. Объемлющие оболочки Если же луч пересекается со сферической оболочкой какого-нибудь подэлемента, то последний разбивается дальше. Если трассируемый луч пересекает объекты сцены в нескольких точках, то необходимо определить видимое пересечение. Для алгоритмов определения видимости простых непрозрачных поверхностей, которые обсуждаются в данном разделе, пересечением с видимой поверхностью будет точка с максимальным значением координаты z. Для более сложных алгоритмов, учитывающих отражения и преломления, эти пересечения следует упорядочить вдоль луча по расстоянию от его начала. 62 Алгоритм трассировки лучей для простых непрозрачных поверхностей можно представить следующим образом: Подготовка данных для сцены; Создать список объектов, содержащий по меньшей мере следующую информацию: Полное описание объекта: тип, поверхность, характеристики и т. п. o Описание сферической оболочки: центр и радиус. Флаг прямоугольной оболочки. Если этот флаг поднят, то будет выполнен габаритный тест с прямоугольной оболочкой, если же он опушен, то тест выполняться не будет. Заметим, что габаритный тест необходим не для всех объектов, например для сферы он не нужен. o Описание прямоугольной оболочки: Для каждого трассируемого луча: Выполнить для каждого объекта трехмерный тест со сферической оболочкой в исходной системе координат. Если луч пересекает эту сферу, то занести объект в список активных объектов. Если список активных объектов пуст, то изобразить данный пиксел с фоновым значением интенсивности и продолжать работу. В противном случае, перенести и повернуть луч так, чтобы он совместился с осью z. Запомнить это комбинированное преобразование. Для каждого объекта из списка активных объектов: Если флаг прямоугольной оболочки поднят - преобразовать, используя комбинированное преобразование, эту оболочку в систему координат, в которой находится луч, и выполнить соответствующий тест. Если пересечения с лучом нет, то перейти к следующему объекту. В противном случае преобразовать, используя комбинированное преобразование, объект в систему координат, в которой находится луч, и определить его пересечения с лучом, если они существуют. Занести все пересечения в список пересечений. Если список пересечений пуст, то изобразить данный пиксел с фоновым значением интенсивности. В противном случае определить Zmax. для списка пересечений. jlВычислить преобразование, обратное комбинированному преобразованию. Используя это обратное преобразование, определить точку пересечения в исходной системе координат. Изобразить данный пиксел, используя атрибуты пересеченного объекта и соответствующую модель освещенности. Заметим, что алгоритм определения видимости простых непрозрачных поверхностей, не требует вычислять преобразование, обратное комбинированному, или определять точку пересечения в исходной системе координат, если в модели освещения не возникает необходимость включения в алгоритм свойств поверхности объекта или ее ориентации в точке пересечения. Эти шаги включены в данный алгоритм для полноты и удобства при реализации алгоритма трассировки лучей с учетом общей модели освещенности. 63