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

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

 

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

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

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

 

Визуализация неба и облаков.

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

 

Здесь имеется в виду раскраска неба в зависимости от времени суток, времени года, положения солнца относительно положения наблюдателя и др. Реально применимым является следующий подход: заранее на этапе препроцессинга просчитываются (используя ray-tracing или radiosity ) текстуры для неба (как правило они большого размера - для обеспечения высокой реалистичности) с дискретностью, например, в 1 час и сохраняются на жестком диске. В реальном времени происходит лишь наложение части такое текстуры (в зависимости от положения наблюдателя и "просматриваемой" части неба) и последовательное морфирование ее в следующую текстуру (например, с помощью мультитекстурирования, которое поддерживается средствами OpenGL как extension).

Подробно с такими алгоритмами можно ознакомиться в разделе физики "Оптика атмосферы".

Такой точности, конечно, не требуется. Так как основное задание состоит в моделирование и визуализации облаков, то на раскраске неба можно не останавливаться подробно. Достаточно сделать его цвет однородным - как некий средний цвет (например, "небесно-голубой": R=0.196078, G=0.6, B=0.8), или изменять цвет линейно как градиент к линии горизонта.

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

Остановимся более подробно на моделировании и визуализации облаков. Здесь рассматривают два вида алгоритмов. Первые рассматривают облака как двумерную текстуру, сформированную особым образом. Наиболее распространенным здесь является использование "шумовых" функций, например, "Perlin noise". На таких алгоритмах работают, такие приложения для генерации ландшафтов, как TerraGen, а также практически все игровые приложения, в которых предпринимаются попытки хоть как то отобразить небо. Алгоритмы второго типа рассматривают облака как некоторую трехмерную структуру, которая подчиняется физическим законам, связанными с ее изменениями в результате движения, преобразования пара в воду, а также по раскраске облаков в результате рассеивания солнечного света в их структуре.

Двухмерное моделирование облаков. Использование Perlin Noise.

Использование Perlin Noise для моделирования облаков является наиболее распространенным способом из-за его простоты и достаточной степени реалистичности для ряда приложений.

Вообще говоря, облачная поверхность обладает неравномерной структурой, но и не совсем хаотической. Отсюда, для формирования облаков необходима некая хаотическая функция, ядро которой подчиняется некоторому определенному закону. Этим условиям вполне удовлетворяют функции Perlin Noise, которые есть суть комбинация шумовой функции и интерполяционной функции. Аргументами для шумовой функции выступают целые числа (integer).

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

Основными величинами здесь являются амплитуда (amplitude) и частота (frequency). Амплитуда отвечает за высоту волну, частота равна обратному от длины волны, длина волны - это, по отношению к шумовой функции, расстояние от одной красной точки до другой.

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

исходные функции

суммарная функция

Амплитуду и частоту на каждом шаге изменяют по следующему закону:

frequency = 2i
amplitude = persistencei

где i - номер генерируемой функции. Величина persistence специально введена для обеспечения зависимости амплитуды от частоты.

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

суммарное изображение

 

Октавой (octave) называется каждая сгенерированная и добавленная в суммарный поток функция. Количество октав, также, является основной величиной в данном процессе и влияет на качество изображения.

Реализация.

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

  function IntNoise(32-bit integer: x)      

    x = (x<<13) ^ x;
    return ( 1.0 - ( (x * (x * x * 15731 + 789221) + 1376312589) & 7fffffff) / 1073741824.0);    

  end IntNoise function

Здесь на вход подается целое число, а на выходе получается дробное число между -1.0 и 1.0.

Далее используется интерполяция. Здесь, также, возможны некоторые варианты:

Линейная интерполяция:

function Linear_Interpolate(a, b, x)
    return  a*(1-x) + b*x
end of function
Это самый простой способ интерполяции: самый быстрый, зато обладает плохой точностью.

Косинусная интерполяция:

function Cosine_Interpolate(a, b, x)
    ft = x * 3.1415927
    f = (1 - cos(ft)) * .5
    return  a*(1-f) + b*f
end of function

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

Кубическая интерполяция:

function Cubic_Interpolate(v0, v1, v2, v3,x)
    P = (v3 - v2) - (v0 - v1)
    Q = (v0 - v1) - P
    R = v2 - v0
    S = v1
    return Px3 + Qx2 + Rx + S
  end of function
Это более точный метод, чем косинусная интерполяция, но более медленный, за счет использования большого количества умножений. Как правило, достаточно использовать линейную или косинусную интерполяцию.

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

  function Noise(x, y)
    .
    .
  end function

  function SmoothNoise_2D(x>, y)
    
    corners = ( Noise(x-1, y-1)+Noise(x+1, y-1)+Noise(x-1, y+1)+Noise(x+1, y+1) ) / 16
    sides   = ( Noise(x-1, y)  +Noise(x+1, y)  +Noise(x, y-1)  +Noise(x, y+1) ) /  8
    center  =  Noise(x, y) / 4

    return corners + sides + center


  end function

Исходя из всех условий и преобразований в результате получим следующий алгоритм получения двумерной картинки с использованием функций Perlin Noise:

  function Noise(integer x, integer y)
    n = x + y * 57;
    n = (n << 13) ^ n;
    return (1.0 - ((n * (n * n * 15731 + 789221) + 1376312589) & 7fffffff) / 1073741824.0);    
  end function

  function SmoothNoise(float x, float y)
    corners = (Noise(x-1, y-1) + Noise(x+1, y-1) + Noise(x-1, y+1) + Noise(x+1, y+1)) / 16
    sides   = (Noise(x-1, y) + Noise(x+1, y) + Noise(x, y-1) + Noise(x, y+1)) /  8
    center  =  Noise(x, y) / 4
    return corners + sides + center
  end function

  function InterpolatedNoise(float x, float y)

      integer_X    = int(x)
      fractional_X = x - integer_X

      integer_Y    = int(y)
      fractional_Y = y - integer_Y

      v1 = SmoothedNoise(integer_X,     integer_Y)
      v2 = SmoothedNoise(integer_X + 1, integer_Y)
      v3 = SmoothedNoise(integer_X,     integer_Y + 1)
      v4 = SmoothedNoise(integer_X + 1, integer_Y + 1)

      i1 = Interpolate(v1 , v2 , fractional_X)
      i2 = Interpolate(v3 , v4 , fractional_X)

      return Interpolate(i1 , i2 , fractional_Y)

  end function

  function PerlinNoise_2D(float x, float y)

      total = 0
      p = persistence
      n = Number_Of_Octaves - 1

      loop i from 0 to n

          frequency = 2i
          amplitude = pi

          total = total + InterpolatedNoise(x * frequency, y * frequency) * amplitude

      end of i loop

      return total

  end function

Вместо функции Interpolate обычно выбирается функция либо линейной, либо косинусной интерполяции.

Изменение облачности.

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

Если для моделирования облаков мы использовали Perlin noise, то для изменения облачности достаточно вычесть попиксельно некоторую константу (так как мы получаем в итоге работы алгоритма Perlin Noise карту интенсивностей) и сделать значения меньшие нуля равными нулю.

Трехмерное моделирование облаков. Использование клеточных автоматов.

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

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

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

Для каждого вокселя мы вводим три битовых (то есть, либо 0, либо 1) параметра, которые отражают его физическую природу как части облака:

hum - если равен 1, то это означает, что в данном вокселе собралось достаточно пара для формирования облака.

act - если равен 1, то это означает, что в данном вокселе началась фаза преобразования из пара в воду (то есть, в облако).

cld - если равен 1, то это означает, что в данном вокселе существует облако.

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

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

Здесь i, j, k - координаты вокселя в введенной нами сетке, ti - момент времени. То есть, если у нас уже есть какая-то воксельная модель облаков в момент времени ti, то мы по этим формулам рассчитываем, какую форму она примет в момент времени ti+1. Но одних этих формул недостаточно, так как они формируют лишь в определенном смысле стационарную модель и никак не влияют на зарождение и угасание облаков. Вводятся дополнительные формулы:

Здесь, pext - пороговое значение, влияющее на угасание облаков; phum - пороговое значение, влияющее на изменени влажности; pact - пороговое значение, влияющее на изменение активности.

Для моделирования воздействия ветра можно применять, например, следующие формулы:

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

Гораздо более простым решением является использование Perlin Noise текстуры как карты высот для облачной поверхности. Построение Perlin Noise текстуры описывалось выше. В результате мы получаем черно-белую текстуру, где на каждый пиксель приходится сколько-нибудь градаций (например, если сохранять как обычную картинку, то 256). Далее, мы строим трехмерную сетку, длина и ширина которой совпадают с параметрами текстуры, и высотой, например, N. В каждом вокселе облако либо есть, либо его нет. Далее, для мы берем столбцы вокселей с координатами i, j в сетке и для каждого столбца проставляем проставляем присутствие облака в клетках со следующими координатами:

N/2 - noise_intens*N/256 - Random(rand_param) < h < N/2 + noise_intens*N/256 + Random(rand_param)

где: noise_intens - цвет Perlin Noise текстуры (сохраненной в 256 градациях серого);

 rand_param - вводится для того чтобы модель получалась не совсем симметричной, обычно равен небольшому целому числу, например, 3 или 4.

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

Трехмерная сетка не должна быть большой, потому как может так случится, что нам придется выводить все <width>*<length>*<height> полигонов.

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

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

Shafts of light.

Вообще говоря, облака, как твердые объекты отбрасывают тень на землю. Тем самым создается такой эффект как "Shafts of light" - совокупность лучей света, образующие некие конические объекты, которые исходят из разрывов в облаках. С помощью этого эффекта существенно повышается реалистичность и "законченность" картинки.

Моделировать данный эффект можно следующим образом. Создается битовая карта небесной поверхности. Если использовалось двумерное моделирование облаков, то из полученной текстуры битовая карта получается следующим образом: черные пиксели (равные нулю) приравниваются к нулю, а все остальные - равными единицами. Если использовалось трехмерное моделирование, то битовая карта получается следующим образом: все столбцы "проецируются на горизонтальную плоскость" и если в столбце был хоть один воксель с установленным параметром присутствия облака, то пиксель в битовой карте с соответствующими координатами столбца будет равен 1, а если облака в данном столбце не нашлось, то равен 0. Далее проводятся конусы (для OpenGL - это те же цилиндры, только с разными радиусами) из условного положения источника света до некоторого уровня относительно поверхности земли (можно прорисовывать до земной поверхности, но это не слишком реалистично). Также не нужно выводить те части конусов, которые располагаются выше нижней границе облачной поверхности.

Оценка

Двухмерное моделирование облаков 10 баллов
Трехмерное моделирование облаков 15 баллов
Простейшая раскраска неба +3 балла
Движение облаков +2 балла
Изменение облаков в зависимости от времени +5 баллов
Зарождение и угасание облаков, по желанию пользователя. Изменение облачности. +3 балла
Моделирование "shafts of light" +7 баллов
Простейшая визуализация ландшафта, как земной поверхности +2 балла
Перемещение наблюдателя по сцене и корректировка в зависимости от этого изображения +2 балла
Реалистичность +3 балла

 

Главная | О курсе | Лекции | Библиотека | Задания | Оценки | FAQs
  (с) Лаборатория компьютерной графики, 1997-2002
Дизайн: Алексей Игнатенко