Студопедия — Смешивание цвета в трехмерном пространстве
Студопедия Главная Случайная страница Обратная связь

Разделы: Автомобили Астрономия Биология География Дом и сад Другие языки Другое Информатика История Культура Литература Логика Математика Медицина Металлургия Механика Образование Охрана труда Педагогика Политика Право Психология Религия Риторика Социология Спорт Строительство Технология Туризм Физика Философия Финансы Химия Черчение Экология Экономика Электроника

Смешивание цвета в трехмерном пространстве






Примеры показывают, что порядок создания объектов влияет на результат смешивания цветов. Трехмерные сцены OpenGL требуют особой техники смешивания. Если в сцене одновременно участвуют как непрозрачные, так и светопроницаемые (translucent) объекты, то для повышения эффективности передачи естественно воспользоваться буфером глубины (depth buffer) или буфером оси Z. Конвейер OpenGL использует его для ответа на вопрос, виден ли конкретный фрагмент поверхности объекта. Если объект находится ближе к наблюдателю, чем какой-то другой с теми же экранными (двухмерными) координатами, то цвет ближнего объекта замещает цвет фрагмента, который уже находится в буфере кадра. Итак, точки невидимых объектов исчезают, то есть не изображаются, а, следовательно и не участвуют в смешивании цветов. При этом повышается производительность работы конвейера. Буфер глубины должен отсекать все объекты, расположенные за непрозрачными телами, но не делать этого, если ближний объект обладает какой-то степенью прозрачности.

Если сцена статична, то мы можем управляеть этим процессом с помощью порядка следования объектов и своевременного включения смешивания. Но если объекты (или наблюдатель) перемещаются, то проблема становится более сложной. Эффект анимации требует особого подхода, так как дальний объект может выйти на передний план и результат должен зависеть от того, прозрачен он или нет. Решением проблемы является управление режимом работы буфера глубины. Сначала создаются непрозрачные объекты и буфер глубины при этом работает в нормальном режиме, отсекая все объекты расположенные за ними. Затем мы включаем режим смешивания, устанавливаем буфер глубины в режим «только чтение» (read-only) и создаем полупрозрачные объекты. При этом ближние объекты не могут заслонить дальние, так как изменения в буфере глубины запрещены. В конце процесса рисования надо вновь выключить режим смешивания и снять флаг режима read-only. Заметьте, что работа выполняется без учета первоначального взаимного расположения объектов в статической сцене. Переключение режима «только чтение» выполняет команда glDepthMask. Параметр GL_FALSE включает его, а параметр GL_TRUE восстанавливает нормальный режим работы буфера.

Следующий пример демонстрирует как использовать такой метод для создания двух объектов с разными светопроницающими свойствами. В нем также иллюстрируются некоторые другие технологические приемы. Например, как внести эффект анимации с помощью функции glutIdleFunc. Она сообщает системе адрес функции, которую следует вызывать каждый раз, когда очередь сообщений приложения оказывается пустой, то есть когда приложению (временно) нечего делать. В параметре этой функции мы указываем адрес другой нашей функции (Animate), которая будет вызываться настолько часто, насколько часто наше приложение оказывается бездействующим. В теле функции Animate (чтобы время не пропадало даром) мы изменяем значения глобальных переменных, которые определяют позицию двух объектов в трехмерном пространстве. Если в этот момент перерисовать сцену, то объекты сместятся. Таким образом система постоянно инициирует перерисовку сцены, что при использовании двух буферов кадра воспринимается как анимация изображения.

Команда перерисовки в нашем GLUT-каркасе может выглядеть как прямой вызов OnPaint (что было бы недопустимо в каркасе MFC), но мы делаем это другим (более корректным с точки зрения традиционного Windows-программирования) способом. Мы сообщаем системе, что окно нуждается в перерисовке без предварительного стирания фона (см. команду InvalidateRect). В ответ на это система пошлет нам сообщение WM_PAINT, которое будет обработано в OnPaint. Описатель окна (переменная типа HWND), необходимая для вызова InvalidateRect, может быть получен с помощью функции glutGetHWND.

InvalidateRect(glutGetHWND(),0,FALSE); // Значение FALSE говорит о том, что не надо стирать фон окна

Другим новым приемом является вызов функции glGenLists, которая способна сгенерировать множество пустых списков изображений. Мы дважды просим ее создать по одному списку, затем заполняем списки командами. Важно понять, что функции glutSolidSphere и glutSolidCube генерируют много команд, создающих объекты из примитивов, которые в свою очередь собираются из вершин. Затем эти команды из откомпилированных списков воспроизводятся в функции перерисовки (см. вызов glCallList).

float gSphereZ = 1, gCubeZ = -1; // Начальные смещения

unsigned gSphere, gCube; // Индексы списков команд изображений

 

void Init()

{

float spec[] = { 1, 1, 1, 0.15f };

glMaterialfv(GL_FRONT, GL_SPECULAR, spec);

 

glMaterialf(GL_FRONT, GL_SHININESS, 100.);

float pos[] = { 0.5f, 0.5f, 1, 0 };

glLightfv(GL_LIGHT0, GL_POSITION, pos);

 

glEnable(GL_LIGHTING);

glEnable(GL_LIGHT0);

glEnable(GL_DEPTH_TEST);

 

gSphere = glGenLists(1); // Список команд для изображения сферы

glNewList(gSphere, GL_COMPILE);

glutSolidSphere (0.35);

glEndList();

 

gCube = glGenLists(1); // Список команд для изображения куба

glNewList(gCube, GL_COMPILE);

glutSolidCube (0.8);

glEndList();

}

 

void OnPaint()

{

glClear (GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);

 

glPushMatrix ();

glTranslated (-0.05, 0, -3.5);

glTranslated (0, 0, gSphereZ);

 

float dif[] = { 0.8f, 0.8f, 0, 1 };

glMaterialfv(GL_FRONT, GL_DIFFUSE, dif);

float emis[] = { 0, 0, 0, 1 };

glMaterialfv(GL_FRONT, GL_EMISSION, emis);

 

glCallList (gSphere); // Вызываем список команд для изображения сферы

glPopMatrix ();

 

glPushMatrix ();

glTranslated (0, 0, -3.5);

glTranslated (0, 0, gCubeZ);

glRotated (15, 1, 1, 0);

glRotated (30, 0, 1, 0);

 

float emic[] = { 0, 0.3f, 0.3f, 0.6f };

glMaterialfv(GL_FRONT, GL_EMISSION, emic);

 

float difc[] = { 0, 0.8f, 0.8f, 0.6f };

glMaterialfv(GL_FRONT, GL_DIFFUSE, difc);

 

glEnable (GL_BLEND);

glDepthMask (FALSE);

glBlendFunc (GL_SRC_ALPHA, GL_ONE);

glCallList (gCube); // Вызываем список команд для изображения куба

glDepthMask (TRUE);

glDisable (GL_BLEND);

glPopMatrix ();

 

glutSwapBuffers();

}

 

void Animate() // Анимируем сцену периодически приближая-удаляя объекты

{

static bool b = true;

gSphereZ += b? -0.04f: 0.04f;

gCubeZ += b? 0.04f: -0.04f;

if (gSphereZ <= -1. || gSphereZ >= 1.)

b =!b;

InvalidateRect(glutGetHWND(),0,FALSE);

}

 

void OnSize (int w, int h)

{

if (!h)

return;

glViewport(0, 0, w, h);

glMatrixMode(GL_PROJECTION);

glLoadIdentity();

 

gluPerspective(35, float(w) / h, 1, 100);

glMatrixMode(GL_MODELVIEW);

glLoadIdentity();

}

 

void OnSpecialKey (int key, int x, int y)

{

switch (key)

{

case GLUT_KEY_DOWN:

gSphereZ = 1;

gCubeZ = -1;

glutIdleFunc(0);

break;

case GLUT_KEY_UP: glutIdleFunc(Animate); break;

}

glutPostRedisplay();

}

Ускорить rendering сцены можно путем отказа от генерации обратных граней объектов. Это делается с помощью команды glEnable(GL_CULL_FACE);. Вставьте ее в функцию Init и сравните результат. Скорость передачи увеличилась за счет потерь в реалистичности. Попробуйте поменять порядок создания объектов сцены и объясните результат.

Напускаем туману (Fog)

Компютерные изображения обычно далеки от реальности и одной из причин этого является слишком большой уровень контрастности. Такой механизм OpenGL как antialiasing способен сгладить ребра граней или кромки объектов, но главным инструментов в повышении реалистичности изображения является внесение атмосферных эффектов. Fog (туман) — это обобщенный термин, который используентся для описания всех атмосферных эффектов: моросящий дождь, дымка, городской смог, промышленные загрязнения. Основным качеством этих явлений является затухание контраста изображения на расстоянии. Такие эффекты играют важную роль при разработке тренажеров для пилотов (программах-симуляторах полета).

При включенном режиме тумана glEnable(GL_FOG) цвет объекта при отдалении его от наблюдателя постепенно превращается в цвет тумана. Мы имеем возможность управлять плотностью тумана, его цветом и параметрами затухания изображения. Туман вступает в игру после того, как конвейер произвел матричные преобразования, учет освещенности и текстуры. В больших программах-симуляторах, программах молекулярного моделирования применение тумана может даже повысить производительность, если отказаться от прорисовки объектов, которые слишком «затуманены». Использовать туман легко, но трудно подобрать его параметры чтобы добиться желаемого эффекта. Семейство функций glFog* позволяет управлять плотностью тумана путем выбора одной из трех формул затухания изображения. Туманный механизм смешивает цвет фрагмента изображаемого объекта с цветом тумана, используя blending так, как было описано в предыдущем разделе. Коэффициенты смешивания вычисляются в зависимости от выбранного режима по следующим формулам.

GL_LINEAR
GL_EXP
GL_EXP2

Здесь z — это расстояние от глаза наблюдателя до центра фрагмента; d — плотность тумана; a — начало интервала линейного изменения плотности; b — конец интервала. Последние 3 параметра задаются с помощью функций glFog*. Коэффициенты нормируются так, чтобы попасть в диапазон [0,1]. Дополнительной регулировкой является команда glHint, которая дает возможность управлять точностью вычисления тумана. Следующий пример демонстрирует технологию наведения тумана. В консольное окно выводится текстовое описание, соответствующее значению переменной gMode (тип тумана). Вам необходимо включить туман и задать его параметры.

// Каждое нажатие клавиши F переключает тип тумана: (exponential, exponential squared, linear).

// Каждое нажатие пробела увеличивае-уменьшает плотность тумана

// Каждое нажатие L включает-выключает режим Local Viewer

 

double gx, gy, gz = 8;

float gDens; // Плотность тумана

int gMode = GL_EXP2; // Начальный тип тумана

int gLocalViewer; // Начальный значение параметра в glLightModeli

 

void RedTeapot () // Изображение красного блестящего чайника

{

glNewList(1, GL_COMPILE);

float f[] = { 0.1745f, 0.01175f, 0.01175f };

glMaterialfv (GL_FRONT, GL_AMBIENT, f);

 

f[0] = 0.61424f; f[1] = 0.04136f; f[2] = 0.04136f;

glMaterialfv (GL_FRONT, GL_DIFFUSE, f);

 

f[0] = 0.727811f; f[1] = 0.626959f; f[2] = 0.626959f;

glMaterialfv (GL_FRONT, GL_SPECULAR, f);

 

glMaterialf (GL_FRONT, GL_SHININESS, 0.6*128);

 

glutSolidTeapot(1);

glEndList();

}

 

void SwitchFog() // Переключение типа тумана

{

switch (gMode)

{

case GL_EXP:

gMode = GL_EXP2;

cout << "\nFog mode is GL_EXP2";

break;

case GL_EXP2:

gMode = GL_LINEAR;

cout << "\nFog mode is GL_LINEAR";

glFogf (GL_FOG_START, 2);

glFogf (GL_FOG_END, 12);

break;

case GL_LINEAR:

gMode = GL_EXP;

cout << "\nFog mode is GL_EXP";

break;

}

 

glFogi (GL_FOG_MODE, gMode); // Установка типа тумана

}

 

void Init()

{

glClearColor(0.5, 0.5, 0.5, 1);

glEnable(GL_DEPTH_TEST);

glEnable(GL_LIGHTING);

glEnable(GL_LIGHT0);

 

glEnable(GL_AUTO_NORMAL);

glEnable(GL_NORMALIZE);

 

float f[] = { 0, 3, 3, 0 };

glLightfv(GL_LIGHT0, GL_POSITION, f);

glLightModeli(GL_LIGHT_MODEL_LOCAL_VIEWER, gLocalViewer);

 

RedTeapot ();

 

// Здесь включите туман, задайте его цвет (серый). Задайте его плотность (gDens).

// Задайте качество передачи (glHint). Вызовите функцию SwitchFog

}

 

void OnPaint()

{

static float

x[] = { -1, 0, 1 },

y[] = { 1, 0,-1 },

z[] = { 0,-2,-4 };

 

glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);

glPushMatrix ();

gluLookAt (gx, gy, gz, 0, 0, 0, 0, 1, 0);

 

for (GLuint i=0; i<3; i++)

{

glPushMatrix();

glTranslatef (x[i], y[i], z[i]);

glCallList(1);

glPopMatrix();

}

glPopMatrix ();

 

glutSwapBuffers();

}

 

void OnSize(int w, int h)

{

if (!h)

return;

glViewport(0, 0, w, h);

glMatrixMode(GL_PROJECTION);

glLoadIdentity();

 

gluPerspective(30, double(w)/ h, 1, 40);

 

glMatrixMode(GL_MODELVIEW);

glLoadIdentity();

}

 

void OnSpecialKey (int key, int x, int y)

{

switch (key)

{

case GLUT_KEY_LEFT: gx +=.5; break;

case GLUT_KEY_RIGHT: gx -=.5; break;

case GLUT_KEY_DOWN: gy -=.5; break;

case GLUT_KEY_UP: gy +=.5; break;

}

glutPostRedisplay();

}

void OnKey (unsigned char ch, int x, int y)

{

static bool bGrow = true; // Флаг роста плотности тумана

 

switch (ch)

{

case 27: exit(0); break;

case ' ':

gDens += bGrow? 0.05f: -0.05f;

if (fabs(gDens) < 0.01 || gDens > 0.2)

bGrow =!bGrow;

glFogf (GL_FOG_DENSITY, gDens);

break;

case 'f': SwitchFog();break;

}

glutPostRedisplay();

}

Установка GL_LIGHT_MODEL_LOCAL_VIEWER, задаваемая командой glLightModelfv, работает по умолчанию (равна 0). Она сделана для того, чтобы вы знали, что с ее помощью можно задать способ вычисления угла отражения specular -компоненты света. Если второй параметр функции равен нулю, то свет отражется параллельно оси –z, независимо от координат текущей вершины объекта и глаза наблюдателя. При других значениях параметра угол отражения зависит от взаимного расположения объекта и глаза. Введите управление и мониторинг оставшихся параметров тумана.

Текстурные отображения (Texture Mapping)

До сих пор внутренние области всех геометрических примитивов либо заполнялись одним и тем же, сплошным цветом, либо оттенялись цветом собственных вершин в режиме интерполяции цветов. Однако существует еще один способ заполнения примитивов, с помощью текстурных отображений. Текстура — это bitmap-изображение, накладываемое, а точнее, по довольно сложному алгоритму отображаемое на поверхность геометрического примитива для создания эффекта реального (или нереального) материала, из которого объект изготовлен. Фактура реального материала часто имитируется одним и тем же, но повторяющимся изображением.

На деле текстура — это массив данных, описывающих прямоугольную поверхность. Элементы этого массива иногда называют текселами (texels). Основным достоинством алгоритмов обработки текстур является то, что они позволяют отобразить текстуру и на непрямоугольную область. Следующая серия рисунков иллюстрирует эту технику. Сначала из bmp -файла загружается обычное прямоугольное растровое изображение.

Затем, например, 3 его точки совмещаются с 3 точками примитива GL_TRIANGLE (отображение без искажений).

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

Заметьте, что в новом треугольнике только одна из вершин (верхняя) изменила свои координаты. Этот алгоритм ниже будет использован при разработке приложения для анимации изображений. Там и были получены эти картинки, правда затем пришлось в PhotoDraw вырезать ненужные детали, так как все изображение имеет прямоугольную форму и состоит из 4-х подобных треугольников. Приложение мы создадим позже, а сейчас начнем с более простого примера, для объяснения работы которого, тем не менее, потребуются определенные усилия. Чтобы стало ясно что дает текстура, запустите приведенный ниже готовый код. Вы должны увидеть чайник, расписанный одномерным текстурным узором. Одномерная текстура как бы накатана на поверхность чайника. Важно то, что здесь узор был создан программным способом, а не взят из файла.

Создайте новый файл, поместите в него следующий код и подключите его к вашему проекту консольного типа.

// Автоматически генерируемая текстура задана одномерным массивом gStripes

BYTE gStripes [3 * 32]; // 32 тройки типа (red, green, blue)

double gParam[] = { 1, 1, 1, 0 };// Массив с параметрами генерации текстуры

double gx, gy, gz = 15, // Для перемещения наблюдателя

void MakeStripes() // Заполнение массива байтов цветами текстуры

{

for (int i = 0; i < 32; i++) // 32 тройки типа (red, green, blue)

{

int r = 3 * i, // Индексы компонент цвета в массиве

g = r + 1,

b = g + 1;

if (i <= 4)

gStripes[r] = 255; // Ширина красной полосы 4 пиксела

else if (i <= 8)

gStripes[g] = 255; // Зеленой тоже

else

gStripes[b] = 255; // Ширина синей полосы 32 – 8 = 24 пиксела

}

}

void Init()

{

glClearColor (0, 0, 0, 0);

glEnable(GL_DEPTH_TEST);

glShadeModel(GL_FLAT);

glEnable(GL_TEXTURE_GEN_S); // Активизируем режим вывода одномерной текстуры

glEnable(GL_TEXTURE_1D);

//==== Эти команды нужны чайнику

glEnable (GL_CULL_FACE);

glCullFace (GL_BACK);

glEnable (GL_LIGHTING);

glEnable (GL_LIGHT0);

glEnable (GL_AUTO_NORMAL);

glEnable (GL_NORMALIZE);

glFrontFace (GL_CW);

glMateriali (GL_FRONT, GL_SHININESS, 128);

MakeStripes(); // Создаем массив, описывающий текстуру

 

glPixelStorei(GL_UNPACK_ALIGNMENT, 1); // Выравнивание по границе байта

//=== Как интерпретировать текстурные значения при текстурировании фрагмента

glTexEnvf (GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE);

//=== Определение текстурных параметров. Требуем бесконечно повторять узор

glTexParameterf (GL_TEXTURE_1D, GL_TEXTURE_WRAP_S, GL_REPEAT);

//=== При растяжении и сжатии требуем линейно усреднять цвет

glTexParameterf (GL_TEXTURE_1D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);

glTexParameterf (GL_TEXTURE_1D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);

//=== Определение текстурного изображения

glTexImage1D (GL_TEXTURE_1D, 0, 3, 32, 0, GL_RGB, GL_UNSIGNED_BYTE, gStripes);

glTexGeni (GL_S, GL_TEXTURE_GEN_MODE, GL_OBJECT_LINEAR);

glTexGendv (GL_S, GL_OBJECT_PLANE, gParam);

}

void OnPaint()

{

glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);

glPushMatrix ();

gluLookAt (gx, gy, gz, 0, 0, 0, 0, 1, 0);

glRotatef(10, 1, 0, 0);

glutSolidTeapot(2);

glPopMatrix ();

glutSwapBuffers();

}

void OnSize(int w, int h)

{

if (!h)

return;

glViewport(0, 0, w, h);

glMatrixMode(GL_PROJECTION);

glLoadIdentity();

gluPerspective (30, double(w)/ h, 1, 100);

glMatrixMode(GL_MODELVIEW);

glLoadIdentity();

}

void OnSpecialKey (int key, int x, int y)

{

switch (key)

{

case GLUT_KEY_LEFT: gx += 1; break;

case GLUT_KEY_RIGHT: gx -= 1; break;

case GLUT_KEY_DOWN: gy -= 1; break;

case GLUT_KEY_UP: gy += 1; break;

}

glutPostRedisplay();

}

Интересно, обратили ли вы внимание на то, что мы задали максимальный уровень блеска материалу чайника, но он не блестит? Попробуйте это исправить.

Главной командой, которая создает одномерную текстуру, является glTexImage1D.

glTexImage1D (GL_TEXTURE_1D, 0, 3, 32, 0, GL_RGB, GL_UNSIGNED_BYTE, gStripes);

Именно она, совместно с массивом gStripes, определяет текстурное изображение (texture image), которое может иметь до 4-х компонент цвета. Мы задали изображение, использующее 3 компоненты (RGB) цвета, значения которых следует брать из массива байт gStripes. Второй параметр задает уровень детализации изображения. Он соответствует индексу изображения в последовательности mipmap. 3-й параметр — это размер изображения. 4-й параметр — это граница (должна быть 0, или 1). При единице текстура исчезает. Генерация текстуры осуществляется с помощью функции:

glTexGendv (GL_S, GL_OBJECT_PLANE, gParam);

Чтобы продемонстрировать способы накатки текстуры и прояснить роль загадочного массива gParam, проведите эксперимент. Задайте в качестве инициализирующего выражения для gParam такие значения: { 0., 1., 0., 0. }. В результате вы получите изображение:

Затем замените выражение на { 0., 0., 1., 0. } и вы получите новое достижение в области дизайна.

Если экспериментов недостаточно, чтобы понять смысл элементов массива gParam, или вы почуствовали вкус к новому роду деятельности, то попробуйте задать другие значения и получить что-то новое, например:







Дата добавления: 2015-10-19; просмотров: 737. Нарушение авторских прав; Мы поможем в написании вашей работы!



Композиция из абстрактных геометрических фигур Данная композиция состоит из линий, штриховки, абстрактных геометрических форм...

Важнейшие способы обработки и анализа рядов динамики Не во всех случаях эмпирические данные рядов динамики позволяют определить тенденцию изменения явления во времени...

ТЕОРЕТИЧЕСКАЯ МЕХАНИКА Статика является частью теоретической механики, изучающей условия, при ко­торых тело находится под действием заданной системы сил...

Теория усилителей. Схема Основная масса современных аналоговых и аналого-цифровых электронных устройств выполняется на специализированных микросхемах...

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

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

Примеры задач для самостоятельного решения. 1.Спрос и предложение на обеды в студенческой столовой описываются уравнениями: QD = 2400 – 100P; QS = 1000 + 250P   1.Спрос и предложение на обеды в студенческой столовой описываются уравнениями: QD = 2400 – 100P; QS = 1000 + 250P...

Травматическая окклюзия и ее клинические признаки При пародонтите и парадонтозе резистентность тканей пародонта падает...

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

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

Studopedia.info - Студопедия - 2014-2024 год . (0.011 сек.) русская версия | украинская версия