Добавил:
Upload Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:
Библиотека OpenGL.doc
Скачиваний:
12
Добавлен:
05.09.2019
Размер:
180.74 Кб
Скачать

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

До сих пор не рассматривался α-канал (в 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).

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

Текстурирование позволяет наложить изображение на многоугольник и вывести этот многоугольник с нало­женной на него текстурой, соответствующим образом преобразо­ванной. 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 – целое число от 1 до 4, показывающее, какие из 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. Кроме того, необходимо задать способ фильтрования, который будет применяться при выводе текстуры.

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

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

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, но и в повышенном удобстве ра­боты с текстурами.

Вначале мы добавим две переменные для хранения угла вращения каждого объекта. Мы сделаем это вначале программы. Посмотрите ниже, я добавил две строки после объявления переменной BOOL keys[256]. В этих строках объявляются две переменные с плавающей запятой, которые мы можем использовать для очень точного поворота объектов. Числа с плавающей запятой учитывают значения меньше единицы. Вместо использования 1, 2, 3 для угла, мы можем использовать 1.1, 1.7, 2.3 или даже 1.015 для точности. Вы увидете, что числа с плавающей запятой неотемлимая часть программирования на OpenGL.

#include <windows.h>      // Заголовочный файл для Windows #include <gl\gl.h>        // Заголовочный файл для OpenGL32 библиотеки #include <gl\glu.h>       // Заголовочный файл для GLu32 библиотеки #include <gl\glaux.h>     // Заголовочный файл для GLaux библиотеки static HGLRC hRC;       // Постоянный контекст рендеринга static HDC hDC;         // Приватный контекст устройства GDI BOOL    keys[256];      // Массив для процедуры обработки клавиатуры GLfloat rtri;           // Угол для треугольник GLfloat rquad;          // Угол для четырехугольника

Необходимо модифицировать код в DrawGLScene(). Я буду переписывать всю процедуру. Это будет сделать легко для Вас, так как Вы увидите какие изменения я сделал. Я объясню почему некоторые строки были модифицированы, и какие линии добавлены. Следующая секция кода, такая же как в последнем уроке.

GLvoid DrawGLScene(GLvoid) { glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);     // Очистка экрана                                                         //      и буфера глубины glLoadIdentity();                                       // Сброс просмотра glTranslatef(-1.5f,0.0f,-6.0f);                         // Сдвиг в глубь экрана и влево

Следующая строка новая. glRotatef(Angle,Xtrue,Ytrue,Ztrue) отвечает за вращения объекта вдоль оси. Вы многое получите от использования этой команды. Угол некоторое число (обычно переменная), которое задает насколько Вы хотите повернуть объект. Xtrue, Ytrue и Ztrue или 0.0f или 1.0f. Если один из параметров равен 1.0f, OpenGL будет вращать объект вдоль соответствующей оси. Поэтому если Вы имеете glRotatef(10.0f,0.0f,1.0f,0.0f), объект будет поварачиваться на 10 градусов по оси Y. Если glRotatef(5.0f,1.0f,0.0f,1.0f), объект будет поварачиваться на 5 градусов по обеим осям X и Z.

Чтобы лучше понять вращения по осям X, Y и Z я объясню это на примерах.

Ось X - предположим Вы работаете за токарным станком. Заготовка перемещается слева направо (также как ось X в OpenGL). Заготовка вращается вокруг оси X. Также мы вращаем что-то вокруг оси X в OpenGL.

Ось Y- Представьте что Вы стоите посреди поля. Огромный торнадо приближается к Вам. Центр торнадо перемещается от земли в небо (верх и низ, подобно оси Y в OpenGL). Предметы захваченные торнадо кружаться вдоль оси Y (центр торнадо) слева направо или справо налево. Когда вы вращаете что-то вокруг оси Y в OpenGL, это что-то будет вращаться также.

Ось Z - Вы смотрите на переднюю часть вентилятора. Передняя часть вентилятора ближе к Вам, а дальняя часть дальше от Вас (также как ось Z в OpenGL). Лопасти вентилятора вращаются вдоль оси Z (центр вентилятора) по часовой или против часовой стрелки. Когда Вы вращаете что-то вокруг оси Z в OpenGL, это что-то будет вращаться также.

В следующей строке кода, если rtri равно 7, мы будем вращать на 7 градусов по оси Y (слева направо). Вы можете поэксперементировать с кодом. Изменяйте от 0.0f до 1.0f, и от 1.0f до 0.0f вращение треугольника по осям X и Y одновременно.

        glRotatef(rtri,0.0f,1.0f,0.0f);         // Вращение треугольника по оси Y

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

        glBegin(GL_TRIANGLES);                  // Начало рисования треугольника                 glColor3f(1.0f,0.0f,0.0f);      // Верхняя точка - красная                 glVertex3f( 0.0f, 1.0f, 0.0f);  // Первая точка                 glColor3f(0.0f,1.0f,0.0f);      // Левая точка - зеленная                 glVertex3f(-1.0f,-1.0f, 0.0f);  // Вторая                 glColor3f(0.0f,0.0f,1.0f);      // Правая - синия                 glVertex3f( 1.0f,-1.0f, 0.0f);  // Третья         glEnd();                                // Конец рисования

Посмотрите на код ниже, там мы добавим вызов glLoadIdentity(). Мы сделаем это для инициализации просмотра. Что будет если мы не сбросим просмотр? Если мы сдвинули объект после вращения, Вы получите очень неожиданные результаты. Поскольку оси вращаются, они будут указывать не в тех направлениях, о каких Вы думаете. Поэтому если мы сдвинулись влево по оси X (для установки треугольника), мы можем переместить квадрат в глубь экрана или вперед, в зависимости от того как много мы вращали по оси Y. Попробуйте убрать glLoadIdentity() и вы поймете о чем я говорю. Квадрат будет вращаться вокруг своей оси X, но и вокруг центра координат синхронно вращению треугольника.

Так как сцена сброшена, поэтому X идет слева направо, Y сверху вниз, Z от нас и далее. Теперь мы перемещаем. Как Вы видите мы сдвигаем на 1.5 вправо, вместо 3.0, как мы делали в последнем уроке. Когда мы сбрасываем экран, наш фокус перемещается в центр экрана, это означает, что мы находимся не 1.5 единицы слева, мы вернулись в 0.0. Поэтому мы не должны сдвигаться на 3.0 единицы вправо (если бы не было сброса), мы должны только сдвинуться от центра вправо на 1.5 единицы.

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

        glLoadIdentity();         glTranslatef(1.5f,0.0f,-6.0f);          // Сдвиг вправо на 1.5         glRotatef(rquad,1.0f,0.0f,0.0f);        // Вращение по оси X

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

        glColor3f(0.5f,0.5f,1.0f);              // Синий цвет         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();                                // Окончим

Следующие две строки новые. Думайте о rtri и rquad как о контейнерах. Вначале нашей программы мы сделали контейнеры (GLfloat rtri и GLfloat rquad). Когда мы построили контейнеры они были пусты. В первой строке ниже ДОБАВЛЯЕМ 0.2 в контейнер. Если мы проверим значение контейнера rtri после этой секции кода, мы увидим что оно увеличилось на 0.2. Контейнер rquad уменьшиться на 0.15. Если мы проверим значение контейнера rquad после этой секции кода, мы увидим что оно уменьшилось на 0.15. Отрицательные значения вращения приводят к тому, что объект вращается в противоположную сторону. Как если бы значения были положительные.

Попробуйте изменить + на - в строке ниже и объект будет вращаться в другом направлении. Попробуйте изменить значение с 0.2 до 1.0. С увеличением значения объект будет вращаться быстрее. С уменьшением значения будет вращаться медленее.

        rtri+=0.2f;             // Увеличение переменной вращения для треугольника         rquad-=0.15f;           // Уменьшение переменной вращения для квадрата }

glPushMatrix, glPopMatrix (…attrib)

glPushAttrib(GL_COLOR_BUFFER_BIT or GL_CURRENT_BIT or GL_LIGHTING_BIT or GL_TEXTURE_BIT); glPushAttrib() сохраняет все атрибуты, указанные битами в параметре mask, помещая их в стек атрибутов. glPopAttrib() восстанавливает значения тех переменных состояния, которые были сохранены командой glPushAttrib().

Функции glPushMatrix и glPopMatrix предназначены для помещения матриц в стек и извлечения из него.

void glPushMatrix(

void

);

void glPopMatrix(

void

);

Параметры

Функции не принимают параметров. 

Пояснения

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

Для каждого режима матриц, таких как GL_MODELVIEW, GL_PROJECTION и GL_COLOR, а также для каждого текстурного модуля, существует стек матриц. Если функцией glMatrixMode установлен матричный режим GL_TEXTURE, то функции glPushMatrix и glPopMatrix будут оперировать над стеком активного текстурного модуля.

Глубина стека матриц в режиме GL_MODELVIEW не менее 32−х элементов, в других режимах — не менее 2−х. Стеки текстурных матриц имеют одинаковую глубину. В любом режиме матриц текущая матрица всегда находится на вершине стека.

Дополнительную информацию можно получить при помощи следующих функций:  glGet с аргументом GL_MATRIX_MODE,  glGet с аргументом GL_MODELVIEW_MATRIX,  glGet с аргументом GL_PROJECTION_MATRIX,  glGet с аргументом GL_TEXTURE_MATRIX,  glGet с аргументом GL_MODELVIEW_STACK_DEPTH,  glGet с аргументом GL_PROJECTION_STACK_DEPTH,  glGet с аргументом GL_TEXTURE_STACK_DEPTH,  glGet с аргументом GL_MAX_MODELVIEW_STACK_DEPTH,  glGet с аргументом GL_MAX_PROJECTION_STACK_DEPTH,  glGet с аргументом GL_MAX_TEXTURE_STACK_DEPTH.

Коды ошибок

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

Код ошибки

Пояснение

GL_STACK_OVERFLOW

Функция glPushMatrix вызвана, когда текущий стек матриц уже полон.

GL_STACK_UNDERFLOW

Функция glPopMatrix вызвана, когда в текущем стеке матриц осталась только одна матрица.

GL_INVALID_OPERATION

Функция glPushMatrix или glPopMatrix вызвана между glBegin и соответствующим ему вызову glEnd.

texture mapping наложение текстуры # в КГА - наложение текстур на трёхмерную поверхность (см. 3D graphicsbamp mapping,texture)

ALPHA BLENDING

alpha Blending Реальный мир состоит из прозрачных, полупрозрачных и непрозрачных объектов. Alpha B lending это способ передачи информации о прозрачности полупрозрачным объектам. Эффект прозрачности и просвечивания достигается путем смешивания значений цветов исходного и результирующего пикселей. Разделение изображения на многоугольники производится с использованием маски, плотность которой зависит от прозрачности объекта. В результате цвет точки является комбинацией цветов переднего и заднего плана. Обычно, Alpha имеет нормализованное значение от 0 до 1 для каждого цветного пикселя. Новый пиксель = (alpha) (цвет пикселя А) + (1 - alpha) (цвет пикселя В).

dithering

1. размывание [аудио]сигнала (для получения более естественного звучания);

2. псевдосмешение (размывание) цветов (точечных растров), проф. дизеринг # метод, используемый в КГА для получения за счёт смешения точек двух различных цветов оттенков плавных переходов при выводе цветного (полутонового) изображения на устройство, не имеющее возможности прямого вывода нужных цветов ( color dithering). Существует два способа смешивания цветов: pattern (шаблон) и scatter (разброс).

Depth Fog

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

glEnable(GL_LIGHTING) ОСВЕЩЕНИЕ

Параметр Описание

GL_AMBIENT • ИЗМЕНЯЕТ ЦВЕТ РАССЕЯННОГО ОТРАЖЕНИЯ МАТЕРИАЛА. ПАРАМЕТР PARAM ДОЛЖЕН СОДЕРЖАТЬ ЧЕТЫРЕ ЦЕЛЫХ ИЛИ ВЕЩЕСТВЕННЫХ ЗНАЧЕНИЯ ЦВЕТА РАССЕЯННОГО ОТРАЖЕНИЯ (RGBA) МАТЕ

РИАЛА. ПО УМОЛЧАНИЮ ЗНАЧЕНИЕ ЦВЕТА РАССЕЯННОГО ОТРАЖЕНИЯ РАВНО (0.2, 0.2, 0.2, 1.0).

GL_DIFFUSE • Изменяет цвет диффузного от-

ражения материала. Параметр

param должен содержать четыре

целых или вещественных значе-

ния цвета диффузного отражения

(RGBA) материала. По умолча-

нию значение цвета диффузного

отражения равно (0.8, 0.8, 0.8,

1.0)

GL_SPECULAR • Изменяет цвет зеркального от-

ражения материала. Параметр

param должен содержать четыре

целых или вещественных значе-

ния цвета зеркального отражения

(RGBA) материала. По умолча-

нию значение цвета зеркального

отражения равно (0.0, 0.0, 0.0,

1.0)

11