Введение в компьютерную графику
Полугодовой курс ВМиК МГУ, 2002
     

Задание №5. Визуализация природных явлений.

 

Начало: 17 апреля 2002 года.
Конец: 2 мая 2002 года (23:59)

Автор задания:
Александр Мальковский

Версия для печати здесь (zipped doc - 140кб)

 

Визуализация воды.

Моделирование водных поверхностей является сложной, но интересной задачей. Здесь можно выделить такие подзадачи, как моделирование небольших водоемов (с видимыми границами), для которых характерны небольшие изменения поверхности, то есть небольшие колебания, а также интерференция колебаний от нескольких всплесков и отраженных колебаний от границ; большие водные поверхности: здесь рассматривают небольшие поверхностные колебания (как правило, в этом случае можно обойтись изменениями лишь текстуры или нескольких текстур поверхности (Bump Mapping и др., см. далее) не деформируя непосредственно саму поверхность), небольшие колебания: в этом случае поверхность разбивается на треугольники, но достаточно большого размера и над поверхностью производят небольшие колебания, которые соответствуют, например, небольшим волнам, большие колебания: этот большие волны, брызги и др., здесь происходят значительные деформации водных поверхностей, которые достаточно сложно физически описываются, поэтому большие волны практически никогда не визуализируются. Брызги можно визуализировать, например, используя массив частиц (маленьких плоскостей, ориентированных по нормали на наблюдателя), для которых устанавливаются начальные скорости, а дальнейший их полет происходит по гравитационному закону.

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

Моделирование небольшие водных поверхностей.

 

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

Для каждого узла вводятся следующие характеристики:

mi - масса узла;

 - декартовы координаты узла;

 - скорость узла;

 - ускорение узла;

 - сумма всех сил, действующих на узел;

Выводить на экран такую поверхность можно следующим образом: для каждых четырех узлов: pij pi+1j pi+1j+1 pij+1 на экран выводятся 2 треугольника: pijpi+1jpij+1 и pij+1pi+1jpi+1j+1.

Выражение для силы пружины Sk, действующей на узел pi, следует из закона Гука:

(1)

где ,  - длина покоя и текущая длина пружины соответственно;  - единичный вектор в направлении пружины.

Или, если расписать:

(1)'

Уравнения движения всей такой системы легко выводятся из общего курса физики:

 - масса узла;
- сумма сил пружин, прикрепленных к узлу;
 - сумма внешних сил, приложенных к узлу;
 - коэффициент демпфирования, характеризующий сопротивление среды, в которой движется узел.

Неплохие результаты дают следующие характеристики системы:

Шаг сетки,

H

Масса узла,

mij

Коэффициент упругости,

ск

Демпфирование,

Шаг интегрирования,

1.0

4.0

7.0

0.05

0.4

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

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

Если запретить горизонтальные перемещения на все узлы, то это подчеркнет эффект прохождения волн друг сквозь друга. Также если запретить перемещения некоторых внутренних узлов, то можно смоделировать, например, островок, от которого волны будут также еще и отражаться. В данном случае узлы должны повторять контур островка.

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

Отражения.

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

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

Обычно, водные поверхности моделируются на открытом пространстве. И здесь необходимо учитывать эффект отражения неба от поверхности воды. Для этого берется текстура неба и накладывается на поверхность воды, но координаты текстуры не изменяются в зависимости от изменения водной поверхности. В OpenGL это достигается следующим образом:

Прозрачность и преломление.

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

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

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

Bump mapping.

Bump mapping используется для передачи неровностей поверхности. Реально в природе не существует абсолютно плоских объектов, и большинство объектов, которые мы видим в реальной жизни обладают различными шероховатостями. В моделировании при передаче общей формы объекта мы разбиваем его на полигоны. Но для передачи таких "мелких" свойств, как неровности необходимо модифицировать текстуру объекта или накладывать на одну плоскость несколько текстур (делать несколько полупрозрачных плоскостей, параллельных данной, но находящихся "немного выше" нее или использовать мультитекстурирование, входящие в расширение OpenGL).

Условно говоря, нам необходимо лишь менять направление нормали в каждой точке плоскости для передачи неровностей, и это возможно, используя расширения OpenGL. Но мы будем рассматривать лишь стандарт OpenGL. Здесь подобного можно добиться, если выводить вместо каждой плоскости, для которой мы хотим произвести bump mapping, три плоскости, параллельные друг другу и находящиеся на небольшом отдалении друг от друга (чтобы визуально этого было не заметно).

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

Сначала мы загружаем исходную текстуру воды (1), а из карты поверхности создаем две текстуры: первая (2)- точно такая же, но в каждой точке значение делиться на два (так как текстура черно-белая, то будем считать что мы уменьшаем яркость в два раза); вторая (3)- это инвертированная (по значению яркости) карта поверхности, для которой также значение яркости делится на 2, то есть здесь: <source_pixel> = (255 - <map_pixel>) / 2.

Вывод на экран происходит в следующей последовательности: сначала выводится текстура (2), перед этим в OpenGL должны быть установлены следующие параметры:

Перед выводом следующей плоскости устанавливаются следующие параметры:

Сама плоскость выводится выводится на том же месте, что и предыдущая, но "чуть-чуть" приподнята относительно вектора наблюдения (чтобы не было перекрытий) и наложенной текстурой (3). Для нее изменяются координаты текстурами, чтобы отобразить эффект неровности поверхности. Пересчет текстурных координат происходит относительно вектора наблюдения. То есть вызывается команда glTexCoord2f(old_tex_x + tex_dx, old_tex_y + tex_dy), tex_dx и tex_dy берутся при подсчете вектора свига: tex_d = {tex_dx, tex_dy, tex_dz}. Вычисляется он следующим образом: tex_d = man_pos - plane_center, где man_pos - вектор координат месторасположения наблюдателя, plane_center - центральная точка текущей плоскости (вместо нее, для ускорения, можно взять одну из вершин рассматриваемой плоскости). Далее tex_d нормируется (представляется в единичный вектор) и далее все координаты домножаются на некоторое небольшое число (в зависимости от глобальной метрики сцены), которое и будет характеризовать расхождение, а значит и высоту шероховатости. Если указать это число достаточно большим, то будут видны просто две плоскости и никакого эффекта шероховатости создаваться не будет. В этом особенность этого метода: можно передать лишь небольшие ("невысокие") неровности, для других необходимо производить дополнительную триангуляцию.

Перед выводом третей (последней плоскости) необходимо установить следующие параметры OpenGL:

Здесь также выводится плоскость, которая параллельна предыдущим, но "чуть-чуть" приподнята относительно них по вектору наблюдения, для избежания пересечений. На плоскость накладывается текстура (1), при этом координаты никак не пересчитываются (в отличии от предыдущей).

В итоге получается изображение, на котором виден "микрорельеф".

Расскажем теперь, как bump mapping применяется по отношению к моделированию водных поверхностей. Предположим, что необходимо моделировать большую водную поверхность, без видимых границ (граница - линия горизонта), на которой присутствуют лишь небольшие волны, то есть она достаточно "спокойна". Тогда можно не разбивать водную поверхность на множество плоскостей, а сделать одну большую плоскость, для которой применить bump mapping с динамически изменяемой картой поверхности. Обычно сразу загружается достаточное количество карт глубины (10-15), затем они меняют друг друга, в соответствие со временем изменения водной поверхности, а в конце происходит их зацикливание. Таким образом нам достаточно выводить только один полигон (то есть 3 - в нашей реализации bump mapping'а), а не разбивать поверхность на множество полигонов.

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

Оценка

Моделирование динамически изменяющейся водной поверхности 15 баллов
Интерактивное управление изменениями поверхности (добавить всплеск и др.) +4 балла
Отражения в водной поверхности +6 баллов
Реализация прозрачности и преломления в водной поверхности +4 балла
Перемещение наблюдателя по сцене +2 балла
Реализация каустиков и визуализация донных поверхностей +4 балла
Использование bump mapping'а для более точной передачи водной поверхности +5 баллов
Главная | О курсе | Лекции | Библиотека | Задания | Оценки | FAQs
  (с) Лаборатория компьютерной графики, 1997-2002
Дизайн: Алексей Игнатенко