Сделай Сам Свою Работу на 5

Рисование точек, линий и многоугольников





Для задания размеров точки служит процедура glPointSize(GLfloat size), которая устанавливает размер точки в пикселях, по умолчанию он равен единице.

Для задания ширины линии в пикселях служит процедура gflineWidth(GLfloatwidth). Шаблон, которым будет рисоваться линия, можно задать при помощи процедуры glLineStipple(Glint factor, GLushort pattern). Шаблон задается переменной pattern и растягивается в factor раз. Использование шаблонов линии необходимо разрешить при помощи команды glEnable(GL_UNE_STIPPLE). Запретить использование шаблонов линий можно командой glDisable(GL_LINE_ST1PPLE).

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

Многоугольник имеет две стороны (лицевую и нелицевую) и может быть отрисован по-разному, в зависимости от того, какая сторона обращена к наблюдателю. По умолчанию обе стороны рисуются одинаково. Для задания того, как именно следует рисовать переднюю и заднюю стороны многоугольника, служит процедура glPolygonMode(GLenum face, GLenum mode). Параметр face может принимать значения GL_FRONT_AND_BACK (обе стороны), GL_FRONT (лицевая сторона) или GL_BACK (нелицевая сторона). Параметр mode может принимать значения GL_POINT, GL_LINE или GL_FILL, обозначая, что многоугольник должен рисоваться как набор граничных точек, граничная ломаная линия или заполненная область, например:



 

glPolygonMode(GL_FRONT, GL_FILL);

glPolygonMode(GL_BACK, GLJJNE).

 

По умолчанию вершины многоугольника, которые появляются на экране в направлении против часовой стрелки, называются лицевыми. Это можно изменить при помощи процедуры glFrontFace(GLenum mode). По умолчанию параметр mode равняется GL_CCW, что соответствует направлению обхода против часовой стрелки. Если задать этот параметр равным GL_CW, то лицевыми будут считаться многоугольники с направлением обхода вершин по часовой стрелке.

При помощи процедуры glCullFace(GLenum mode) вывод лицевых или нелицевых граней многоугольников можно запретить. Параметр mode принимает одно из значений GL_FRONT (оставить только лицевые грани), GL_BACK (оставить нелицевые) или GL_FRONT_AND_BACK (оставить все грани). Для отсечения граней необходимо разрешить отсечение при помощи команды glEnable(GL_CULL_FACE).



Шаблон для заполнения грани можно задать при помощи процедуры gIPolygonStipple(const GLubyte * mask), где mask задает массив битов размером 32 на 32.

Для разрешения использования шаблонов при выводе многоугольников служит команда glEnable(GL_POLYGON_STIPPLE).

Свой вектор нормали для каждой вершины можно задать при помощи одной из следующих процедур:

 

glNormal3{b s i d f}(TYPE nx, TYPE ny, TYPE nz);

glNormal3{b s I d f}v(const TYPE * v).

 

В версиях с суффиксами b, s или i значения аргументов масштабируются в отрезок [-1, 1].

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

#include <windows.h>

#include <gl\gl.h>

drawBox(GLfloat x1, GLfloat x2, GLfloat y1, GLfloat y2, GLfloat z1, GLfloat

z2)

{

glBegin ( GL_POLYGON );

glNormal3f ( 0.0, 0.0, 1.0 );

glVertex3f ( x1, y1, z2 );

glVertex3f ( x2, y1, z2 );

glVertex3f ( x2, y2, z2 );

glVertex3f ( x1, y2, z2 );

glEnd ();

glBegin ( GL_POLYGON );

glNormal3f ( 0.0, 0.0, -1.0 );

glVertex3f ( x2, y1, z1 );

glVertex3f ( x1, y1, z1 );

glVertex3f ( x1, y2, z1 );

glVertex3f ( x2, y2, z1 );

glEnd ();

glBegin ( GL_POLYGON );

glNormal3f ( -1.0, 0.0, 0.0 );

glVertex3f ( x1, y1, z1 );

glVertex3f ( x1, y1, z2 );

glVertex3f ( x1, y2, z2 );

glVertex3f ( x1, y2, z1 );

glEnd ();

glBegin ( GL_POLYGON );

glNormal3f ( 1.0, 0.0, 0.0 );

glVertex3f ( x2, y1, z2 );

glVertex3f ( x2, y1, z1 );

glVertex3f ( x2, y2, z1 );

glVertex3f ( x2, y2, z2 );

glEnd ();

glBegin ( GL_POLYGON );

glNormal3f ( 0.0, 1.0, 0.0 );

glVertex3f ( x1, y2, z2 );

glVertex3f ( x2, y2, z2 );

glVertex3f ( x2, y2, z1 );

glVertex3f ( x1, y2, z1 );

glEnd ();

glBegin ( GL_POLYGON );

glNormal3f ( 0.0, -1.0, 0.0 );

glVertex3f ( x2, y1, z2 );

glVertex3f ( x1, y1, z2 );

glVertex3f ( x1, y1, z1 );

glVertex3f ( x2, y1, z1 );

glEnd ();

}

Преобразование объектов в пространстве

Преобразования в пространстве

В процессе построения изображения координаты вершин подвергаются определенным преобразованиям. Подобным преобразованиям подвергаются заданные векторы нормали.



Изначально камера находится в начале координат и направлена вдоль отрицательного направления оси Оz.

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

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

Текущая матрица задается при помощи процедуры gIMatrixMode(GLenum mode). Параметр mode может принимать значения GL_MODELVIEW, GL_TEXTURE или GL_PROJECTION, позволяя выбирать в качестве текущей матрицы матрицу моделирования (видовую матрицу), матрицу проецирования или матрицу преобразования текстуры.

Процедура gILoadldenity() устанавливает единичную текущую матрицу.

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

Преобразование переноса задается процедурой glTranslate{f d}(TYPE x, TYPE у, TYPE z), обеспечивающей перенос объекта на величину (x, у, z).

Преобразование поворота задаётся процедурой glRotate{f d}(TYPE angle, TYPE x, TYPE y, TYPE z), обеспечивающей поворот на угол angle в направлении против часовой стрелки вокруг прямой с направляющим вектором (x, у, z).

Преобразование масштабирования задаётся процедурой glScale{f d}(TYPE x, TYPE у, TYPE z).

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

Получение проекций

Видимым объемом при перспективном преобразовании в OpenGL является усеченная пирамида.

Для задания перспективного преобразования в OpenGL служит процедура gIFrustrum(GLdouble teft, GLdoubte right, GLdouble bottom, GLdouble top, GLdouble near, GLdoubte far).

Параметры определяют плоскости, по которым проводится отсечение. Величины near и far должны быть неотрицательными.

Иногда для задания перспективного преобразования удобнее воспользоваться следующей процедурой из библиотеки утилит gluPerspective(GLdouble fovy, GLdouble aspect, GLdouble zNear, GLdouble zFar).

Эта процедура создает матрицу для задания симметричного поля зрения и умножает текущую матрицу на неё. Здесь fovy – угол зрения камеры в плоскости Oxz, лежащей в диапазоне [0, 180]. Параметр aspect – отношение ширины области к её высоте, zNear и zFar – расстояния вдоль отрицательного направления оси Oz, определяющие ближнюю и дальнюю плоскости отсечения.

Существует ещё одна удобная функция для задания перспективного проецирования gluLookAt (GLdouble eyeX, GLdouble eyeY, GLdouble eyeZ, GIdouble centerX, GLdouble centerY, GLdouble centerZ, GLdouble upX, GLdouble upY, GLdouble up2).

Вектор (еуеХ, eyeY, eyeZ) задаёт положение наблюдателя, вектор (cenlerX, centerY, centerZ) – направление на центр сцены, а вектор (upX, upY, upZ) – направление вверх.

В случае параллельного проецирования видимым объемом является прямоугольный параллелепипед. Для задания параллельного проецирования служит процедура glOrtho(GLdouble left, GLdouble right, GLdouble bottom, GLdouble top, GLdouble near, GLdouble far).

Параметры left и right определяют координаты левой и правой вертикальных плоскостей отсечения, a bottom и top – нижней и верхней горизонтальных плоскостей.

Следующим шагом в задании проецирования (после выбора параллельного или перспективного преобразования) является задание области в окне, в которую будет помещено получаемое изображение. Для этого служит процедура gIViewport(GLint x, GLint у, GLsizei width, GLsizei height).

Здесь (х, у) задаёт нижний левый угол прямоугольной области в окне, a width и height являются её шириной и высотой.

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

Для помещения текущей матрицы в стек служит процедура gIPushMatrix(), для извлечения матрицы из стека – процедура glPopMatrix().

Задание моделей закрашивания

Линия или заполненная грань могут быть нарисованы одним цветом (плоское закрашивание, GL_FLAT) или путём интерполяции цветов в вершинах (закрашивание Гуро, GL_SMOOTH).

Для задания режима закрашивания служит процедура glShadeModel(GLenum mode), где параметр mode принимает значение GL_SMOOTH или GL_FLAT.

Освещение

OpenGL использует модель освещённости, в которой свет приходит из нескольких источников, каждый из которых может быть включён или выключен. Кроме того, существует еще общее фоновое (ambient) освещение.

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

Пользователь может определить до восьми источников света и их свойства, такие, как цвет, положение и направление. Для задания этих свойств служит процедура gllight{i f}[v](GLenum light, GLenum pname, TYPE param), которая задаёт параметры для источника света light, принимающего значения GL_LIGHT0, GL_LIGHT1, ..., GL_LIGHT7. Параметр pname определяет характеристику источника света, которая задается последним параметром.

Для использования источников света расчёт освещенности следует разрешить командой glEnable(GL_LGHTING), а применение соответствующего источника света разрешить (включить) командой glEnable, например: glEnable(GL_LIGHT0).

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

Если параметр w в команде GL_POSITION равен нулю, то соответствующий источник света – направленный и светит в направлении (х, у, z). Если же w отлично от нуля, то это позиционный источник света, находящийся в точке с координатами (x/w, y/w, z/w).

Заданием параметров GL_SPOT_CUTOFF и GL_SPOT_DIRECTION можно создавать источники света, которые будут иметь коническую направленность. По умолчанию значение параметра GL_SPOT_CUTOFF равно 180°, т. е. источник светит во всех направлениях с равной интенсивностью. Параметр GL_SPOT_CUTOFF определяет максимальный угол от направления источника, в котором распространяется свет от него. Он может принимать значение 180° (не конический источник) или от 0 до 90°.

Интенсивность источника с расстоянием, вообще говоря, убывает (параметры этого убывания задаются при помощи параметров (GL_CONSTANT_ATTENUATION, GL_LINEAR_ATTENUATION и GL_QUADRATIC_ATTENUATION). Только собственное свечение материала и глобальная фоновая освещенность с расстоянием не ослабевают.

Глобальное фоновое освещение можно задать при помощи команды gtLightModel{i f} [v] (GL_LIGHT_MODEL_AMBIENT ambientColor).

Местонахождение наблюдателя оказывает влияние на блики на объектах. По умолчанию при расчётах освещённости считается, что наблюдатель находится в бесконечно удалённой точке, т. е. направление на наблюдателя постоянно для любой вершины. Можно включить более реалистическое освещение, когда направление на наблюдателя будет вычисляться для каждой вершины отдельно. Для этого служит команда glLightModeli(GL_LIGHT_MODEL_LOCAL_VIEWER, GL_TRUE).

Для задания освещения как лицевых, так и нелицевых граней (для нелицевых граней вектор нормали переворачивается) служит следующая команда glLightModeli(GL_LIGHT_MODEL_TWO_SIDE, GL_TRUE), причём существует возможность отдельного задания свойств материала для каждой из сторон.

Свойства материала, из которого сделан объект, задаются при помощи процедуры glMaterial{i f}[v](GLenum face, GLenum pname, TYPE param).

Параметр face указывает, для какой из сторон грани задается свойство, и принимает одно из следующих значений: GL_BACK, GL_FRONT_AND_BACK, GL_FRONT.

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

Расчёт освещённости в OpenGL не учитывает затенения одних объектов другими.

10.7. Полупрозрачность. Использование α-канала

До сих пор не рассматривался α-канал (в RGBA-представлении цвета) и значение соответствующей компоненты во всех примерах всегда равнялось единице. Задавая значения, отличные от единицы, можно смешивать цвет выводимого пикселя с цветом пикселя, уже находящегося в соответствующем месте на экране, создавая тем самым эффект прозрачности.

При этом наиболее естественно думать об этом, считая что RGB-компоненты задают цвет фрагмента, α-значение – его непрозрачность (степень поглощения фрагментом проходящего через него света). Так, если у стекла установить значение, равное 0.2, то в результате вывода цвет получившегося фрагмента будет на 20 % состоять из собственного цвета стекла и на 80 % – из цвета фрагмента под ним.

Для использования α-канала необходимо сначала разрешить режим прозрачности и смешения цветов командой gEnable(GL_BLEND).

В процессе смешения цветов цветовые компоненты выводимого фрагмента RsGsBsAs смешиваются с цветовыми компонентами уже выведенного фрагмента RdGdBdAd по формуле

(RsSr+RdDr, GsSg+GdDg, BsSb+BdDb, AsSa+AdDa),

где (Sr, Sg, Sb, Sa) и (Dr, Dg, Db, Da) – коэффициенты смешения.

Для задания связи этих коэффициентов с α-значениями используется функция glBlendFunc(GLenum sfactor, GLenum dfactor).

Здесь параметр sfactor задаёт то, как нужно вычислять коэффииенты (Sr, Sg, Sb, Sa), а параметр dfactor – коэффициенты (Dr, Dg, Db, Da).

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

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

Для использования текстуры надо сначала разрешить одно- или двумерное текстурирование при помощи команд glEnable(GL_TEXTURE1D) или glEnable(GL_TEXTURE_2D).

Для задания двумерной текстуры служит процедура glTexlmage2D(GLenum target, GLint level, GLint component, GLsizei width, GLsizei height, GLint border, GLenum format, GLenum type, const GLvoid *pixels).

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

Следующий параметр component – целое число от одного до четырех, показывающее, какие из RGBA-компонент выбраны для использования. Значение 1 выбирает компоненту R, значение 2 выбирает R и А компоненты, 3 соответствует R, G и В, а 4 соответствует компонентам RGBA.

Параметры width и height задают размеры текстуры, border задает размер границы (бортика), обычно равный нулю. Как параметр width, так и параметр height, должны иметь вид 2n + 2b, где n – целое число, a b – значение параметра border. Максимальный размер текстуры зависит от реализации OpenGL, но он не менее 64 на 64.

При текстурировании OpenGL поддерживает использование пирамидального фильтрования (mip-mappping). Для этого необходимо иметь текстуры всех промежуточных размеров, являющихся степенями двух, вплоть до 1´1, и для каждого такого разрешения вызвать glTexImage2D с соответствующими параметрами level, width, height и image. Кроме того, необходимо задать способ фильтрования, который будет применяться при выводе текстуры.

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

Способ выбора соответствующего текселя, как для увеличения, так и для уменьшения (сжатия) текстуры необходимо задать отдельно. Для этого используется процедура glTexParameteri(GL_TEXTURE_2D, GLenum p1, GLenum p2), где параметр p1 показывает, задается ли фильтр для сжатия или для растяжения текстуры, принимая значение GL_TEXTURE_MIN_FLITER или GL_TEXTURE_MAG_FILTER. Параметр p2 задает способ фильтрования.

При использовании пирамидального фильтрования помимо выбора текселя на одном слое текстуры появляется возможность либо выбрать один соответствующий слой, либо проинтерполировать результаты выбора между двумя соседними слоями. Для правильного применения текстуры каждой вершине следует задать соответствующие ей координаты текстуры при помощи процедуры glTexCoord{1 2 3 4}{s i f d}[v](TYPE coord, ...).

Этот вызов задаёт значения индексов текстуры для последующей команды gIVertex.

Если размер грани больше, чем размер текстуры, то для циклического повторения текстуры служат команды gITexParameteri (GL_TEXTURE_2D, GL_TEXTURE_S_WRAP, GL_REPEAT), gITexParameteri(GL_TEXTURE_2D, GL_TEXTURE_T_WRAP, GL_REPEAT).

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

gIMatrixMode(GL_TEXTURE);

gIRotatef(...};

gIMatrixMode(GL_MODELV1EW);

При выводе текстуры OpenGL может использовать линейную интерполяцию (аффинное текстурирование) или же точно учитывать перспективное искажение. Для задания точного текстурирования служит команда glHint(GL_PERSPECTIVE_CORRECTION_HINT, GL_NICEST).

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

Описанный выше способ работ с текстурами используется в OpenGL версии 1.0. В более новых версиях OpenGL, начиная с версии 1.1, введены дополнительные функции, повышающие удобство работы с текстурами. В OpenGL 1.0 процедуру glTexImage2D необходимо вызывать всякий раз, когда нужно сменить текущую текстуру. Это достаточно медленный способ. В OpenGL 1.1 имеется возможность присваивать имена текстурам и затем сменять текущую текстуру только указанием имени новой текстуры, без повторной её загрузки в память процедурой glTexImage2D.

Имя текстуры представляет собой уникальное значение типа GLuint. Перед использованием текстуры необходимо присвоить ей имя. Имена текстур можно сгенерировать при помощи процедуры glGenTextures(GLsizei n, GLuint *textures).

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

Для выбора текущей (активной) текстуры используется функция glBindTexture(GLenum target, GLuint texture).

Параметр target определяет тип текстуры (одномерная – GL_TEXTURE_1D или двумерная – GL_TEXTURE_2D). На практике более часто используются двумерные текстуры, которые представляют собой обычные двумерные изображения. Параметр texture определяет имя текстуры, которую необходимо сделать активной.

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

Для того чтобы наложить текстуру на объект или многоугольник достаточно установить активную текстуру (процедура glBindTexture) и определить текстурные координаты при помощи процедуры glTexCoord.

Достоинство использования функций OpenGL 1.1 для работы с текстурами заключается не только в более высоком быстродействии по сравнению с использованием процедуры glTexImage2D, но и в повышенном удобстве работы с текстурами. Создав массив текстурных имён можно работать одновременно с несколькими текстурами, вызывая лишь функцию glBindTexture по мере необходимости.

 








Не нашли, что искали? Воспользуйтесь поиском по сайту:



©2015 - 2024 stydopedia.ru Все материалы защищены законодательством РФ.