Добавил:
Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:
Компьютерная графика лабораторный практикум.doc
Скачиваний:
241
Добавлен:
01.05.2014
Размер:
1.41 Mб
Скачать

6.2. Тени объектов

Тени придают изображению большую реалистичность. Тень передает большое количество информации. В данном разделе рассматриваются два метода вычисления теней: "раскрашивание" теней; использование буфера глубины.

6.2.1. Тени как текстура

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

Рис. 6.4. Вычисление формы тени

На рис. 6.4., а показан параллелепипед, отбрасывающий тень на пол. орма тени определяется проекциями каждой грани параллелепипеда на плоскость пола, когда источник света является центром проекций. В действительности тень является объединением проекций шести граней. На рис. 6.4., б проиллюстрирована суперпозиция проекций двух граней: верхняя грань top проецируется в грань top`, а передняя грань front проецируется в front`.

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

Рис. 6.5. Иллюстрация примера построения теней.

6.2.2. Построение "спроецированной" грани

Для создания новой грани F` из исходной F производится проецирование каждой вершины грани F на рассматриваемую плоскость. Для этого необходим метод вычисления координат этих вершин на плоскости. Если предположить, что плоскость проходит через точку А и имеет нормальный вектор n. В этом случае проецирование вершины V - есть результат точка V`. Математическая сторона этого процесса: V` - это точка, в которой луч от источника света S, проходящей через точку V , пересекает плоскость. Эта точка задается формулой:

.

6.3. Пример реализации “зеркала”.

Рис. 6.6.

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

Алгоритм использует интуитивное представление полной сцены с зеркалом как составленной из двух: «настоящей» и «виртуальной» – находящейся за зеркалом. Следовательно, процесс рисования отражений состоит из двух частей: 1) визуализации обычной сцены и 2) построения и визуализации виртуальной. Для каждого объекта «настоящей» сцены строится его отраженный двойник, который наблюдатель и увидит в зеркале.

Рис. 6.7. Зеркальное отражение

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

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

  1. Рисуем сцену как обычно, но без объектов-зеркал.

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

  3. Визуализируем сцену, отраженную относительно плоскости зеркала.

При этом буфер маски позволит ограничить вывод формой проекции объекта-зеркала.

Эта последовательность действий позволит получить убедительный эффект отражения.

Рассмотрим этапы более подробно:

Сначала необходимо нарисовать сцену как обычно. Не будем останавливаться на этом этапе подробно. Заметим только, что, очищая буферы OpenGL непосредственно перед рисованием, нужно не забыть очистить буфер маски:

glClear(GL_COLOR_BUFFER_BIT|GL_DEPTH_BUFFER_BIT|

GL_STENCIL_BUFFER_BIT);

Во время визуализации сцены лучше не рисовать объекты, которые затем станут зеркальными.

На втором этапе необходимо ограничить дальнейший вывод проекцией зеркального объекта на экран.

Для этого настраиваем буфер маски и рисуем зеркало

glEnable(GL_STENCIL_TEST);

/* условие всегда выполнено и значение в буфере будет равно 1*/

glStencilFunc(GL_ALWAYS, 1, 0);

glStencilOp(GL_KEEP, GL_KEEP, GL_REPLACE);

RenderMirrorObject();

В результате мы получили:

в буфере кадра – корректно нарисованная сцена, за исключе-нием области зеркала; в области зеркала (там, где мы хотим видеть отражение) значение буфера маски равно 1.

На третьем этапе нужно нарисовать сцену, отраженную относительно плоскости зеркального объекта.

Сначала настраиваем матрицу отражения. Матрица отражения должна зеркально отражать всю геометрию относительно плоскости, в которой лежит объект-зеркало. Ее можно получить, например, с помощью такой функции (попробуйте получить эту матрицу самостоятельно в качестве упражнения):

void reflectionmatrix(GLfloat reflection_matrix[4][4],

GLfloat plane_point[3],

Glfloat plane_normal[3])

{

GLfloat* p;

GLfloat* v;

float pv;

GLfloat* p = (Glfloat*)plane_point;

Glfloat* v = (Glfloat*)plane_normal;

float pv = p[0]*v[0]+p[1]*v[1]+p[2]*v[2];

reflection_matrix[0][0] = 1 - 2 * v[0] * v[0];

reflection_matrix[1][0] = - 2 * v[0] * v[1];

reflection_matrix[2][0] = - 2 * v[0] * v[2];

reflection_matrix[3][0] = 2 * pv * v[0];

reflection_matrix[0][1] = - 2 * v[0] * v[1];

reflection_matrix[1][1] = 1- 2 * v[1] * v[1];

reflection_matrix[2][1] = - 2 * v[1] * v[2];

reflection_matrix[3][1] = 2 * pv * v[1];

reflection_matrix[0][2] = - 2 * v[0] * v[2];

reflection_matrix[1][2] = - 2 * v[1] * v[2];

reflection_matrix[2][2] = 1 - 2 * v[2] * v[2];

reflection_matrix[3][2] = 2 * pv * v[2];

reflection_matrix[0][3] = 0;

reflection_matrix[1][3] = 0;

reflection_matrix[2][3] = 0;

reflection_matrix[3][3] = 1;

}

Настраиваем буфер маски на рисование только в областях, где значения буфера равно 1:

/* условие выполнено и тест дает истину только если значение в буфере маски равно 1 */

glStencilFunc (GL_EQUAL, 0x1, 0xffffffff);

/* ничего не меняем в буфере */

glStencilOp (GL_KEEP, GL_KEEP, GL_KEEP);

и рисуем сцену еще раз (без зеркальных объектов)

glPushMatrix();

glMultMatrixf((float *)reflection_matrix);

RenderScene();

glPopMatrix();

Наконец, отключаем маскирование

glDisable(GL_STENCIL_TEST);

После этого можно опционально еще раз вывести зеркальный объект, например, с альфа-смешением – для создания эффекта замутнения зеркала и т.д.

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

Программный код отвечающий за отрисовку данного изображения:

void reflection(void)

{

glMatrixMode(GL_PROJECTION);

glPushMatrix();

/* вызов видового преобразования */

glTranslatef(0.f, 0.f, -viewdist);

glRotatef(viewangle, 1.f, 0.f, 0.f);

/* отражение от плоскости XZ*/

glScalef(1.0, -1.0, 1.0);

/*отмена видового преобразования */

glRotatef(-viewangle, 1.f, 0.f, 0.f);

glTranslatef(0.f, 0.f, viewdist);

glMatrixMode(GL_MODELVIEW);

glCullFace(GL_FRONT); // отсекаем лицевые грани

draw();

drawLeftWall(1.0f);

glCullFace(GL_BACK);

glMatrixMode(GL_PROJECTION);

glPopMatrix();

glMatrixMode(GL_MODELVIEW);

}

glClear(GL_COLOR_BUFFER_BIT|GL_DEPTH_BUFFER_BIT|GL_STENCIL_BUFFER_BIT);

if(isFog)

drawFog();

//==1== подготовка буфера трафарета для вывода отражения

// не изменять цвет или значение в Z-буфере. изменять stencil

// этот проход только для буфера трафарета : в результате получим

// единицу в буфере трафарета для всех точек "пола"

glDisable(GL_DEPTH_TEST);

glColorMask(GL_FALSE, GL_FALSE, GL_FALSE, GL_FALSE);

glEnable(GL_STENCIL_TEST);

glStencilOp(GL_REPLACE, GL_REPLACE, GL_REPLACE);

glStencilFunc(GL_ALWAYS, 1, 0xffffffff);

drawfloor(1.f); /* рисуем пол для установки битов stencil буфера */

/*

* возвратить буфера цвета и глубины назад, установить функцию stencil буфера

* на пропускание, если установлены stencil значения, затем рисуем отражение */

// разрешить цвет и Z-буфер

glColorMask(GL_TRUE,GL_TRUE,GL_TRUE,GL_TRUE);

glEnable(GL_DEPTH_TEST);

// и рендерим только туда, где stencil=1

//(тест дает истину только если значение в буфере трафарета равно 1)

glStencilFunc(GL_EQUAL, 1, 0xffffffff);

/* ничего не меняем в буфере */

glStencilOp(GL_KEEP, GL_KEEP, GL_KEEP);

if(isReflection || isMultiReflection)

reflection(); /* рисуем отражение */

/* отключаем stencil тест */

glDisable(GL_STENCIL_TEST);

draw(); /* draw the unreflected scene */

glEnable(GL_BLEND);

glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);

drawfloor(0.8f); /* blend the floor in with the reflection */

drawLeftWall(0.8f);

glDisable(GL_BLEND);

glDisable(GL_FOG);

if(dblbuf)

glutSwapBuffers();

else

glFlush();

CHECK_ERROR("redraw()");

}

В результате выполнения данного примера представлена техника отражения без использования текстур

Соседние файлы в предмете Компьютерная Графика