Генерация карты высот

от автора

В качестве языка программирования здесь используется C++, но перенести этот код на другой язык программирования будет не так уж сложно.
Код написанный ниже далёк от идеала, но новичкам он может пригодится.
Не так давно у меня была проблема с генерацией карты высот для ландшафта.

Я решил попробовать задать каждой точке случайное значение.


Вот пример кода для двухмерного массива данных.

for(int i=0;i<World::size;i++) { 	for(int u=0;u<World::size;u++) 	{                 //Задаётся зерно для генерации случайных чисел 		srand(GetTickCount()*i*u);                                            //Задаются случайные значения всем точкам от 0*0.1-10, до 100*0.1-10 		World::data[i][u]=(rand()%100)*0.1f-10.0f;                             	} } 

Но такой результат мне не годился, и я решил добавить холмы и ямы.

Код с использованием функции Land_MakeHill(код которой находится ниже):

srand(GetTickCount()); for(int i=0;i<rand()%(World::size*World::size*1000);i++) { 		Land_MakeHill(World::data,                            //Карта высот                 rand()%(World::size),             //Координаты по X в пределах размера карты                 rand()%(World::size),             //Координаты по Y в пределах размера карты                 World::size,                              //Размер карты                 (rand()%20*1.0)+20)/100.0, //Высота холма                 rand()%14+14);                      //Радиус холма(в данном случае от 14 до 28 точек). } srand(GetTickCount()); for(int i=0;i<rand()%(World::size*World::size*1000);i++) { 	Land_MakeHill(World::data,                            //Карта высот         rand()%(World::size),               //Координаты по X в пределах размера карты         rand()%(World::size),               //Координаты по Y в пределах размера карты         World::size,                                //Размер карты          -(rand()%20*1.0)+20)/100.0, //Глубина ямы           rand()%4+7);                           //Радиус ямы(в данном случае от 7 до 11 точек). } 

Обратите внимание — отличие создания холма от ямы всего лишь высота. У ямы она меньше нуля, у холма больше.
Код функции Land_MakeHill:

/*data - указатель на массив,  px - координаты по x,  py - координаты по y,  size - размер карты, height - высота, Rad - радиус */ void Land_MakeHill(float** data,int px,int pz, int size,float height,int Rad ) { for(int i=0;i<size;i++){ for(int w=0;w<size;w++){ //Чем дальше точка от центра, тем меньше значение float d=Rad *Rad -((px-i)*(px-i)+(pz-w)*(pz-w));  data[i][w]+=d*height; } } } 

Такому ландшафту очень не хватает плавности, поэтому понадобилось сделать сглаживание.

Код функции Land_blur:

void Land_Blur(float** data,int size) { //Временный массив вершин float** oldData = new float*[size];     for (int i = 0; i < size; i++){ 	oldData[i] = new float[size]; } //Переносим значения из массива вершин во временный массив, чтобы для сглаживания не использовались уже сглаженные точки for(int i=0;i<size;i++){                          	for(int u=0;u<size;u++){ 		oldData[i][u]=data[i][u]; 	} } //Идём начиная со второй точки до предпоследней, чтобы у каждой точки было 8 точек вокруг. for(int i=1;i<size-1;i++){                    	for(int u=1;u<size-1;u++){ 		float v[9]; 			v[0]=data[i-1][u-1]; 			v[1]=data[i-1][u  ]; 			v[2]=data[i-1][u+1]; 			v[3]=data[i]  [u-1]; 			v[4]=data[i]  [u  ]; 			v[5]=data[i]  [u+1]; 			v[6]=data[i+1][u-1]; 			v[7]=data[i+1][u  ]; 			v[8]=data[i+1][u+1]; 		data[i][u]=(v[0]+v[1]+v[2]+v[3]+v[4]+v[5]+v[6]+v[7]+v[8])/9; 	} } } 

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

        //Задаём случайные значения для всех точек 	for(int i=0;i<World::size;i++) 	{ 		for(int u=0;u<World::size;u++) 		{ 			srand(GetTickCount()*i*u); 			World::data[i][u]=(rand()%1000)*0.1-100; 		} 	} 	srand(GetTickCount());         //Создаём холмы 	for(int i=0;i<rand()%(World::size*World::size*1000);i++) 	{                 //Эта функция идентична той, которая была разобрана ранее 		Land_MakeHill(World::data,rand()%(World::size*17),rand()%(World::size*17),World::size,((rand()%10*1.0)+10)/100.0,rand()%14+14); 	} 	srand(GetTickCount());         //Создаём ямы 	for(int i=0;i<rand()%(World::size*World::size*1000);i++) 	{                //Эта функция идентична той, которая была разобрана ранее 		Land_MakeHill(World::data,rand()%(World::size),rand()%(World::size),World::size,-((rand()%20*1.0)+20)/100.0,rand()%4+7); 	}         //Делаем сглаживание 3 раза подряд         for(int i=0;i<3;i++)  	Land_Blur(World::data,World::size); 

После этого я добавил ещё немного маленьких холмов и ещё раз сгладил карту.
Вот что получилось:

ссылка на оригинал статьи http://habrahabr.ru/post/183986/


Комментарии

Добавить комментарий

Ваш адрес email не будет опубликован. Обязательные поля помечены *