I_dovelemon
Date: 2014/9/7
Source: Csdn Blog
Topics: Bump Mapping, Tangent Space, Normal map, Height map
Introduction
We know that in the real world, the surface of any object is not very smooth, this rough surface effect, the light source will be illuminated by the feeling of darkness. So how do you simulate this effect in 3D graphics? Is the modeling method used to build a rough surface for the surface of the model? This method is difficult to make real rough sense, after all, the surface roughness is very small effect, it is difficult to model the way to model. So, it can only be replaced by other methods. In 3D graphics, there is a technique called bump mapping, which allows the surface roughness of the model to be achieved without the need to add additional vertex data to the model.
Bump Mapping
To create this effect, it is clear that we need to simulate by lighting calculations. To perform light calculations, you naturally need light sources and normals. Light source, we can easily use the color value, the light source location to define it. And for normals, because we're not adding vertices, changing the way the model is, so there's only the normals of the vertices, and then interpolation is hard to make a rough feeling. What we need is that when the model is rendered to the final surface, the normals of each pixel need to be different and need to be created according to different lightness and darkness.
And how is the normals of each pixel calculated? Imagine that we can attach a rugged map to the surface of the model, but this map does not have the light and dark feeling of a rough material under the light source. To make this texture feel like a bump and light, we need to get a normal out of every pixel. In this way, as the light source moves continuously, we calculate the illumination of each pixel, and the light and shade effect of each pixel can appear. So the rest of the question is, how do you design the normal of each pixel of the map to create the bump and roughness we want?
In 3D graphics, there is a graph, called height map, that is something. As shown below is a picture of the height:
As can be seen from the above figure, the uneven, black place is very low, the white place is very high. This height chart, in fact, is a grayscale graph, that is, its color values in the RGB components are actually the same.
Well, with this bump effect, our task then is to build each pixel normal according to the height map. Since we can't build in real-time in shader, that's too inefficient, so we need to build the normals of all the texture pixels beforehand, because the normals are vectors, so we can use three components to represent them, so we can keep the normals in the RGB values. Just to scale the values of each component of the normals to a range of 0-255.
The following function is used to calculate the height graph of the BMP format as normal and exists in another BMP bitmap of the same size, which is called the normal map:
<span style= "Font-family:microsoft Yahei;" >/** * Suppose the texture is the + Bit format heightmap and needs to being * converted to BES a normal map instead. */hresult Zfxd3dskinmanager::converttonormalmap (zfxtexture *ptexture) {HRESULT hr= zfx_ok; D3dlocked_rect D3drect; D3dsurface_desc DESC; Get a dummy pointer lpdirect3dtexture9 PTex = ((lpdirect3dtexture9) ptexture->pdata); Ptex->getleveldesc (0, &desc); if (FAILED (ptex->lockrect (0, &d3drect, NULL, 0)) {log ("Error:cannot lock texture to copy pixels \"%s\ "", PT Exture->chname); return zfx_bufferlock; }//Get pointer to pixel data dword* Ppixel = (dword*) d3drect.pbits; Build normals at each pixel for (DWORD j=0; J<desc. Height; J + +) {for (DWORD i=0; I<desc. Width; i++) {DWORD color00 = ppixel[0]; DWORD color10 = ppixel[1]; DWORD Color01 = Ppixel[d3drect.pitch/sizeof (DWORD)]; float fHeight00 = (float) ((color00&0x00ff0000) >>16)/255.0f; float fHeight10 = (float) ((color10&0x00ff0000) >>16)/255.0f; float fHeight01 = (float) ((color01&0x00ff0000) >>16)/255.0f; Zfxvector vcPoint00 (i+0.0f, j+0.0f, fHeight00); Zfxvector vcPoint10 (i+1.0f, j+0.0f, fHeight10); Zfxvector vcPoint01 (i+0.0f, j+1.0f, fHeight01); Zfxvector VC10 = vcpoint10-vcpoint00; Zfxvector vc01 = vcpoint01-vcpoint00; Zfxvector Vcnormal; Vcnormal.cross (VC10, VC01); Vcnormal.normalize (); Store normal as RGBA in normalmap *ppixel++ = Vectortorgba (&vcnormal, fHeight00); }} ptex->unlockrect (0); Lpdirect3dsurface9 psurface=null;ptex->getsurfacelevel (0, &psurface);D 3DXSaveSurfaceToFile ("Normal.bmp", D3dxiff_bmp, psurface, NULL, NULL); return ZFX_OK;} Converttonormalmap</span>
The method of calculating normals from a height map is to take out adjacent three points to construct the normals of these three points. For example, the current pixel is a, then the second point is a pixel B adjacent to the right of a, and the next third point is the adjacent dot C below point A. Because it is a grayscale figure, the three components of the color value are the same, so I select the R component to build the Z-value of the vector point corresponding to the A-pixel point, and use the point-a pixel position xy in the bitmap as the X, y of the build vector. In the same way, we create a vector of three points in turn, and then calculate the final normals. We normalized the normals and then converted the normals to RGB values through Vectortorgba and saved them in a new BMP image.
Here is the function of Vectortorgba:
<span style= "Font-family:microsoft Yahei;" >//encode vector data as RGBA color value for normal Mapdword Vectortorgba (zfxvector *vc, float fheight) { DWORD R = (DWORD) (127.0f * vc->x + 128.0f); DWORD G = (DWORD) (127.0F * vc->y + 128.0f); DWORD B = (DWORD) (127.0F * vc->z + 128.0f); DWORD A = (DWORD) (255.0F * fheight); Return ((a<<24l) + (r<<16l) + (g<<8l) + (b<<0l));} Vectortorgba</span>
This function also saves the normal map in Normal.bmp, the following is the corresponding normal.bmp of the height map:
Summary
This article briefly describes how to build a normal map based on a height map. In the following article, we will tell you how to perform light calculations based on this normal map to achieve the effect of concave and convex shading. And in the following will be a very important concept in 3D graphics: Tangent Space.
Zfxengine Development Note Bump Mapping (1)