Generating Terrain Textures by (31 May 2001) |
Return to The Archives |
Introduction
|
Several months ago I was working on a terrain algorithm. When it was
implemented, all of a sudden I realized that I needed some textures. At that
moment I rushed into this texture generation stuff. Here I’ve provided the stuff I’ve found on the net, fertilized with my own ideas. |
The Theory
|
There are different types of terrain. You can call them different types of land if
you like. There are for example snow, rocks, grass, mud, etc. Those can be
found at various places in nature. The texture synthesis in this paper is based on combining all types of terrain but weighted with factors according to the traits of the specific place. For each terrain type a probability factor is calculated and then used as a weight while calculating the color of the current pixel. Calculating the weight Factors defining the influence of a certain type of terrain at the current point: ElevationThere are some factors that modify already specified factors. Elevation skewLighting This is a huge topic, so I’ll stick to a very simple method. Direct lighting. The pixel receives light depending on its normal vector. A simple dot product. More complicated methods can be exploited here but I think this is slightly off topic with this paper. |
Data Structures
|
In order to enable as many terrain types as we use a dynamic structure.
STL offers such structures that can be used with a minor effort. The terrain type. Contains the parameters of the terrain type.
TexID is an identifier of texture in the textures collection. If this value is invalid i.e. no texture is assigned to this terrain type then the r,g,b values are used as color for this terrain type. Factors were discussed in the Theory section. A STL list is used to store the terrain types. The texture type. This is quite straightforward. The memory pointed by pb is the raw bitmap data loaded from the .bmp file.
A STL vector is used to store textures because the index of the texture in the collection is used as an id (texID) in the terrain type. The color factor type The color factor type is used to store all color/weight values that are found to affect the current pixel.
A STL list is used to store all color factor values for a pixel. Loading data in structures The terrain type and texture collections are initialized loading a .txt file. Thus one can generate as many textures as one want only specifying different data files. |
Algorithm
|
For each pixel in the generated texture: Rendering a pixel Rendering a pixel - The code The TRender function finds a color value with height “h” and normal vector “normal”. If there is a texture use tu, tv as texture coordinates. (It is sometimes more appropriate to use different texture coordinates for different terrain types) The g_resource is a global singleton that encapsulates the “terrain type” and texture collections.
|
Problems
|
Although the TRender function is working perfectly, using a height map sometimes
makes it difficult to compute an accurate normal vector. Or the problem is that
an accurate normal vector has been computed from discreet heights on a discreet
grid. Troubling with some interpolation will probably lead to better results. I’m calculating the normal as a cross- product of two vectors made from the four neighbor points of the current point. A simple linear interpolation is applied to enable non-grid aligned heights. Another problem can arise when there are some places that are not covered by any terrain type. This would mean that after all terrain types had been traversed the color/factor collection is empty and we are likely to end with a black pixel in the texture. There is no good solution to this problem as it is a result of lack of information though some tricks can be used. Such as second pass on failure or a second “backup” collection of color/factors. |
Improvements
|
Improving the speed. I haven’t optimized the code. In fact it is quite chaotically written. After all it is not supposed to work run-time. Improving the rendering You can create special effects defining a method of blending for each terrain type. Color modulation for example can result in numerous interesting effects. Improving realism More than one set of terrain types may be used for one landscape to increase the realism. For example different types of grass, grain fields, flowers, mud, loam and many others can be found in the same elevation and slope. Other natural phenomenon can be considered. More factors can be introduced such as shadows, humidity, climate, season, human beings, etc. Shadows are major part of a good light engine. However if we already calculated where the shadow is this information can be used in our texture generation. Places that are known to be in the shadow of a hill most of the day usually grow different type of plants than other areas. Concave places get rid of the water more slowly thus are more wet hence terrain type (mud for example) with larger humidity factor will be placed there. Climate and season can be used to switch between terrain type sets. |
The Source Code
|
The demo source code, which is available to download here: article_generatingterrtex.zip (384k), is actually
used as a texture generator for another demo. It was written in a hurry without any plans or design. Classes: wj_texture_gen - This is the texture generator. MakeTexture method generates the texture. MapInter - interpolates the map grid. Given real coordinates returns a “real” interpolated height. Singleton - template class that allows definition of classes that have only one copy and are global though not quite. wj_resource - Singleton. Encapsulates “terrain type” and texture collections. PureScript - Singleton. Parses text files and loads the data. The main function: The height map is loaded from a .bmp file only the blue component is used as a height. A patch size is specified in the .txt file. The dimensions of the height map are divided to the patch side and appropriate number of textures is generated with the specified resolution. For each patch a wj_texture_gen object is instantiated, MakeTexture is called. Then it is written in a file with name that is generated runtime. There is texture mirroring which I use in other projects. If you want to remove it remove the line: tg.Mirror(px&1,py&1); |
Special Thanks
|
I would like to thank Klaus Hartman about his ideas that really made me try texture synthesis myself. (A large set of ideas exposed in the Theory and Improvement sections.) |
|