здесь 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) используется линейная интерполяция:
Этот метод работает быстро, но дает некорректные результаты для граней, расположенных под углом к экрану, так как при интерполяции не учитываются значения глубины точек.
,
где 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,Bd,Аd) |
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