3 С. А. Васильев opengl компьютерная графика
Скачать 491.09 Kb.
|
Внимание!Угол angle задается в градусах. Необходимо помнить,что на самом деле преобразования осуществляются не над самим объектом, а над его локальной системой координат. Это очень удобно, когда в одну глобальную систему коорди- нат сцены необходимо вставить определенным образом несколько объектов, описанных в своих систе- мах локальных координат. Поясним на примере (все рассматриваем в плоскости z = 0). Пусть требуется объект А (квадрат), заданный в своей системе координат, переместить вдоль оси x на 2 единицы и раз- вернуть на 45 ° против часовой стрелки относительно оси z (см. рис. 2). Такая постановка задачи в OpenGL не применима, так как объект определяется только в конце своих геометрических преобразова- ний. Правильнее было сказать: необходимо развернуть на 45 ° (против часовой стрелки) систему коор- динат относительно вектора (0,0,1), после чего, переместить ее (относительно старого положения) в но- вое место вдоль вектора (2,0,0) и определить объект А в новом положении системы координат. Рис. 2 Пояснение модельно-видовых преобразований в OpenGL Для выполнения такой задачи можно использовать следующий фрагмент программы модельно- видового преобразования: Y 45 ° 2 y ′ x ′ y x y ′′ x ′′ Х Шаг 1 Шаг 2 Шаг 3 Шаг 4 0 31 //шаг 1 – устанавливается единичная текущая матрица (оси x0y) glLoadIdentity(); //шаг 2 – поворачивается система координат x0y на 45 ° // против часовой стрелки относительно вектора //(0,0,1) и занимает новое положение x ′0y′ glRotatef(45,0,0,1); //шаг 3 – система x ′0y′ смещается по оси x′ на 2 единицы и // занимает положение x ′′0y′′ glTranslatef(2.0f, 0.0f, 0.0f); //шаг 4 – определяем объект и текущая матрица // модельно-видового преобразования умножается // на координаты объекта glBegin(GL_QUADS); glVertex3f(–1.0f, 1.0f, 0.0f); // левый верхний угол glVertex3f( 1.0f, 1.0f, 0.0f); // правый верхний угол glVertex3f( 1.0f, –1.0f, 0.0f); // правый нижний угол glVertex3f(–1.0f, –1.0f, 0.0f); // левый нижний угол glEnd(); Теперь рассмотрим, что произойдет с объектом A, если поменять местами шаг 2 с шагом 3 в при- веденном выше фрагменте программы? Получим новый код. // Устанавливается единичная текущая матрица оси x0y glLoadIdentity(); // Система x0y смещается по оси x на 2 единицы и занимает // положение x ′0y′ glTranslatef(2.0f, 0.0f, 0.0f); // Поворачивается система координат x ′0y′ на 45° // против часовой стрелки относительно вектора (0,0,1) и // занимает новое положение x ′′0y′′ glRotatef(45,0,0,1); // Определяем объект и текущая матрица модельно-видового // преобразования умножается на координаты объекта glBegin(GL_QUADS); glVertex3f(-1.0f, 1.0f, 0.0f); // левый верхний угол glVertex3f( 1.0f, 1.0f, 0.0f); // правый верхний угол glVertex3f( 1.0f,-1.0f, 0.0f); // правый нижний угол glVertex3f(-1.0f,-1.0f, 0.0f); // левый нижний угол glEnd(); Конечный результат такого преобразования будет отличаться предыдущей задачи. Ход преобразо- ваний можно проанализировать на рисунке 3. Рис. 3 Пример модельно-видовых преобразований Если в приведенном примере (рис. 4) рассуждать по геометрическим преобразованиям с точки зре- 2 y ′ x ′ y x y ′′ x ′′ Y X Шаг 1 Шаг 3 0 45 ° 0 Шаг 2 Шаг 4 32 ния объекта, то конечную цель можно достичь после следующих шагов: шаг 1 – поворота объекта на 45 ° относительно оси z после чего; шаг 2 – перемещение объекта (повернутого) вдоль оси x на две еди- ницы. Но в OpenGL это осуществляется в обратном порядке. Совет: приучите себя к рассуждениям о преобразованиях объектов с точки зрения их систем коор- динат, и это вас избавит от возможных геометрических ошибок. Напоминаем, что текущая матрица умножается на координаты точек объекта только при определе- нии самого объекта. После чего координаты объекта преобразуются в новые значения. А до этого мо- мента формируется текущая матрица преобразования. Любой вызов команды преобразования заверша- ется перемножением текущей матрицы преобразования на сформированную матрицу командой преоб- разования. Полученная матрица размещается на место текущей. Изменяя положение самого объекта, создается иллюзия, что перемещается камера наблюдения. В OpenGL существует возможность управлять камерой с одновременным изменением модельно-видовой матрицы. Это можно сделать с помощью команды: void gluLookAt( GLdouble eyex, GLdouble eyey, GLdouble eyez, GLdouble cx, GLdouble cy, GLdouble cz, GLdouble upx, GLdouble upy, GLdouble upz) ЗДЕСЬ ПАРАМЕТРЫ EYEX, EYEY, EYEZ ОПРЕДЕЛЯЮТ ТОЧКУ НАБЛЮДЕНИЯ, CX, CY, CZ ЗАДАЮТ ЦЕНТР СЦЕНЫ, КОТОРЫЙ БУДЕТ ПРОЕКТИРОВАТЬСЯ В ЦЕНТР ОБЛАСТИ ВЫВОДА, И ПАРАМЕТРЫ UPX, UPY, UPZ ЗАДАЮТ ВЕКТОР ПОЛОЖИТЕЛЬНОГО НА- ПРАВЛЕНИЯ ОСИ У СЦЕНЫ, ОПРЕДЕЛЯЯ ПОВОРОТ КАМЕРЫ. ОБЫЧНО ПАРАМЕТРЫ UPX, UPY, UPZ ИМЕЮТ ЗНАЧЕНИЯ – (0,1,0). Внимание! Команду gluLookAt() обычно отрабатывают, когда модельно-видовая матрица равна единичной. Например: … glMatrixMode(GL_MODELVIEW); // текущая матрица – видовая glLoadIdentity(); // текущая матрица – единичная gluLookAt(2.0f,1.0f,3.0f, // положение центра наблюдения 6.0f,0.0f,0.0f, // центр сцены в мировых координатах 0.0f,1.0f,0.0f); // вектор "верх" направлен вдоль оси у … 10.3 Область вывода В OpenGL готовая для визуализации графическая информация поступает в специально настроен- ную область вывода, которая определяется шириной (p x ), высотой (p y ) и положением ее центра на экра- не (o x , o y ). Эти параметры формируются специальной командой: void glViewPort (GLint x, GLint y, GLint width, GLint height) Параметры x и y задают координаты левого нижнего угла (x, y) области вывода в оконной системе ко- ординат. Параметры width и height определяют ширину и высоту окна вывода. Все параметры команды задаются в пикселях. Размеры оконной системы координат определяются текущими размерами окна при- ложения, точка (0,0) находится в левом нижнем углу окна. После выполнения команды glViewPortпараметры области выво- да устанавливаются в значения p x = width, p y = height, o x = x + width/2и o y = y + height (точка с координатами (0, 0, 0) в оконных координатах будет располагаться я в центре ок- на области вывода), а оконные координаты выводимых вершин определяются соотношением: 2 2 2 2 f n n f z o p y o p x z y x y y x x w w w + + − + + = , где n и f определяют допустимый диапазон изменения глубины (z – координата). По умолчанию данные параметры равны 0 и 1 соответственно. Но их можно изменять командой: void glDepthRange (GLclampd n, GLclampd f) 33 После отсечения и деления на w координаты z лежат в диапазоне значений от –1 до 1, соответствен- но для ближней и дальней плоскостей отсечения. Команда glDepthRange определяет линейное отобра- жение нормализованных z-координат из этого диапазона в оконные координаты. Команду glViewPort часто используют в CAD системах для моделирования четырех видов проек- тируемого объекта. Это можно реализовать, например, следующим образом: экран разбивается на четы- ре части и каждая описывается командой glViewPort с соответствующими значениями параметров окна вывода. После каждого такого описания необходимо настроить вид проекции и параметры камеры на- блюдения. После чего, необходимо вывести сцену. И так четыре раза. 11 ПРОЕКЦИИ В OpenGL командно реализованы общепринятые в компьютерной графике два вида проекций: ор- тографическая (параллельная) и перспективная с одной главной точкой схода на оси z. Для реализации других видов проекций необходимо использовать готовые матрицы проецирования. 11.1 Ортографическая проекция Первый тип проекции (рис. 4) может быть задан командой void glOrtho (GLdouble left, GLdouble right, GLdouble bottom, GLdouble top, GLdouble zNear, GLdouble zFar) Рис. 4 Усеченный объем видимости для случая ортографической параллельной проекции Команда glOrtho() создает матрицу параллельной проекции и усеченный объем видимости. Пара- метры left и right задают координаты левой и правой вертикальной плоскости отсечения. Параметры bottom и top определяют координаты верхней и нижней плоскости отсечения. Параметры zNear и zFar задают расстояние от точки (0,0,0) до ближней и дальней плоскостей отсечения и могут быть положи- тельными и отрицательными. В процессе работы команды glOrtho() текущая матрица M умножается на матрицу, сформирован- ную командой glOrtho(), и результат помещается на место матрицы М. В библиотеке glu32.lib существует эквивалент команды glOrtho(left,right,botton,top, –1, 1): void gluOrtho2D (GLdouble left, GLdouble right, GLdouble bottom, GLdouble top) 11.2 Перспективная проекция Для задания перспективной проекции с одной главной точкой схода по оси z применяется команда void glFrustum (GLdouble left, GLdouble right, GLdouble bottom, GLdouble top, GLdouble zNear, GLdouble zFar) Направление проецирования Картинная плоскость Задняя секущая плоскость Передняя секущая плоскость zFar zNear left right top botton x y z 34 Команда glFrustum () создает матрицу центральной проекции и усеченный пирамидальный объем видимости (рис. 5). Центр проецирования Рис. 5 Перспективная проекция и усеченный пирамидальный объем видимости (точка наблюдения) находится в начале системы координат. Параметры left и right задают координаты левой и правой вертикальной плоскости отсечения. Параметры bottom и top определяют координаты верхней и нижней плоскости отсечения. Параметры zNear и zFar задают расстояние от наблюдателя до ближней и дальней плоскостей отсечения, причем оба значения должны быть положительными. Пара- метры left, right, bottom и top задаются для ближней плоскости отсечения. Внимание! В конечном итоге значение глубины (z) любой выводимой точки сцены нормируется к возможностям буфера глубины, т.е. к значению в диапазоне от 0 до 1. Чем больше значение отношения zNea/rzFar, тем менее эффективно будут различаться в буфере глубины, расположенные рядом поверх- ности. Не следует задавать параметру zNear нулевое значение, так как в этом случае отношение zNear/ zFar стремиться к бесконечности. В библиотеке glu32.lib существует команда gluPerspective() аналогичная по функциям, что иglFrus- tum (), но с различными входными пара- метрами. void gluPerspective (GLdouble fovy, GLdouble aspect, GLdouble zNear, GLdouble zFar) Данная команда задает усеченный пирамидальный объем видимости в видовой системе координат. Параметр fovy определяет угол видимости (в градусах) вдоль оси у. Угол видимости вдоль оси х задает- ся параметром aspect, который определяется как отношение ширины и высоты области вывода. Пара- метры zNear и zFar задают расстояние от наблюдателя до ближней и дальней плоскостей отсечения, причем оба значения должны быть положительными. Эквивалентность работы данной команды с ко- мандой glFrustum (), наступает при lef t = –right, bottom = –top, tg(fovy/zNear) = top/zNear, aspect = right/top. Для того чтобы включить проекцию необходимо включить режим проецирования и загрузить еди- ничную текущую матрицу преобразования. Например: … // Установка настроек области вывода glViewport(0,0,width,height); // Выбираем матрицу проекции glMatrixMode(GL_PROJECTION); // Делаем ее единичной glLoadIdentity(); gluPerspective(45.0f,width/height,0.1f,100.0f); Задняя секущая плоскость Передняя секущая плоскость zNear Центр проекции z botton top Направление проецирования zFar y x Картинная плоскость right left 35 glMatrixMode(GL_MODELVIEW); // Делаем ее единичной glLoadIdentity(); … 12 ОБРАТНЫЕ ПРЕОБРАЗОВАНИЯ ОКОННЫХ КООРДИНАТ В ОБЪЕКТНЫЕ Часто требуется пользователю, используя мышь или другой указатель, выбрать точку в трехмерном пространстве, оперируя лишь ее проекцией на экране. Решая данную задачу, необходимо вспомнить, что оконные координаты объекта получаются из его мировых путем трех матричных преобразований: модельно-видовых, проекционных и преобразований к области вывода. И для определения мировых ко- ординат точки объекта по его оконным координатам требуется проделать обратные, вышеприведенные, преобразования. Но тут возникает другая проблема, множество точек из мировых координат, располо- женных вдоль луча-проектора, дадут одну и ту же проекцию на экране. Для разрешения этой неодно- значности в OpenGL обратные преобразования решены командами gluUnProject() при диапазоне глу- бин в вашем приложении [0, 1],либо gluUnProject4(),еслидиапазон глубин отличается от [0, 1]. Рас- смотрим параметры и функциональные возможности этих команд: int gluUnProject (GLdouble winx, GLdouble winy, GLdouble winz, const GLdouble modelMatrix[16],const GLdouble projMatrix[16], const GLint viewport[4], GLdouble *objx, GLdouble *objy, GLdouble *objz); Данная команда преобразует заданные оконные координаты (winx, winy, winz) в объектные коорди- наты (objx, objy, objz), используя преобразования, заданные модельно-видовой матрицей (modelMatrix), проекционной матрицей (projMatrix) и портом просмотра (viewport). Если функция выполнилась удач- но, то она возвращает значение GL_TRUE, в противном случае GL_FALSE. Для получения однозначного результата от обратного преобразования, команда gluUnProject() тре- бует в качестве одного из своих параметров значение глубины в оконных координатах (winz). Если winz = 0.0, то вызов gluUnProject() вернет координаты точки (objx, objy и objz), расположенной на ближней плоскости отсечения объема видимости, а при winz = 1.0 будет вычислена точка на дальней плоскости отсечения. Изъятие текущих значений матриц преобразований осуществляется командой: voidglGetDoublev(GLenum pname,GLdouble *params) Параметр pname определяет вид матрицы (см. документацию): модельно-видовой – GL_MODELVIEW_MATRIX; проецирования – GL_PROJECTION_MATRIX. Параметр params указывает на массив размеще- ния. Значения параметров окна можно выбрать командой: voidglGetIntegerv (GLenum pname,GLdouble *params) Назначение параметров такое же, как и в команде glGetDoublev. Значение параметра pname для ок- на должно быть GL_VIEWPORT. Рассмотрим фрагмент программы, где по экранным координатам точки(x и y), например, взятых от мыши, вычисляем значение координат точки объекта, обеспечивших эту проекцию. В качестве winz возьмем значение 0.0. … GLint viewport[4]; //для окна GLdouble mv_matrix[16]; // для модельно-видовой матрицы GLdouble proj_matrix[16]; // для матрицы прецирования GLdouble obx,oby,obz; // Возвращаемые объектные x, y, z координаты GLint x,y; … // Обрабатываем событие от "мышки" (формируем значение x и y) … glGetIntegerv(GL_VIEWPORT,viewport); glGetDoublev(GL_MODELVIEW_MATRIX,mv_matrix); 36 glGetDoublev(GL_PROJECTION_MATRIX,proj_matrix); gluUnProject(x,y,0.0,mv_matrix,proj_matrix,viewport,&ox,&oy,&oz); printf("Объектные координаты при z=0 (%f,%f,%f)\n",ox,oy,oz); … Подобные ситуации часто возникают при выборе объектов на экране. 13 ПОСТРОЕНИЕ РЕАЛИСТИЧЕСКИХ ИЗОБРАЖЕНИЙ Компьютерное графическое моделирование реальных либо виртуальных объектов предполагает воссоздание на экране компьютера не только правильные геометрические соотношения элементов сце- ны, но и передачу "атмосферы" визуального ряда. Сюда включаются: внешний вид материала, из кото- рых сделан объект, признаки наличия света; преломление и смешивание цветов через полупрозрачные среды фрагментов объекта, изменяющийся по глубине туман и т.д. Для создания реалистических изо- бражений в OpenGL существует богатый командный инструментарий, обеспечивающий: • наложение текстур на поверхность объекта, • задание свойств материала из которого сделан объект, • определение свойств источников света, • задание модели освещения, • задание законов смешивания цветов через полупрозрачные поверхности, • задание тумана (дымки) и т.д. 13.1 Текстуры Текстурой называется одномерное или двумерное изображение с совокупностью параметров, опре- деляющих, каким образом производится наложение изображения на поверхность графического объекта. В OpenGL текстурирование выполняется по следующей схеме: 1 Размещаем в оперативной памяти массив данных, в котором будет храниться образ будущей тек- стуры. 2 Выбираем изображение (например, из файла) и преобразуем его к внутреннему формату OpenGL. Заполняем массив данными изображения. 3 Создаем текстуру в памяти. Для этого будем использовать команду glTexImage2D() для двумер- ных текстур, либо gluBilld2Mipmaps(). 4 Задаем возможные параметры фильтрации текстуры для достижения наилучшего восприятия объектов при различных коэффициентах масштабирования. Для этого будем использовать команду glTexParameter(). 5 Указываем каким образом координаты текстуры связанные с координатами текстурируемого объекта. Это можно выполнить, например, командой glTexCoord(). Рассмотрим этапы текстурирования объекта подробнее. |