3d terrain generation

转载 2008年09月30日 18:02:00


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);


    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)
    	// 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)
    	// 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) {
    		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 * 
    	if (terrainHeights == NULL)
    	// allocate memory for the normals, and check for errors
    	if (normals) {
    		terrainNormals = (float *)malloc(terrainGridWidth * 
    						terrainGridLength * 
    						sizeof(float) * 3);
    		if (terrainNormals == NULL)
    			terrainNormals = NULL;
    	// if mode = RGBA then allocate memory for colors, and check for errors
    	if (mode == 4) {
    		terrainColors = (float *)malloc(terrainGridWidth * 
    						terrainGridLength * 
    		if (terrainColors == NULL)
    		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] =
    				terrainColors[3*(i*terrainGridWidth + j)+2] = 
    	// if we want normals then compute them		
    	if (normals)
    	// free the image's memory 

    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);


    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);


    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);


    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
    	// test for normals
    	if (terrainNormals != NULL) {
    		glColorMaterial(GL_FRONT, GL_DIFFUSE);
    	// generate n-1 strips, where n = terrainGridLength
    	// for each vertex test if colors and normals are enabled
    	for (i = 0 ; i < terrainGridLength-1; i++) {
    		for (j = 0;j < terrainGridWidth; j++) {
    			aux = 3*((i+1)*terrainGridWidth + j);
    			if (terrainColors != NULL) 
    			if (terrainNormals != NULL)
    				startW + j + xOffset,
    				terrainHeights[(i+1)*terrainGridWidth + (j)] + yOffset,
    				startL - (i+1) + zOffset);
    			aux = 3*(i*terrainGridWidth + j);
    			if (terrainColors != NULL) 
    			if (terrainNormals != NULL)
    				startW + j + xOffset, 
    				terrainHeights[(i)*terrainGridWidth + j] + yOffset,
    				startL - i + zOffset);					
    	// return the list index so that the application can use it

    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
    		//scale the terrain so that the height varies from
    		// -10 to 30
    		// create a terrain centered on the origin
    		myDisplayList = terrainCreateDL(0,0,0);

    Then, when rendering just call the display list


    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);


    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

    Focus On 3D Terrain Programming·Chapter 5(1)

    《Focus On 3D Terrain Programming》 第5章翻译的第1部分
    • u013216537
    • u013216537
    • 2017年06月29日 22:55
    • 158

    学习 开源 3D gis软件 --Virtual Terrain Project

    开源GIS软件 VTPThe goal of VTP is to foster the creation of tools for easily constructing any part of th...
    • zhizhu8256
    • zhizhu8256
    • 2008年01月07日 15:19
    • 3123


    从前对unity3dTerrain这块了解很少,只知道他可以刷地形。这几天一直弄地形,发现地形有点意思,主要通过以下几点来说明: (1)地形尺寸是可以改变的,一般自动创建的是长度2000宽度2000...
    • woailvmengmeng
    • woailvmengmeng
    • 2013年12月15日 19:00
    • 3036

    地形算法 Fractal Terrain Generation

    地形算法 Fault Generation 一、不规则地形生成(分形地形算法):Fractal Terrain Generation Fractal Terrain Gener...
    • familycsd000
    • familycsd000
    • 2015年06月24日 16:55
    • 904


    • lavendarWang
    • lavendarWang
    • 2014年10月28日 20:09
    • 887

    [基础教程] Unity3D Terrian地形设置中文教程

    Using Terrains 使用地形 Creating a new Terrain 创建地形 A new Terrain can be created from Terrain->Create Te...
    • mysouling
    • mysouling
    • 2016年02月24日 10:51
    • 1969


    • holsety
    • holsety
    • 2007年04月27日 23:43
    • 2339

    Direct3D 地形

    高程图生成三角形网格 3D场景的模拟离不开地形,因此3D地形的模拟在3D程序设计中很重要。在3D场景中,地形的表面都是通过三角形网来表示,即通过高度图(也称影像图)上的对应坐标值来表示规则网格顶点坐标...
    • u011000290
    • u011000290
    • 2015年11月06日 23:11
    • 717

    Unity3D 地形(Terrain)设置

    这篇说的是Unity地形 关于Unity3D是什么。我就不多做解释了。由于工作原因,该系列原创教程不定期更新。每月必然有更新。谢谢各位。 Unity地形:: 新建地形: ...
    • linuxheik
    • linuxheik
    • 2014年07月23日 19:24
    • 2204

    unity terrain export to obj

    unity terrain export to obj
    • 2016年03月15日 10:17
    • 1594
    您举报文章:3d terrain generation