Геом моделирование 2D объектов бис бис (1). У геометрическое моделирование и отображение двухмерных объектов средствами открытой графической библиотеки
Скачать 0.74 Mb.
|
раздел описаний; задание графического режима (задание формата пикселя); задание начальных установок; рисование объектов; завершение программы. Раздел описаний, как обычно, нужен для описания используемых в программе модулей, констант, переменных и других конструкций, предусматриваемых языком программирования. Описания задания графического режима и завершения программы даны в приложении А. Начальные установки задают текущие настройки, разрешают или запрещают какие-то действия в зависимости от замысла разработчика. Из рассмотренных команд к начальным установкам относятся команды выбора и применения цвета фона. В следующих разделах учебного пособия рассмотрены другие возможные начальные установки. Рисующий фрагмент программы включает уже рассмотренные команды описания геометрических примитивов и задания их цвета. Нужно только иметь в виду, что рисование примитивов (занесение кодов в буфер кадра) осуществляется в той последовательности, в которой примитивы описаны в программе. Это означает, что в случае перекрытия примитивов сверху (в буфере и на экране) окажется примитив, описанный в программе позднее. Задание по созданию геометрических форм для самостоятельного выполнения (углубленное задание) 1)Попробуйте внести команду задания цвета glColor3f(1.0,0.0,0.0); внутрь операторных скобок glBegin – glEnd, рисующих какой-либо примитив. Поставьте ее перед первой, второй, третьей командой glVertex. Попытайтесь объяснить эффект. 2) Перед операторными скобками glBegin – glEnd, рисующими некоторый примитив, вставьте команду glShadeModel(GL_FLAT); и снова внесите внутрь скобок команду задания цвета, поставив ее перед первой, второй, третьей командой glVertex. Посмотрите описание команды glShadeModel в литературе. Поясните результаты. РАССТАНОВКА ГРАФИЧЕСКИХ ОБЪЕКТОВ В СЦЕНЕ Дисплейный список Как отмечалось в разделе 2, графический объект описывается в своей системе координат – ОСК. Расположение объекта в заданном месте окна вывода осуществляется путем сдвига и поворота всей ОСК, как это показано на рисунке4. Для изменения размеров объекта применяется масштабирование ОСК.Таким образом, объект рисуется на экране с привязкой к своей ОСК, но сама эта ОСК установлена в МСК и промасштабирована требуемым образом. Если в разных местах сцены отображается несколько объектов, имеющих одинаковую форму, то есть одинаково описанных в своей ОСК, то для их отображения в соответствии с описанным подходом необходимо задать с помощью операций сдвига и поворота положение ОСК первого объекта, задать с помощью операции масштабирования размеры первого объекта, нарисовать первый объект (скобки glBegin – glEnd), задать положение ОСК второго объекта, задать размеры второго объекта, нарисовать второй объект и т.д. Легко понять, что параметры расстановки у всех объектов различны, а процесс рисования одинаков. Это означает, что в программе несколько раз будут вызываться одни и те же последовательности рисующих команд в скобках glBegin – glEnd. В программировании в таких случаях применяют процедуры. В библиотеке OpenGL повторяющаяся последовательность рисующих команд тоже может быть оформлена в виде своеобразной процедуры, которая носит название дисплейного списка. Дисплейный список – это любая последовательность команд, имеющая самостоятельное значение и получившая уникальное имя. Эта последовательность команд заключается в операторные скобки glNewList – glEndList. Команда glNewList(1,GL_COMPILE); открывает (создает) дисплейный список, а беспараметрическая команда glEndList(); его закрывает. Параметрами команды открытия являются имя дисплейного списка (это целое число, например, 1) и режим его компиляции. Если этот режим GL_COMPILE, то дисплейный список компилируется, но не выполняется, а ждет своего вызова специальной командой. Она имеет вид glCallList(1); . Если же режим компиляции дисплейного списка задается строкой GL_COMPILE_AND_EXECUTE, то дисплейный список компилируется и тут же выполняется. В рассматриваемом примере в виде дисплейного списка имеет смысл оформить рисование стрелки привязанной к своей ОСК. В этот дисплейный список войдут команды задания цвета и рисования (в скобках glBegin – glEnd) составляющих стрелку примитивов. Команды геометрических преобразований Для расстановки и масштабирования объектов в сцене применяются команды, задающие геометрические преобразования: glTranslate, glRotateи glScale. Команда glTranslatef(±Δx±Δy±Δz); задает сдвиг ОСК вдоль ее координатных осей на расстояния Δx, Δy иΔz относительно предыдущего положения. Эта команда, в принципе, работает в трехмерном пространстве, поэтому имеет три параметра. Знаки приращений Δx, Δy, Δz определяют направление сдвига: в направлении положительной (плюс) или отрицательной (минус) координатной полуоси. Буква f(float) в описании команды означает, что сдвиги задаются вещественными числами, хотя могут использоваться и другие типы параметров команды. Например, команда glTranslatef(-0.5,0.5,0.0); устанавливает начало ОСК наклонной стрелки в точку (-0.5,0.5), как показано на рисунке 4. Команда glRotatef(±alfa,nx,ny,nz); п оворачивает ОСК на угол alfa против часовой стрелки (знак плюс) или по часовой стрелке (минус) вокруг некоторой оси. Ось поворота рассматривается как вектор, выходящий из начала координат ОСК и имеющий координаты nx,ny,nz. Это означает, что команда поворота, как и команда сдвига, работает в трехмерном пространстве. Напомним, что координатами вектора в трехмерном пространстве являются проекции его на координатные оси, а в числах – координаты точки, в которую он направлен. Например, на рисунке 5 показан вектор с координатами (-3,2,1), там же изображены его проекции nx,ny,nz на координатные оси. Очевидно, чтобы повернуть объект в плоскости экрана (в плоскости z=0), нужно использовать нулевые координаты nx,ny и ненулевую координату nz,а чтобы правильно задать угол поворота объекта, нужно смотреть на поворот с «острия» вектора оси поворота.Так, если в качестве оси поворота объекта используется вектор , то положительное и отрицательное направление поворота устанавливается так, как показывает стрелка на рисунке 5. Команда glRotate поворачивает ОСК относительно ее предыдущего состояния, то есть угол поворота может накапливаться. Величина угла alfa в команде выражается в градусах. Команда glScalef(kx,ky,kz); сжимает или растягивает ОСК, а вместе с ней и описанный в ней объект, вдоль координатных осей. Величину деформации задают коэффициенты масштабирования kx,ky,kz. При выполнении команды glScale координаты всех точек ОСК умножаются на масштабные коэффициенты. Это означает, что при использовании kx,ky,kz>1 происходит увеличение объекта на экране, а при kx,ky,kz<1 – его уменьшение. Равенство какого-то коэффициента нулю обращает в нуль соответствующую координату точек объекта. Различные сочетания масштабных коэффициентов (неравенство их другдругу) приводят к искажению геометрической формы объекта. Расстановка объектов в сцене с применением дисплейных списков Графические объекты (стрелки), рассматриваемые в качестве примера, имеют одинаковую форму. Это означает, что они могут быть описаны с помощью одного дисплейного списка. Пусть он имеет имя в виде числа 2 и описывает объект в ОСК так, как это показано на рисунке 3. Для того чтобы расставить графические объекты в соответствии с рисунком 1, нужно для каждого из них задать местоположение командой сдвига, задать угол наклона командой поворота, задать размер командой масштабирования и вызвать на исполнение дисплейный список. Центральная стрелка не нуждается в геометрических преобразованиях, так как ее положение и размеры соответствуют рисунку 1 (напомним, что по умолчанию ОСК совпадает с МСК). Поэтому для рисования центральной стрелки нужно просто вызвать дисплейный список: glCallList(2); . Теперь можно перейти к рисованию повернутой стрелки. Для нее команды геометрических преобразований и вызов дисплейного списка выглядят так: glTranslatef(-0.5,0.5,0.0); glRotatef(135,0.0,0.0,1.0); glScalef(0.5,0.5,1.0); glCallList(2); В приведенном фрагменте программы важна последовательность преобразований. Что будет, если ее изменить, например, поменять местами поворот и сдвиг? Операция поворота изменит направления координатных осей, и тогда сдвиг, который выполняется вдоль этих координатных осей, даст не ожидаемый, а совсем другой результат. Вместо перемещения влево–вверх стрелка сдвинется вниз. Это легко понять, построив эволюции стрелки в масштабе на бумаге. Критично и место размещения в программе операции масштабирования. Действительно, если масштабирование предшествует сдвигу, то сдвиг произойдет в измененной системе координат и желаемая величина перемещения не будет достигнута. 3.4 Использование стековой памяти После размещения второго объекта – повернутой стрелки – нужно перейти к отображению третьего объекта. Координаты начала его ОСК – (0.5,0.5). Однако просто применить команду glTranslate с такими параметрами не получится, так как перед этим в процессе установки второй стрелки положение ОСК было изменено. Напомним, что команды сдвига, поворота и масштабирования выполняют свои преобразования ОСК относительно ее предыдущего состояния, то есть работают по приращениям. Значит, для установки третьей стрелки нужно найти такие параметры сдвига, поворота и масштабирования, которые позволят перейти от состояния ОСК второй стрелки к состоянию ОСК третьей стрелки, что, в общем случае, непросто. Гораздо проще было бы задать положение третьей стрелки, отталкиваясь от исходного состояния ОСК, то есть в центре экрана, без поворота, без масштабирования. Для этого можно было бы после установки второй стрелки вернуть ОСК в исходное состояние, выполнив обратные геометрические преобразования, а затем приступить к установке третьей стрелки. Однако это неэффективный прием, так как наборы преобразований, в общем случае, могут быть большими. В библиотеке OpenGL есть аппарат стековой памяти, специально созданный для выполнения этой работы. Стек – это память, действующая по принципу «последним вошел – первым вышел». Если в некоторый момент выполнения программы применить команду glPushMatrix(); , то состояние системы координат, действующее на данный момент, будет запомнено. Далее это состояние можно изменять командами сдвига, поворота, масштабирования, но запомненное исходное состояние будет храниться в стеке. И в нужный момент времени запомненное состояние ОСК может быть возвращено – считано из стека – беспараметрической командой glPopMatrix(); . В принципе, объем стека позволяет, если это необходимо, сохранять в нем несколько состояний системы координат – на разные моменты времени. Для этого каждый раз применяется команда glPushMatrix. Для извлечения из стека очередного состояния ОСК каждый раз применяется команда glPopMatrix. Работа со стеком имеет одну особенность. После того, как командой glPopMatrix некоторое состояние ОСК извлекается из стека, оно становится доступным для изменения (сдвига, поворота, масштабирования), но в самом стеке оно пропадает – стирается. Следовательно, если это состояние ОСК в будущем понадобится еще раз, его нужно еще раз запомнить с помощью команды glPushMatrix. Применив аппарат стековой памяти, расстановку стрелок в соответствии с рисунком 1 можно описать следующим образом. //запоминание исходного состояния ОСК glPushMatrix(); //отображение первой стрелки glCallList(2); //установка второй стрелки glTranslatef(-0.5,0.5,0.0); glRotatef(135,0.0,0.0,1.0); glScalef(0.5,0,5,1.0); //отображение второй стрелки glCallList(2); //возврат исходного состояния ОСК glPopMatrix(); //повторное запоминание исходного состояния ОСК glPushMatrix(); //установка третьей стрелки glTranslatef(0.5, -0.5,0.0); glScalef(0.5,0,5,1.0); //отображение третьей стрелки glCallList(2); С помощью стека можно запоминать и возвращать любое состояние системы координат. Однако часто бывает необходимо установить именно исходное состояние ОСК – без каких-либо сдвигов, поворотов и масштабных изменений. Для этого служит команда glLoadIdentity(); . Ее удобно использовать в начале программы. Дело в том, что в процессе работы программы часто возникает необходимость выполнить ее тело еще раз, то есть перерисовать изображение. Это происходит, например, при изменении размеров окна вывода или его сворачивании–разворачивании. При перерисовке в программе сохраняется текущее состояние ОСК, которое существовало на момент завершения предыдущего цикла рисования. Это означает, что последующие геометрические преобразованияначнутся не от исходного состояния ОСК, и их выполнение не приведет к желаемому результату. Команда glLoadIdentity позволяет предотвратить такую неправильность работы программы. 3.5 Расстановка объектов по глубине При работе с двухмерными объектами координату глубины (координату z) можно не использовать. Однако все команды геометрических преобразований работают в трехмерном пространстве и потому имеют своеобразие, которое следует учитывать и в двухмерной графике. В процессе расстановки объекты могут располагаться с частичным перекрыванием. Оно возникает даже тогда, когда координата z объектов одинакова. В этом случае по умолчанию сверху окажется объект, нарисованный программой позже. Коды его цветояркости позже попадут в буфер кадра и заменят собой коды, занесенные туда ранее. При этом неважно, какую глубину имеют объекты. Но в библиотеке OpenGL есть и другой режим вывода перекрывающихся объектов, основанный на так называемом тесте глубины. В этом режиме глубина объектов, то есть координата z их элементов, фиксируется в выделенной для этого памяти – буфере глубины. В процессе вывода на экран перекрывающихся объектов расстояния от них до наблюдателя сравниваются между собой с помощью специального алгоритма, который упорядочивает объекты по координате z. Точнее, по глубине упорядочиваются элементы объектов, претендующие на закраску каждого пикселя окна вывода. В результате более близкий к наблюдателю объект на экране заслонит более далекие объекты. В случае равенства координаты z двух объектов (их элементов) последовательность их вывода зависит от настройки алгоритма буфера глубины. Это и есть тест глубины. По умолчанию тест глубины не работает.Для его включения нужно применить разрешающую команду. Вообще в OpenGL имеется две команды, которые разрешают и запрещают различные возможности. ЭтоglEnable(<параметр>); и glDisable(<параметр>); .Их параметр – это текстовая строка, которая определяет, что разрешается или запрещается. Чтобы разрешить упорядочение объектов по глубине, в начало программы нужно вставить команду glEnable(GL_DEPTH_TEST); . В любой момент времени это разрешение можно отменить командой glDisable(GL_DEPTH_TEST);, после чего объекты снова будут выводиться на экран в последовательности рисования их программой. Чтобы подготовить буфер глубины к работе, его нужно очистить командой glClear(GL_DEPTH_BUFFER_BIT); , которая также вставляется в начало программы. После такой подготовки буфер глубины можно использовать. По умолчанию тест глубины проходит и выводится на экран тот объект, элементы которого ближе к наблюдателю, чем элементы других объектов, то есть координата z проходящего тест объекта строго меньше координаты z других объектов. Можно настроить тест глубины и по-другому. Например, тест может проходить объект, координата z которого меньше или равна, а может быть и больше координаты z других объектов. Настройка теста глубины выполняется с помощью команды glDepthFunc. 3.6 Задание по расстановке объектов для самостоятельного выполнения (углубленное задание) 1) Примените к рисованию первой стрелки команду масштабирования с отрицательным значением первого параметра, например, со значением (-1). Поясните эффект. 2) Определите набор и последовательность геометрических преобразований, необходимых для поворота на заданный угол всей сцены, показанной на рисунке 1. 3) Определите последовательность команд, которая позволяет придать каждой стрелке сцены свой цвет. НАЛОЖЕНИЕ ТЕКСТУРЫ НА ДВУХМЕРНЫЕ ОБЪЕКТЫ Процесс наложения текстуры Текстура в компьютерной графике – это двухмерный массив разноцветных элементов – текселей (texel – textureelement). Текстура располагается в своей системе координат – СКТ, где каждый тексель получает две текстурные координаты sиt.Геометрический примитив, как известно, описывается своими характерными точками, каждая из которых имеет две геометрические координаты (координату z при текстурировании можноне учитывать). Суть процесса текстурирования заключается в установлении соответствия между координатами текселей и геометрическими координатами. Другими словами, каждому элементу геометрического примитива ставится в соответствие тексель. При выводе изображения на экран каждому элементу примитива сопоставляется пиксель окна вывода. Следовательно, в конечном итоге, в процессе наложения текстуры для каждого пикселя, попавшего внутрь контура примитива, находится тексель текстуры. При этом в случае наложения большой текстуры на маленький примитив текстура будет сжата, в противном случае – растянута. Закон сопоставления характерных точек примитива и текстуры выбирает разработчик, а нахождение текселей для каждого пикселя изображения примитива выполняют команды графической библиотеки. Текстурный рисунок обычно изготавливается в растровом графическом редакторе и сохраняется в одном из стандартных форматов. В графической библиотеке текстура представляется и используется в некотором внутреннем формате, который не совпадает ни с одним стандартным. Следовательно, в графической программе должно осуществляться конвертирование рисунка во внутренний формат библиотеки, то есть преобразование текстурного рисунка в текстурный образец. С учетом приведенных сведений можно сформулировать последовательность действий, необходимых для наложения текстуры на геометрический примитив: изготовить рисунок текстуры; разработать закон наложения текстуры; определить текстурные координаты текселей, соответствующих характерным точкам примитива; разрешить текстурирование; конвертировать текстурный рисунок в текстуру (текстурный образец); используя команды графической библиотеки, задать соответствие текстурных и геометрических координат; записать фрагмент программы, рисующей текстурированный примитив. Из семи перечисленных действий три первые требуют принятия творческих решений, а четыре последние – применения графических технологий.
|