Смекни!
smekni.com

Генерация и построение изображений ландшафта в реальном времени (стр. 3 из 8)

здесь size - размер карты высот, distance - расстояние, theta - угол. Помните - радиус должен быть меньше половины размера карты высот.

Поработав с этими величинами, мы можем получить довольно прилично выглядящий остров:

Вот мы и рассмотрели некоторые алгоритмы построения карт высот для ландшафтов. Рассмотрим еще некоторые сопутствующие операции:

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

· Превращение гористой местности в холмистую. Я их различаю по очертанию вертикальных разрезов у вторых более пологие края.

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

Полный алгоритм генерации карты высот

publicvoid GenerateHeightmap(int SizeX, int SizeY, GenMethod LandGenMethod, Convolution[] Convs, bool Smoothing, bool Valley, bool Island)

{

this.SizeX = SizeX;

this.SizeY = SizeY;

Heightmap = newdouble[SizeX, SizeY];

PerlinNoise Noise = newPerlinNoise(256);

double min = 99999;

double max = -99999;

double[,] ar = newdouble[SizeX, SizeY];

if (LandGenMethod == GenMethod.Perlin)

{

for (int i = 0; i < SizeX; i++)

for (int j = 0; j < SizeY; j++)

{

for (int l = 0; l < Convs.Length; l++)

{

if (Convs[l].Operation == Operation.Plus)

if (Convs[l].Coef != 0)

ar[i, j] += Noise.Generate(i, j, Convs[l].Coef);

else

if (Convs[l].Coef != 0)

ar[i, j] *= Noise.Generate(i, j, Convs[l].Coef);

}

if (max < ar[i, j]) max = ar[i, j];

if (min > ar[i, j]) min = ar[i, j];

}

}

else

{

Random rand = newRandom();

double theta;

double distanceX, distanceY;

double Radius;

double x, y;

double t;

min = 0;

for (int k = 0; k < Convs[0].Coef; k++)

{

Radius = rand.NextDouble() * (SizeX * Convs[1].Coef);

if (Island)

{

theta = rand.NextDouble() * Math.PI * 2;

t = rand.NextDouble();

distanceX = t * (SizeX * Convs[2].Coef - Radius);

distanceY = t * (SizeY * Convs[2].Coef - Radius);

x = SizeX / 2.0 + Math.Cos(theta) * distanceX;

y = SizeY / 2.0 + Math.Sin(theta) * distanceY;

}

else

{

x = SizeX * rand.NextDouble();

y = SizeY * rand.NextDouble();

}

for (int i = 0; i < SizeX; i++)

for (int j = 0; j < SizeY; j++)

{

t = Radius * Radius - ((i - x) * (i - x) + (j - y) * (j - y));

if (t > 0)

ar[i, j] += t;

if (max < ar[i, j]) max = ar[i, j];

//if (min > ar[i, j]) min = ar[i, j];

}

}

}

double coef = 1 / ((max - min));

for (int i = 1; i < SizeX-1; i++)

for (int j = 1; j < SizeY-1; j++)

{

if (Smoothing)

Heightmap[i, j] = (ar[i - 1, j - 1] + ar[i - 1, j] + ar[i - 1, j + 1] +

ar[i , j - 1] + ar[i , j] + ar[i , j + 1] +

ar[i + 1, j - 1] + ar[i + 1, j] + ar[i + 1, j + 1] - 9.0*min) / (9.0*(max-min));

else

Heightmap[i, j] = (ar[i, j] - min) * coef;

if (Valley)

Heightmap[i, j] = Math.Sqrt(Heightmap[i, j]);

}

Алгоритмы визуализации ландшафта и окружающей среды

Использование карт освещения

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

Сейчас под картами освещения чаще всего подразумевают одну из их разновидностей – текстурные карты освещения. Они представляют собой изображения, накладываемые при рисовании «поверх» основных текстур; при этом яркость точки на карте освещения используется для модуляции яркости точки основной текстуры. Этот процесс продемонстрирован на рисунке:

Наложение карт освещения

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

Часть набора карт освещения для небольшой сцены

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

Вычисление результирующего цвета

R = Rтекст Rосв

G = Gтекст Gосв

B = Bтекст Bосв

Где значение компонентов цвета лежат в диапазоне [0, 1].

Проверка: если карта освещенности будет полностью белой, то результирующая текстура будет такой же, как и основная текстура (компоненты везде домножаются на 1, т.к. белый цвет это R = 1, G = 1, B = 1)

если карта освещенности будет полностью черной, то результирующая текстура тоже черной (компоненты везде домножаются на 0, т.к. черный цвет это R = 0, G = 0, B = 0), что соответствует отсутствие источников освещения).

Создание карт освещения будет рассмотрено позже

Наложение текстур

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

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

В аффинном текстурировании (affinemapping) используется линейная интерполяция:



, где u0 и u1 – значения текстурной координаты U, заданные на концах некоторого отрезка, и . Точно такая же формула используется для координаты V.

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


Перспективно-корректное текстурирование, как следует ожидать из названия, дает корректные результаты для произвольных граней благодаря дополнительной интерполяции глубины точек:

,
где z0, z1 – глубины концов отрезка, на котором проводится интерполяция.


Рис. Сравнение методов текстурирования

Все современные видеоадаптеры используют перспективно-корректное текстурирование.

Смешивание текстур

Смешивание с учетом цвета:

Смешивание без учета текстуры:

Прозрачность реализуется с помощью специального режима смешения цветов (blending). Алгоритм смешения комбинирует цвета так называемых входящих пикселей (т.е. «кандидатов» на помещение в буфер кадра) с цветами соответствующих пикселей, уже хранящихся в буфере. Для смешения используется четвертая компонента цвета – альфа-компонента, поэтому этот режим называют еще альфа-смешиванием. Программа может управлять интенсивностью альфа-компоненты точно так же, как и интенсивностью основных цветов, т.е. задавать значение интенсивности для каждого пикселя или каждой вершины примитива.

Расчет результирующего цвета каждого пикселя:

res=сsrc*k1+cdst*k2

Параметр src определяет, как получить коэффициент k1 исходного цвета пикселя, a dst задает способ получения коэффициента k2 для цвета в буфере кадра. Для получения результирующего цвета используется следующая формула:, где сsrc – цвет исходного пикселя, cdst – цвет пикселя в буфере кадра (res, k1, k1, сsrc, cdst – четырехкомпонентные RGBA-векторы).

Приведем наиболее часто используемые значения аргументов src и dst.

SRC_ALPHA k=(As,As,As,As)
SRC_ONE_MINUS_ALPHA k=(1,1,1,1)-(As,As,As,As)
DST_COLOR k=(Rd,Gd,Bd)
ONE_MINUS_DST_COLOR k=(1,1,1,1)- (Rd,Gd,Bdd)
DST_ALPHA k=(Ad,Ad,Ad,Ad)
DST_ONE_MINUS_ALPHA k=(1,1,1,1)-(Ad,Ad,Ad,Ad)
SRC_COLOR k=(Rs,Gs,Bs)
ONE_MINUS_SRC_COLOR k=(1,1,1,1)- (Rs,Gs,Bs,As)

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

Все прозрачные объекты выводятся после непрозрачных.

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

В нашем программном комплексе коэффициент ALPHA для воды = 0.45

А режим смешения SRC_ONE_MINUS_ALPHA