《introduce to 3D Game Programming》 Chapter 13 Terrain reading nodes
-----------------------------------------------------------------------------------------------------------------------------------------------
灰度图: 用来表示地形高度
heightmap is an array where each element specifies the height of a particular vertex in the terrain grid
allocate a byte of memory for each element in heightmap.
loading a RAW File
定义vector<byte>,这样值就在[0,255]灰度范围之内
bool Terrain::readRawFile(std::string fileName)
{
// Restriction: RAW file dimensions must be >= to the
// dimensions of the terrain. That is a 128x128 RAW file
// can only be used with a terrain constructed with at most
// 128x128 vertices.
// A height for each vertex
std::vector<BYTE> in( _numVertices );
std::ifstream inFile(fileName.c_str(), std::ios_base::binary);
if( inFile == 0 )
return false;
inFile.read(
(char*)&in[0], // buffer
in.size());// number of bytes to read into buffer
inFile.close();
// copy BYTE vector to int vector
_heightmap.resize( _numVertices );
for(int i = 0; i < in.size(); i++)
_heightmap[i] = in[i];
return true;
}
Accessing and modifying the heightmap
Terrain::getHeightmapEntry
Terrain:: setHeightmapEntry
Generating the terrain geometry
地形大小的定义,通过行,列, 以及行列中单元格子的大小 3个元素来确定
define the size of our terrain by specifying the number of vertices per row, the number of vertices per column,
and the cell spacing.
_width = _numCellsPerRow * _cellSPacing;
_depth = _numCellsPerCol * _cellSPacing;
Computing the Vertices
begin generating vertices at start and then to row by row generating vertices until we reach end.
the y-coordinate is easily obtained by finding the corresponding entry in the loaded heightmap data structure
(u,v) texture coordinate that corresponds to the terrain vertex at (i,j) is given by:
根据i,j 乘以 cellSpacing,可以获取顶点在UV坐标系中的坐标
u = j . uCoordIncrementSize
v = i. vCoordIncrementSize
Terrain::Terrain(IDirect3DDevice9* device,
std::string heightmapFileName,
int numVertsPerRow,
int numVertsPerCol,
int cellSpacing,
float heightScale)
{
_device = device;
_numVertsPerRow = numVertsPerRow;
_numVertsPerCol = numVertsPerCol;
_cellSpacing = cellSpacing;
_numCellsPerRow = _numVertsPerRow - 1;
_numCellsPerCol = _numVertsPerCol - 1;
_width = _numCellsPerRow * _cellSpacing;
_depth = _numCellsPerCol * _cellSpacing;
_numVertices = _numVertsPerRow * _numVertsPerCol;
_numTriangles = _numCellsPerRow * _numCellsPerCol * 2;
_heightScale = heightScale;
Computing the Indices-Defining the Triangles
to compute the indices of the triangle grid, we simply iterate through each quad, starting in the upper left and ending
in the lower right of Figure 13.4, and compute the two triangles that make up that quad.
从左上到右下方向使用迭代的方法,计算三角形面片的顶点。
Texturing
the Terrain class provides two ways to texture the terrain. The obvious way is to simply load a previously made textrue
file and use that. The following method implemented by the Terrain class loads a texture form the file into the _tex
data member, which is a pointer to an IDirect3DTexture9 interface. internally, the Terrain:: draw method sets _tex before
rendering the terrain.
load 已有的纹理
bool Terrain::loadTexture(std::string fileName)
{
HRESULT hr = 0;
hr = D3DXCreateTextureFromFile(
_device,
fileName.c_str(),
&_tex);
if(FAILED(hr))
return false;
return true;
}
Lighting
Terrain::genTexture method makes a calll to Rerrain:: lightTerrain that, as the name implies, lights the terrain to enhance
the realism. Since we already computed the colors of the terrain texture, we only need to compute a shade factor that brightens
or darkens areas of the rerrain with respect to a defined light source.
as angles get larger, the quad faces more and more away from the light source, thus receiving less light. notice that once
the angle between the light vector and the normal is greater then 90 degrees, the surface receives no light.
使用Rerrain:: lightTerrain, 因为纹理已经给地形加的颜色,我们只需通过计算光线和法线的夹角来确定地形的亮度。
Computing the shade of a Quad
the direction to the light source is given as a normalized vector that we call L in this discussion. in order to calculate the
angle between L and the quad’s normal vector N, we first need to find N,
计算法线:即是计算两个向量的叉乘
Shading the Terrain
simply iterate through each quad, compute the shade value of that quad, and then scale the quad’s corresponding
texel color by that shade.
Walking on the Terain
move the camera so that it simulates us walking on the terrain. That is ,we need to adjust the camera’s height(y-coordinate)
depending on the part of the terrain that we are standing on.In order to do this we first need to find the cell we are in given
the x- and z-coordinates of the camera’s position. The Terrain:: gerHeight function does this; it takes the camera’s x- and z-corrdinates
as parameters and returns the height the camera needs to be set to in order for it to be on the terrain.
通过移动相机来模拟行走在地图上面。即通过调整相机的高度来随地形起伏变化。首先找到摄像机的位置,然后即可获取高度Terrain:: gerHeight
if we are in the “upper” triangle,. otherwise, we are in the “lower” triangle
to find the height if we are in the “upper” triangle, we construct 2 vectors, u = (cellSpacing, B-A,0) andv = (0,C-A,-cellSpacing)
q = (qx ,A, qz) , 沿向量u方向做线性插值得到dx,同理得到dz,这样高度 y 向量为(q+dxu+dzv)