3d terrain generation

http://www.lighthouse3d.com/opengl/terrain/index.php3?heightmap

Terrain Tutorial


 

Height Maps From Images


Now that we know how to load an image lets see how to create and draw a height map. This section presents a set of functions from the terrain library that deal with height maps. First lets see how we can build a height map from an image.

There are several ways to interpret an image as an height map. If the image is greyscale the process is more or less straightforward, a pixels intensity corresponed to a height.

If the image is RGB then we can convert it to greyscale using the function tgaRGBtoGreyscale from the tgalib (see the tgalib section). Then we can use the Greyscale as before.

The other possible type is RGBA, in which case we can create a height map from the alpha channel, and use the RGB for the terrain colors.

Before presenting the functions lets take a look at the possible status returned:

  • TERRAIN_ERROR_LOADING_IMAGE - this value is returned when there is a problem loading the image.
  • TERRAIN_ERROR_MEMORY_PROBLEM - Oops, no memory to hold the terrain data
  • TERRAIN_ERROR_NOT_SAVED - There was a problem saving the file
  • TERRAIN_ERROR_NOT_INITIALISED - occurs when a function to act upon the terrain is called but there is no terrain!
  • TERRAIN_OK - This what we want, no errors!

We need some variables to hold the terrain data:

  • terrainGridWidth - the number of heights available on the x axis.
  • terrainGridLength - the number of heights available on the y axis.
  • terrainHeights - A one-dimensional array containing the heights
  • terrainColors - A one-dimensional array containing the RGB colors for each height
  • terrainNormals - A one-dimensional array containing the normals for each height

Note that the terrainColors and terrainNormals arrays contain 3 times the number of components of terrainHeights. This is because we don't store the location in the XZ plane of each height in the array.

The function to create the height map based on an image has the following signature:


int terrainLoadFromImage(char *filename, int normals);

Parameters:

filename - the name of the image file
normals - a non-zero value specifies that normals are to be calculated, zero means that we don't want normals


The value returned by this function indicates if the operation was successful or not. This function computes the heights as the pixels intensity scaled down to the interval [0,1]. The code that follows shows the steps required to create the height map. The image loading is performed by the tgalib presented in the previous sections.


    
int terrainLoadFromImage(char *filename, int normals) {

	tgaInfo *info;
	int mode,aux;
	float pointHeight;

	// if a terrain already exists, destroy it.
	if (terrainHeights != NULL)
		terrainDestroy();
		
	// load the image, using the tgalib
	info = tgaLoad(filename);
	
	// check to see if the image was properly loaded
	// remember: only greyscale, RGB or RGBA noncompressed images
	if (info->status != TGA_OK)
		return(info->status);

	// if the image is RGB, convert it to greyscale.
	// mode will store the image's number of components
	mode = info->pixelDepth / 8;
	if (mode == 3) {
		tgaRGBtoGreyscale(info);
		mode = 1;
	}
	
	// set the width and height of the terrain
	terrainGridWidth = info->width;
	terrainGridLength = info->height;

	// alocate memory for the terrain, and check for errors
	terrainHeights = (float *)malloc(terrainGridWidth * 
					terrainGridLength * 
					sizeof(float));
	if (terrainHeights == NULL)
		return(TERRAIN_ERROR_MEMORY_PROBLEM);

	// allocate memory for the normals, and check for errors
	if (normals) {
		terrainNormals = (float *)malloc(terrainGridWidth * 
						terrainGridLength * 
						sizeof(float) * 3);
		if (terrainNormals == NULL)
			return(TERRAIN_ERROR_MEMORY_PROBLEM);
	}
	else
			terrainNormals = NULL;

	// if mode = RGBA then allocate memory for colors, and check for errors
	if (mode == 4) {
		terrainColors = (float *)malloc(terrainGridWidth * 
						terrainGridLength * 
						sizeof(float)*3);
		if (terrainColors == NULL)
			return(TERRAIN_ERROR_MEMORY_PROBLEM);
	}
	else
		terrainColors = NULL;

	// fill arrays
	for (int i = 0 ; i < terrainGridLength; i++)
		for (int j = 0;j < terrainGridWidth; j++) {
		
			// compute the height as a value between 0.0 and 1.0
			aux = mode*(i*terrainGridWidth + j)
			pointHeight = info->imageData[aux+(mode-1)] / 256.0;
			terrainHeights[i*terrainGridWidth + j] = pointHeight;
			
			// if mode = RGBA then fill the colors array as well
			if (mode==4) {
				terrainColors[3*(i*terrainGridWidth + j)] =
				 	info->imageData[aux] / 256.0;
				terrainColors[3*(i*terrainGridWidth + j)+1] =
				 	info->imageData[aux+1]/256.0;
				terrainColors[3*(i*terrainGridWidth + j)+2] = 
					info->imageData[aux+2]/256.0;
			}
		}
	// if we want normals then compute them		
	if (normals)
		terrainComputeNormals();
		
	// free the image's memory 
	tgaDestroy(info);
	
	return(TERRAIN_OK); 
}



The normals computation will be dealt in future sections.

Before going into the rendering function lets take a look at two other functions to scale the terrain. The first one scales the heights of the terrain. As mentioned before when creating a height map from an image, the heights are in the interval [0,1]. In the general case we'll probably want to specify the minimum and maximum heights. The terrain lib provides a function to this end with the following syntax:


int terrainScale(float min,float max);

Parameters:

min - the minimum height
max - the maximum height


This functions rescales all the heights to fit in the interval [min, max]. There is only one detail which is worth pointing out in this function: if using normals it is necessary to rescale them. This is because the scale applied is not uniform, i.e., it is not equal for all the axes, and therefore the normals previously computed are no longer correct. The function will recompute the normals after scaling the terrain.

The other scaling function defines the interval between two adjacent grid points. By default the distance is 1.0.


int terrainDim(float stepWidth, float stepLength);

Parameters:

stepWidth - the x distance between two grid points
stepLength - the z distance between two grid points


 

So now that we have a terrain, lets render it! The terrain library creates a display list using triangle strips for the height map. This function takes 3 parameters, which represent the origin of the terrain. If all parameters are zero then the terrain will be created at the local origin. Otherwise we can use these parameters to place the terrain in any position.

This function looks at the normals array to decide if using materials or just glColor3f. Therefore, normals should not be required when creating the height map if the application is not going to use lighting, otherwise the colors will be lost. Similarly strange results may occur if lighting is enabled in the application but the normals are not computed.

The syntax of the rendering function is as follows:


int terrainCreateDL(float xOffset, float yOffset, float zOffset);

Parameters:

xOffset - specifies the center of the terrain on the x direction
yOffset - specifies the y value of the points with zero height


Next the code of the function is presented.


    
int terrainCreateDL(float xOffset, float yOffset, float zOffset) {

	GLuint terrainDL;
	float startW,startL;
	int i,j,aux;

	// compute the initial point of the terrain on the XZ plane
	startW = terrainGridWidth / 2.0 - terrainGridWidth;
	startL = - terrainGridLength / 2.0 + terrainGridLength;
	
	// Create the id for the display list
	terrainDL = glGenLists(1);

	// create the display list
	glNewList(terrainDL,GL_COMPILE);
	
	// test for normals
	if (terrainNormals != NULL) {
		glColorMaterial(GL_FRONT, GL_DIFFUSE);
		glEnable(GL_COLOR_MATERIAL);
	}

	// generate n-1 strips, where n = terrainGridLength
	// for each vertex test if colors and normals are enabled
	for (i = 0 ; i < terrainGridLength-1; i++) {
		glBegin(GL_TRIANGLE_STRIP);
		for (j = 0;j < terrainGridWidth; j++) {
			aux = 3*((i+1)*terrainGridWidth + j);
			if (terrainColors != NULL) 
				glColor3f(terrainColors[aux],
					terrainColors[aux+1],
					terrainColors[aux+2]);
			if (terrainNormals != NULL)
				glNormal3f(terrainNormals[aux],
					terrainNormals[aux+1],
					terrainNormals[aux+2]);
			glVertex3f(
				startW + j + xOffset,
				terrainHeights[(i+1)*terrainGridWidth + (j)] + yOffset,
				startL - (i+1) + zOffset);

			aux = 3*(i*terrainGridWidth + j);
			if (terrainColors != NULL) 
				glColor3f(terrainColors[aux],
					terrainColors[aux+1],
					terrainColors[aux+2]);
			if (terrainNormals != NULL)
				glNormal3f(terrainNormals[aux],
					terrainNormals[aux+1],
					terrainNormals[aux+2]);
			glVertex3f(
				startW + j + xOffset, 
				terrainHeights[(i)*terrainGridWidth + j] + yOffset,
				startL - i + zOffset);					
		}
		glEnd();
	}
	glEndList();

	// return the list index so that the application can use it
	return(terrainDL);
}



In an application using the terrain lib we must first create the terrain and the display list.


    
	//load an image and compute the normals
	if ((status = terrainLoadFromImage("3dtech.tga",1)) != TERRAIN_OK)
		// do something, there was an error
	else
		//scale the terrain so that the height varies from
		// -10 to 30
		terrainScale(-10,30);
		// create a terrain centered on the origin
		myDisplayList = terrainCreateDL(0,0,0);
	




Then, when rendering just call the display list


    
	glCallList(myDisplayList);



The last function to be presented in here provides a way to get the height for a particular XZ point. The syntax is as follows:


float terrainGetHeight(int x, int z);

Parameters:

x - the x coordinate assuming that the terrain is centered on the XZ plane, and the the spacing between points is 1.
z - the z coordinate assuming that the terrain is centered on the XZ plane, and the the spacing between points is 1.


The return value is the height at the requested point.

A simple example application is provided in here. The application is based on the glut examples provided in the glut tutorial. Use the arrow keys to navigate in the terrain. The mouse, when a button is pressed, will allow you to freely look at the scene and change your orientation. Pressing the arrow keys after the mouse button is pressed will speed up your movement. An image is provided as an example as well as some screen shots taken with the application.

The image from where the height map is created

The rendered height map

A detail of the height map

3D Map Generator Terrain 是一款用于创建逼真地形地图的软件,可以帮助用户在短时间内生成高质量的3D地形地图。由于该软件的功能强大且易于使用,因此广受用户喜爱。 要下载 3D Map Generator Terrain,您可以执行以下操作: 1. 在您的Web浏览器中打开搜索引擎,例如Google或百度。 2. 在搜索框中输入“3D Map Generator Terrain下载”。 3. 单击搜索按钮或按下回车键。搜索结果将显示与您的查询相关的各种网站链接。 4. 浏览搜索结果,找到您认为可信度较高且可提供下载的网站。一般来说,应选择官方网站、知名的软件下载网站或有良好口碑的社区。 5. 单击您选择的网站链接,然后找到软件的下载页面。这通常位于网站的主页、产品页面或下载区域。 6. 在下载页面上,您会找到 3D Map Generator Terrain 的下载选项。通常,您可以选择不同版本的软件,包括免费试用版或完整版。 7. 根据您的需求选择适当的版本,并单击下载按钮。某些网站可能会要求您提供一些个人信息或进行注册。 8. 下载完成后,找到您保存的软件文件并双击打开。 9. 遵循安装向导的指示,将软件安装到您的计算机上。 10. 完成安装后,您可以开始使用 3D Map Generator Terrain 创建自己的地形地图了。 需要注意的是,软件下载的过程可能因所使用的搜索引擎、地域和网站的更新情况而有所不同。我们应在下载前确保所选择的网站可信度高,并采取必要的安全措施来保护我们的计算机和个人信息。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值