ПрограммированиеСтатьи

Создание ландшафта с помощью задания экстремумов. (2 стр)

Создание ландшафта

Здесь я буду описывать функцию которая создает ландшафт:

void CreateLandscape(_Landscape obj) // obj - заданный ландшафт

В начале надо создать и заполнить двумерный массив вершин:

Vertex3f VerMesh[map_size][map_size]; // map_size - кол-во вершин ландшафта

Каждая вершина помимо своей высоты расположения (y), будет иметь еще и позицию по x,z. При использовании карты высот также создается двумерный массив, но обычно каждый элемент массива это лишь параметр указывающий высоту, т.к. позиция этой вершины определена ее порядковым номером в массиве. Так полигоны, которые создаются на основе этих вершин, расположены по x,z в строгом порядке и не могут располагаться друг над другом. В моем же примере вполне возможно, что полигоны ландшафта могут находиться друг над другом (к примеру: гора нависающая над какой-то частью ландшафта), поэтому задается полное расположение вершины в трехмерном пространстве.

После указываются начальные координаты каждой вершины. Высота каждой из них равна 0 (Y=0).

// Задание позиций вершинам
int x, y;
for (y=0; y<map_size; y++)
for (x=0; x<map_size; x++)
{
	VerMesh[x][y].y = 0;
	VerMesh[x][y].x = x*obj.Len; // obj.Len - Расстояние между соседними вершинами
	VerMesh[x][y].z = y*obj.Len; 
}

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

расстояние=корень(квадрат(вершина.x-экстремум.x)+квадрат(вершина.z-экстремум.z))

Length = sqrt( sqr(VerMesh[x][y].x - obj.ext[n].hVer.x) +
              sqr(VerMesh[x][y].z - obj.ext[n].hVer.z)

x,y - порядковый номер вершины
obj.ext[n].hVer - это позиция экстремума, n - номер экстремума(т.к. их может быть много)

Высота экстремума:

Height = obj.ext[n].hVer.y

Изображение

Полученное расстояние надо сравнить с "радиусом распространения" экстремума, если расстояние от экстремума до точки будет меньше, то данная точка должна будет подняться на определенную высоту в зависимости от близости расположения к экстремуму. Гора строится с помощью использования графика косинуса (cos). Наивысшая точка (экстремум) достигается умножением (Cos(0)+1) на высоту расположения экстремума, а точка самого начала (подножия горы) умножением на (Cos(pi)+1), т.е.

(Cos(Rad)+1)*Height,
где Rad - угол, а Height - высота расположения экстремума. Если расстояние от экстремума до вершины равно 0, то Rad так же равен 0, если же оно равно Radius("радиусу распространения") данного экстремума, то Rad = pi. Из этого следует, что
Rad = Length/Radius*pi.

Общая формула высоты, на которую надо поднять точку:

dLen = (cos(pi*Length/Radius)+1)*Height.

Получившееся значение прибавляем к позиции точки по Y.

Изображение

Представьте, что у вас есть гора и вы хотите, чтобы она нависала над какой-то частью ландшафта. Для этого надо все точки, которые входят в образование горы сдвинуть в сторону "нависания", при этом, чем выше находится точка тем сильнее она должна быть сдвинута, и наоборот чем ближе она находится к 0-му уровню ландшафта тем меньше она сдвигается. Все это делается следующим простым способом. К позициям точки по X,Z прибавляем значение сдвига dx, dz, которые находятся путем умножения высоты поднятия точки на коэффициент сдвига:

dx = dLen*dX, dz = dLen*dZ,
dX, dZ - коэффициенты сдвига, задающиеся вместе с экстремумами(obj.ext[n].dx, obj.ext[n].dz).

Изображение

Ниже приводится часть кода, которая реализует все это.

double Length, dLen;
for (y=0; y<map_size; y++)
for (x=0; x<map_size; x++)
{
	// обходим все экстремумы
	for (int n=0; n<obj.nExt; n++)
	{
		Length=sqrt( sqr(VerMesh[x][y].x-obj.ext[n].hVer.x) + sqr(VerMesh[x][y].z-obj.ext[n].hVer.z);
		if (Length<obj.ext[n].Radius)
		{
			dLen = (float)(cos(pi*Length/obj.ext[n].Radius)+1)*obj.ext[n].hVer.y;
			VerMesh[x][y].y += dLen;
			VerMesh[x][y].x += dLen*obj.ext[n].dx;
			VerMesh[x][y].z += dLen*obj.ext[n].dz;
		}
	}
}

И самое последнее, что надо сделать, это переместить ландшафт на расстояние, которое задается до его создания (obj.Pos). Для этого сдвигаются все точки ландшафта.

// Перемещение вершин ландшафта
for (y=0; y<map_size; y++)
for (x=0; x<map_size; x++)
{
	VerMesh[x][y].x += obj.Pos.x;
	VerMesh[x][y].y += obj.Pos.y;
	VerMesh[x][y].z += obj.Pos.z;
} 

Вот и все, что я хотел рассказать. Ниже приводиться еще одна часть кода вывода ландшафта.

#define Vertex( xv,yv, xTex, yTex) \
glTexCoord2f(xTex, yTex); \
glVertex3f(VerMesh[x+xv][y+yv].x, VerMesh[x+xv][y+yv].y, VerMesh[x+xv][y+yv].z)

// ...

float TextureSize = 1.0f/map_size;
glBegin(GL_TRIANGLES); 
for (int y=0; y<map_size-1; y++)
for (int x=0; x<map_size-1; x++)
{ 
	Vertex(0,0, x*TextureSize, y*TextureSize);
	Vertex(1,0, (x+1)*TextureSize, y*TextureSize);
	Vertex(1,1, (x+1)*TextureSize, (y+1)*TextureSize);

	Vertex(0,0, x*TextureSize, y*TextureSize);
	Vertex(1,1, (x+1)*TextureSize, (y+1)*TextureSize);
	Vertex(0,1, x*TextureSize, (y+1)*TextureSize);
}
glEnd();

Исходный код примера : [gurl=http://www.gamedev.ru/articles/graph/20030519.zip]20030519.zip[/url]

Страницы: 1 2

19 мая 2003