Визуализация неба и облаков.
Двухмерное моделирование облаков. Использование
Perlin Noise.
Использование Perlin Noise для моделирования
облаков является наиболее распространенным способом из-за его простоты и
достаточной степени реалистичности для ряда приложений.
Вообще говоря, облачная поверхность обладает неравномерной структурой, но и
не совсем хаотической. Отсюда, для формирования облаков необходима некая
хаотическая функция, ядро которой подчиняется некоторому определенному закону.
Этим условиям вполне удовлетворяют функции Perlin Noise,
которые есть суть комбинация шумовой функции и интерполяционной функции.
Аргументами для шумовой функции выступают целые числа (integer).
В результате последовательного применения этих двух функций получается, как
показано на рисунках, функция, обладающая гладкостью и в тоже время обладающая
достаточной степенью хаотичностью.
Основными величинами здесь являются амплитуда (amplitude)
и частота (frequency). Амплитуда отвечает
за высоту волну, частота равна обратному от длины волны, длина волны - это, по
отношению к шумовой функции, расстояние от одной красной точки до другой.
Но если фиксировать амплитуду и частоту, то
получаемая функция все еще обладает достаточной степенью равномерностью. Решение
следующее: мы строим несколько функций с различными амплитудами и частотами, а
затем складываем их. Получаемая в результате функция как раз удовлетворяет всем
необходимым условиям (см. рис.).
исходные функции |
|
|
|
|
|
|
суммарная функция |
|
Амплитуду и частоту на каждом шаге изменяют по следующему
закону:
frequency = 2i
amplitude = persistencei
изображения с фиксированными амплитудой
и частотой |
|
|
|
|
|
|
суммарное изображение |
|
Реализация.
Ядром здесь служит шумовая функция. Ее можно определить,
например, следующим образом:
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
|
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
|
Изменение облачности.
Интерактивное изменение облачности существенно повышает степень применимости
приложения. Изменение облачности в реальном времени позволяет более точно
определить возможности программы, а также отразить эффект влияния облаков на
повышение реалистичности сцены как целого.
Если для моделирования облаков мы использовали 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 балла |
|