DirectX 3D 基本框架(四)
2008-10-27 15:43
232 查看
继续扩展原来的D3D基本框架。这次将添加地形类库。做出如下修改:
1.增加一个terrain头/库文件。
代码清单:
//////////////////////////////////////////////////////////////////////////////////////////////////
//
// File: terrain.h
//
// by tianzhihen
//
// 2008.10.27, MSVC++ 8.0
//
//////////////////////////////////////////////////////////////////////////////////////////////////
#ifndef __terrainH__
#define __terrainH__
#include "d3dUtility.h"
#include <string>
#include <vector>
class Terrain
{
public:
Terrain(
IDirect3DDevice9* device,
std::string heightmapFileName,
int numVertsPerRow,
int numVertsPerCol,
int cellSpacing, // space between cells
float heightScale);
~Terrain();
int getHeightmapEntry(int row, int col);
void setHeightmapEntry(int row, int col, int value);
float getHeight(float x, float z);
bool loadTexture(std::string fileName);
bool genTexture(D3DXVECTOR3* directionToLight);
bool draw(D3DXMATRIX* world, bool drawTris);
private:
IDirect3DDevice9* _device;
IDirect3DTexture9* _tex;
IDirect3DVertexBuffer9* _vb;
IDirect3DIndexBuffer9* _ib;
int _numVertsPerRow;
int _numVertsPerCol;
int _cellSpacing;
int _numCellsPerRow;
int _numCellsPerCol;
int _width;
int _depth;
int _numVertices;
int _numTriangles;
float _heightScale;
std::vector<int> _heightmap;
// 帮助器函数
bool readRawFile(std::string fileName);
bool computeVertices();
bool computeIndices();
float computeShade(int cellRow, int cellCol, D3DXVECTOR3* directionToLight);
struct TerrainVertex
{
TerrainVertex(){}
TerrainVertex(float x, float y, float z, float u, float v)
{
_x = x; _y = y; _z = z; _u = u; _v = v;
}
float _x, _y, _z;
float _u, _v;
static const DWORD FVF;
};
};
#endif // __terrainH__
//////////////////////////////////////////////////////////////////////////////////////////////////
//
// File: terrain.cpp
//
// by tianzhihen
//
// 2008.10.27, MSVC++ 8.0
//
//////////////////////////////////////////////////////////////////////////////////////////////////
#include "terrain.h"
#include <fstream>
#include <cmath>
const DWORD Terrain::TerrainVertex::FVF = D3DFVF_XYZ | D3DFVF_TEX1;
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;
// 加载高度图
if( !readRawFile(heightmapFileName) )
{
::MessageBox(0, "readRawFile - FAILED", 0, 0);
::PostQuitMessage(0);
}
// 缩放高度
for(int i = 0; i < _heightmap.size(); i++)
_heightmap[i] *= heightScale;
// 计算顶点坐标
if( !computeVertices() )
{
::MessageBox(0, "computeVertices - FAILED", 0, 0);
::PostQuitMessage(0);
}
// 计算索引坐标
if( !computeIndices() )
{
::MessageBox(0, "computeIndices - FAILED", 0, 0);
::PostQuitMessage(0);
}
}
Terrain::~Terrain()
{
d3d::Release<IDirect3DVertexBuffer9*>(_vb);
d3d::Release<IDirect3DIndexBuffer9*>(_ib);
d3d::Release<IDirect3DTexture9*>(_tex);
}
int Terrain::getHeightmapEntry(int row, int col)
{
return _heightmap[row * _numVertsPerRow + col];
}
void Terrain::setHeightmapEntry(int row, int col, int value)
{
_heightmap[row * _numVertsPerRow + col] = value;
}
bool Terrain::computeVertices()
{
HRESULT hr = 0;
hr = _device->CreateVertexBuffer(
_numVertices * sizeof(TerrainVertex),
D3DUSAGE_WRITEONLY,
TerrainVertex::FVF,
D3DPOOL_MANAGED,
&_vb,
0);
if(FAILED(hr))
return false;
// 起始顶点坐标
int startX = -_width / 2;
int startZ = _depth / 2;
// 终点顶点坐标
int endX = _width / 2;
int endZ = -_depth / 2;
//计算纹理坐标([0,1]之间)的增量
float uCoordIncrementSize = 1.0f / (float)_numCellsPerRow;
float vCoordIncrementSize = 1.0f / (float)_numCellsPerCol;
TerrainVertex* v = 0;
_vb->Lock(0, 0, (void**)&v, 0);
int i = 0;
for(int z = startZ; z >= endZ; z -= _cellSpacing)
{
int j = 0;
for(int x = startX; x <= endX; x += _cellSpacing)
{
// 设置空间坐标及纹理坐标
int index = i * _numVertsPerRow + j;
v[index] = TerrainVertex(
(float)x,
(float)_heightmap[index],
(float)z,
(float)j * uCoordIncrementSize,
(float)i * vCoordIncrementSize);
j++; // next column
}
i++; // next row
}
_vb->Unlock();
return true;
}
bool Terrain::computeIndices()
{
HRESULT hr = 0;
hr = _device->CreateIndexBuffer(
_numTriangles * 3 * sizeof(WORD), // 3 indices per triangle
D3DUSAGE_WRITEONLY,
D3DFMT_INDEX16,
D3DPOOL_MANAGED,
&_ib,
0);
if(FAILED(hr))
return false;
WORD* indices = 0;
_ib->Lock(0, 0, (void**)&indices, 0);
int baseIndex = 0;
// 循环计算每个四边形的索引值
for(int i = 0; i < _numCellsPerCol; i++)
{
for(int j = 0; j < _numCellsPerRow; j++)
{
indices[baseIndex] = i * _numVertsPerRow + j;
indices[baseIndex + 1] = i * _numVertsPerRow + j + 1;
indices[baseIndex + 2] = (i+1) * _numVertsPerRow + j;
indices[baseIndex + 3] = (i+1) * _numVertsPerRow + j;
indices[baseIndex + 4] = i * _numVertsPerRow + j + 1;
indices[baseIndex + 5] = (i+1) * _numVertsPerRow + j + 1;
// next quad
baseIndex += 6;
}
}
_ib->Unlock();
return true;
}
bool Terrain::loadTexture(std::string fileName)
{
// 加载已创建好的纹理文件
HRESULT hr = 0;
hr = D3DXCreateTextureFromFile(
_device,
fileName.c_str(),
&_tex);
if(FAILED(hr))
return false;
return true;
}
bool Terrain::genTexture(D3DXVECTOR3* directionToLight)
{
// 一种过程化方法 —— 首先创建一个空纹理,然后基于地形的高度图逐个计算纹理元的颜色
HRESULT hr = 0;
// 纹理元宽/高
int texWidth = _numCellsPerRow;
int texHeight = _numCellsPerCol;
// 创建空纹理
hr = D3DXCreateTexture(
_device,
texWidth, texHeight,
0, // create a complete mipmap chain
0, // usage
D3DFMT_X8R8G8B8,// 32 bit XRGB format
D3DPOOL_MANAGED, &_tex);
if(FAILED(hr))
return false;
D3DSURFACE_DESC textureDesc;
_tex->GetLevelDesc(0 /*level*/, &textureDesc);
// 验证纹理元格式
if( textureDesc.Format != D3DFMT_X8R8G8B8 )
return false;
D3DLOCKED_RECT lockedRect;
_tex->LockRect(0/*lock top surface*/, &lockedRect,
0 /* lock entire tex*/, 0/*flags*/);
DWORD* imageData = (DWORD*)lockedRect.pBits;
for(int i = 0; i < texHeight; i++)
{
for(int j = 0; j < texWidth; j++)
{
D3DXCOLOR c;
// 取得顶点高度
float height = (float)getHeightmapEntry(i, j) / _heightScale;
// 确定顶点颜色
if( (height) < 42.5f ) c = d3d::BEACH_SAND;
else if( (height) < 85.0f ) c = d3d::LIGHT_YELLOW_GREEN;
else if( (height) < 127.5f ) c = d3d::PUREGREEN;
else if( (height) < 170.0f ) c = d3d::DARK_YELLOW_GREEN;
else if( (height) < 212.5f ) c = d3d::DARKBROWN;
else c = d3d::WHITE;
// 确定单位纹理元明暗度
c *= computeShade(i, j, directionToLight);
imageData[i * lockedRect.Pitch / 4 + j] = (D3DCOLOR)c;//float->DWORD
}
}
_tex->UnlockRect(0);
//纹理过滤
hr = D3DXFilterTexture(
_tex,
0, // default palette
0, // use top level as source level
D3DX_DEFAULT); // default filter
if(FAILED(hr))
{
::MessageBox(0, "D3DXFilterTexture() - FAILED", 0, 0);
return false;
}
return true;
}
float Terrain::computeShade(int cellRow, int cellCol, D3DXVECTOR3* directionToLight)
{
// 计算三角形平面顶点高度值
float heightA = getHeightmapEntry(cellRow, cellCol);
float heightB = getHeightmapEntry(cellRow, cellCol+1);
float heightC = getHeightmapEntry(cellRow+1, cellCol);
// 创建 u/v 向量
D3DXVECTOR3 u(_cellSpacing, heightB - heightA, 0.0f);
D3DXVECTOR3 v(0.0f, heightC - heightA, -_cellSpacing);
// 计算平面法向量
D3DXVECTOR3 n;
D3DXVec3Cross(&n, &u, &v);
D3DXVec3Normalize(&n, &n);
// 计算法向量与方向光的cos值
float cosine = D3DXVec3Dot(&n, directionToLight);
if(cosine < 0.0f)
cosine = 0.0f;
return cosine;
}
bool Terrain::readRawFile(std::string fileName)
{
// 读取RAW文件(128x128) 最多128x128个顶点
// 每个顶点对应一个高度值
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();
// 重置高度图vector大小
_heightmap.resize( _numVertices );
for(int i = 0; i < in.size(); i++)
_heightmap[i] = in[i];
return true;
}
float Terrain::getHeight(float x, float z)
{
// 求得点所在高度(计算视点矩阵用)
// 变换坐标系——使原点位于左上角,而不是原来的中心
x = ((float)_width / 2.0f) + x;
z = ((float)_depth / 2.0f) - z;
// 变换坐标系单位长度——不是原来的_cellSpacing,而是1
x /= (float)_cellSpacing;
z /= (float)_cellSpacing;
// 取不大于 x/z 的最大整数
float col = ::floorf(x);
float row = ::floorf(z);
// 取得所求点所在方格的4个顶点高度
//
// A B
// *---*
// | / |
// *---*
// C D
float A = getHeightmapEntry(row, col);
float B = getHeightmapEntry(row, col+1);
float C = getHeightmapEntry(row+1, col);
float D = getHeightmapEntry(row+1, col+1);
// 继续变换坐标——使dx/dz位于左上第一个方格内
float dx = x - col;
float dz = z - row;
float height = 0.0f;
if(dz < 1.0f - dx) //点位于上三角ABC
{
float uy = B - A; // A->B
float vy = C - A; // A->C
// (A + dxu + dzv)的y分量就是该点所处高度
height = A + d3d::Lerp(0.0f, uy, dx) + d3d::Lerp(0.0f, vy, dz);
}
else // 点位于下三角DCB
{
float uy = C - D; // D->C
float vy = B - D; // D->B
height = D + d3d::Lerp(0.0f, uy, 1.0f - dx) + d3d::Lerp(0.0f, vy, 1.0f - dz);
}
return height;
}
bool Terrain::draw(D3DXMATRIX* world, bool drawTris)
{
HRESULT hr = 0;
if( _device )
{
_device->SetTransform(D3DTS_WORLD, world);
_device->SetStreamSource(0, _vb, 0, sizeof(TerrainVertex));
_device->SetFVF(TerrainVertex::FVF);
_device->SetIndices(_ib);
_device->SetTexture(0, _tex);
// 不使用光照直到我们开启
_device->SetRenderState(D3DRS_LIGHTING, false);
hr =_device->DrawIndexedPrimitive(
D3DPT_TRIANGLELIST,
0,
0,
_numVertices,
0,
_numTriangles);
_device->SetRenderState(D3DRS_LIGHTING, true);
if( drawTris )
{
_device->SetRenderState(D3DRS_FILLMODE, D3DFILL_WIREFRAME);
hr =_device->DrawIndexedPrimitive(
D3DPT_TRIANGLELIST,
0,
0,
_numVertices,
0,
_numTriangles);
_device->SetRenderState(D3DRS_FILLMODE, D3DFILL_SOLID);
}
if(FAILED(hr))
return false;
}
return true;
}
2.增加一个FPS类(计算帧频)
代码清单:
//////////////////////////////////////////////////////////////////////////////////////////////////
//
// File: fps.h
//
// by tianzhihen
//
// 2008.10.27, MSVC++ 8.0
//
//////////////////////////////////////////////////////////////////////////////////////////////////
#ifndef __fpsH__
#define __fpsH__
#include "d3dfont.h"
class FPSCounter
{
public:
FPSCounter(IDirect3DDevice9* device);
~FPSCounter();
bool render(D3DCOLOR color, float timeDelta);
private:
IDirect3DDevice9* _device;
CD3DFont* _font;
DWORD _frameCnt;
float _timeElapsed;
float _fps;
char _fpsString[9];
};
#endif // __fpsH__
//////////////////////////////////////////////////////////////////////////////////////////////////
//
// File: fps.cpp
//
// by tianzhihen
//
// 2008.10.27, MSVC++ 8.0
//
//////////////////////////////////////////////////////////////////////////////////////////////////
#include "fps.h"
#include <cstdio>
FPSCounter::FPSCounter(IDirect3DDevice9* device)
{
_device = device;
_font = new CD3DFont("Times New Roman", 24, 0);
_font->InitDeviceObjects( _device );
_font->RestoreDeviceObjects();
_frameCnt = 0;
_timeElapsed = 0.0f;
_fps = 0.0f;
}
FPSCounter::~FPSCounter()
{
if( _font )
{
_font->InvalidateDeviceObjects();
_font->DeleteDeviceObjects();
delete _font;
}
}
bool FPSCounter::render(D3DCOLOR color, float timeDelta)
{
if( _font )
{
_frameCnt++;
_timeElapsed += timeDelta;
if(_timeElapsed >= 1.0f)
{
_fps = (float)_frameCnt / _timeElapsed;
sprintf(_fpsString, "%f", _fps);
_fpsString[8] = '/0'; // mark end of string
_timeElapsed = 0.0f;
_frameCnt = 0;
}
_font->DrawText(20, 20, color, _fpsString);
}
return true;
}
3.增加相应DX框架文件。因为FPS类用到了d3dfont.h头文件,因此需添加相应的框架文件。列举如下:
d3dfont.h d3dfont.cpp dxutil.h dxutil.cpp d3dutil.h d3dutil.cpp
4.保持camera类不变。d3dUtility.cpp添加Lerp()函数。
float d3d::Lerp(float a, float b, float t)
{
return a - (a*t) + (b*t);
}
相应的d3dUtility.h须包含此函数声明。
float Lerp(float a, float b, float t);
5.在d3dUtility.h中添加一些颜色常量。
const D3DXCOLOR BEACH_SAND( D3DCOLOR_XRGB(255, 249, 157) );
const D3DXCOLOR DESERT_SAND( D3DCOLOR_XRGB(250, 205, 135) );
const D3DXCOLOR LIGHTGREEN( D3DCOLOR_XRGB( 60, 184, 120) );
const D3DXCOLOR PUREGREEN( D3DCOLOR_XRGB( 0, 166, 81) );
const D3DXCOLOR DARKGREEN( D3DCOLOR_XRGB( 0, 114, 54) );
const D3DXCOLOR LIGHT_YELLOW_GREEN( D3DCOLOR_XRGB(124, 197, 118) );
const D3DXCOLOR PURE_YELLOW_GREEN( D3DCOLOR_XRGB( 57, 181, 74) );
const D3DXCOLOR DARK_YELLOW_GREEN( D3DCOLOR_XRGB( 25, 123, 48) );
const D3DXCOLOR LIGHTBROWN(D3DCOLOR_XRGB(198, 156, 109));
const D3DXCOLOR DARKBROWN( D3DCOLOR_XRGB(115, 100, 87));
1.增加一个terrain头/库文件。
代码清单:
//////////////////////////////////////////////////////////////////////////////////////////////////
//
// File: terrain.h
//
// by tianzhihen
//
// 2008.10.27, MSVC++ 8.0
//
//////////////////////////////////////////////////////////////////////////////////////////////////
#ifndef __terrainH__
#define __terrainH__
#include "d3dUtility.h"
#include <string>
#include <vector>
class Terrain
{
public:
Terrain(
IDirect3DDevice9* device,
std::string heightmapFileName,
int numVertsPerRow,
int numVertsPerCol,
int cellSpacing, // space between cells
float heightScale);
~Terrain();
int getHeightmapEntry(int row, int col);
void setHeightmapEntry(int row, int col, int value);
float getHeight(float x, float z);
bool loadTexture(std::string fileName);
bool genTexture(D3DXVECTOR3* directionToLight);
bool draw(D3DXMATRIX* world, bool drawTris);
private:
IDirect3DDevice9* _device;
IDirect3DTexture9* _tex;
IDirect3DVertexBuffer9* _vb;
IDirect3DIndexBuffer9* _ib;
int _numVertsPerRow;
int _numVertsPerCol;
int _cellSpacing;
int _numCellsPerRow;
int _numCellsPerCol;
int _width;
int _depth;
int _numVertices;
int _numTriangles;
float _heightScale;
std::vector<int> _heightmap;
// 帮助器函数
bool readRawFile(std::string fileName);
bool computeVertices();
bool computeIndices();
float computeShade(int cellRow, int cellCol, D3DXVECTOR3* directionToLight);
struct TerrainVertex
{
TerrainVertex(){}
TerrainVertex(float x, float y, float z, float u, float v)
{
_x = x; _y = y; _z = z; _u = u; _v = v;
}
float _x, _y, _z;
float _u, _v;
static const DWORD FVF;
};
};
#endif // __terrainH__
//////////////////////////////////////////////////////////////////////////////////////////////////
//
// File: terrain.cpp
//
// by tianzhihen
//
// 2008.10.27, MSVC++ 8.0
//
//////////////////////////////////////////////////////////////////////////////////////////////////
#include "terrain.h"
#include <fstream>
#include <cmath>
const DWORD Terrain::TerrainVertex::FVF = D3DFVF_XYZ | D3DFVF_TEX1;
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;
// 加载高度图
if( !readRawFile(heightmapFileName) )
{
::MessageBox(0, "readRawFile - FAILED", 0, 0);
::PostQuitMessage(0);
}
// 缩放高度
for(int i = 0; i < _heightmap.size(); i++)
_heightmap[i] *= heightScale;
// 计算顶点坐标
if( !computeVertices() )
{
::MessageBox(0, "computeVertices - FAILED", 0, 0);
::PostQuitMessage(0);
}
// 计算索引坐标
if( !computeIndices() )
{
::MessageBox(0, "computeIndices - FAILED", 0, 0);
::PostQuitMessage(0);
}
}
Terrain::~Terrain()
{
d3d::Release<IDirect3DVertexBuffer9*>(_vb);
d3d::Release<IDirect3DIndexBuffer9*>(_ib);
d3d::Release<IDirect3DTexture9*>(_tex);
}
int Terrain::getHeightmapEntry(int row, int col)
{
return _heightmap[row * _numVertsPerRow + col];
}
void Terrain::setHeightmapEntry(int row, int col, int value)
{
_heightmap[row * _numVertsPerRow + col] = value;
}
bool Terrain::computeVertices()
{
HRESULT hr = 0;
hr = _device->CreateVertexBuffer(
_numVertices * sizeof(TerrainVertex),
D3DUSAGE_WRITEONLY,
TerrainVertex::FVF,
D3DPOOL_MANAGED,
&_vb,
0);
if(FAILED(hr))
return false;
// 起始顶点坐标
int startX = -_width / 2;
int startZ = _depth / 2;
// 终点顶点坐标
int endX = _width / 2;
int endZ = -_depth / 2;
//计算纹理坐标([0,1]之间)的增量
float uCoordIncrementSize = 1.0f / (float)_numCellsPerRow;
float vCoordIncrementSize = 1.0f / (float)_numCellsPerCol;
TerrainVertex* v = 0;
_vb->Lock(0, 0, (void**)&v, 0);
int i = 0;
for(int z = startZ; z >= endZ; z -= _cellSpacing)
{
int j = 0;
for(int x = startX; x <= endX; x += _cellSpacing)
{
// 设置空间坐标及纹理坐标
int index = i * _numVertsPerRow + j;
v[index] = TerrainVertex(
(float)x,
(float)_heightmap[index],
(float)z,
(float)j * uCoordIncrementSize,
(float)i * vCoordIncrementSize);
j++; // next column
}
i++; // next row
}
_vb->Unlock();
return true;
}
bool Terrain::computeIndices()
{
HRESULT hr = 0;
hr = _device->CreateIndexBuffer(
_numTriangles * 3 * sizeof(WORD), // 3 indices per triangle
D3DUSAGE_WRITEONLY,
D3DFMT_INDEX16,
D3DPOOL_MANAGED,
&_ib,
0);
if(FAILED(hr))
return false;
WORD* indices = 0;
_ib->Lock(0, 0, (void**)&indices, 0);
int baseIndex = 0;
// 循环计算每个四边形的索引值
for(int i = 0; i < _numCellsPerCol; i++)
{
for(int j = 0; j < _numCellsPerRow; j++)
{
indices[baseIndex] = i * _numVertsPerRow + j;
indices[baseIndex + 1] = i * _numVertsPerRow + j + 1;
indices[baseIndex + 2] = (i+1) * _numVertsPerRow + j;
indices[baseIndex + 3] = (i+1) * _numVertsPerRow + j;
indices[baseIndex + 4] = i * _numVertsPerRow + j + 1;
indices[baseIndex + 5] = (i+1) * _numVertsPerRow + j + 1;
// next quad
baseIndex += 6;
}
}
_ib->Unlock();
return true;
}
bool Terrain::loadTexture(std::string fileName)
{
// 加载已创建好的纹理文件
HRESULT hr = 0;
hr = D3DXCreateTextureFromFile(
_device,
fileName.c_str(),
&_tex);
if(FAILED(hr))
return false;
return true;
}
bool Terrain::genTexture(D3DXVECTOR3* directionToLight)
{
// 一种过程化方法 —— 首先创建一个空纹理,然后基于地形的高度图逐个计算纹理元的颜色
HRESULT hr = 0;
// 纹理元宽/高
int texWidth = _numCellsPerRow;
int texHeight = _numCellsPerCol;
// 创建空纹理
hr = D3DXCreateTexture(
_device,
texWidth, texHeight,
0, // create a complete mipmap chain
0, // usage
D3DFMT_X8R8G8B8,// 32 bit XRGB format
D3DPOOL_MANAGED, &_tex);
if(FAILED(hr))
return false;
D3DSURFACE_DESC textureDesc;
_tex->GetLevelDesc(0 /*level*/, &textureDesc);
// 验证纹理元格式
if( textureDesc.Format != D3DFMT_X8R8G8B8 )
return false;
D3DLOCKED_RECT lockedRect;
_tex->LockRect(0/*lock top surface*/, &lockedRect,
0 /* lock entire tex*/, 0/*flags*/);
DWORD* imageData = (DWORD*)lockedRect.pBits;
for(int i = 0; i < texHeight; i++)
{
for(int j = 0; j < texWidth; j++)
{
D3DXCOLOR c;
// 取得顶点高度
float height = (float)getHeightmapEntry(i, j) / _heightScale;
// 确定顶点颜色
if( (height) < 42.5f ) c = d3d::BEACH_SAND;
else if( (height) < 85.0f ) c = d3d::LIGHT_YELLOW_GREEN;
else if( (height) < 127.5f ) c = d3d::PUREGREEN;
else if( (height) < 170.0f ) c = d3d::DARK_YELLOW_GREEN;
else if( (height) < 212.5f ) c = d3d::DARKBROWN;
else c = d3d::WHITE;
// 确定单位纹理元明暗度
c *= computeShade(i, j, directionToLight);
imageData[i * lockedRect.Pitch / 4 + j] = (D3DCOLOR)c;//float->DWORD
}
}
_tex->UnlockRect(0);
//纹理过滤
hr = D3DXFilterTexture(
_tex,
0, // default palette
0, // use top level as source level
D3DX_DEFAULT); // default filter
if(FAILED(hr))
{
::MessageBox(0, "D3DXFilterTexture() - FAILED", 0, 0);
return false;
}
return true;
}
float Terrain::computeShade(int cellRow, int cellCol, D3DXVECTOR3* directionToLight)
{
// 计算三角形平面顶点高度值
float heightA = getHeightmapEntry(cellRow, cellCol);
float heightB = getHeightmapEntry(cellRow, cellCol+1);
float heightC = getHeightmapEntry(cellRow+1, cellCol);
// 创建 u/v 向量
D3DXVECTOR3 u(_cellSpacing, heightB - heightA, 0.0f);
D3DXVECTOR3 v(0.0f, heightC - heightA, -_cellSpacing);
// 计算平面法向量
D3DXVECTOR3 n;
D3DXVec3Cross(&n, &u, &v);
D3DXVec3Normalize(&n, &n);
// 计算法向量与方向光的cos值
float cosine = D3DXVec3Dot(&n, directionToLight);
if(cosine < 0.0f)
cosine = 0.0f;
return cosine;
}
bool Terrain::readRawFile(std::string fileName)
{
// 读取RAW文件(128x128) 最多128x128个顶点
// 每个顶点对应一个高度值
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();
// 重置高度图vector大小
_heightmap.resize( _numVertices );
for(int i = 0; i < in.size(); i++)
_heightmap[i] = in[i];
return true;
}
float Terrain::getHeight(float x, float z)
{
// 求得点所在高度(计算视点矩阵用)
// 变换坐标系——使原点位于左上角,而不是原来的中心
x = ((float)_width / 2.0f) + x;
z = ((float)_depth / 2.0f) - z;
// 变换坐标系单位长度——不是原来的_cellSpacing,而是1
x /= (float)_cellSpacing;
z /= (float)_cellSpacing;
// 取不大于 x/z 的最大整数
float col = ::floorf(x);
float row = ::floorf(z);
// 取得所求点所在方格的4个顶点高度
//
// A B
// *---*
// | / |
// *---*
// C D
float A = getHeightmapEntry(row, col);
float B = getHeightmapEntry(row, col+1);
float C = getHeightmapEntry(row+1, col);
float D = getHeightmapEntry(row+1, col+1);
// 继续变换坐标——使dx/dz位于左上第一个方格内
float dx = x - col;
float dz = z - row;
float height = 0.0f;
if(dz < 1.0f - dx) //点位于上三角ABC
{
float uy = B - A; // A->B
float vy = C - A; // A->C
// (A + dxu + dzv)的y分量就是该点所处高度
height = A + d3d::Lerp(0.0f, uy, dx) + d3d::Lerp(0.0f, vy, dz);
}
else // 点位于下三角DCB
{
float uy = C - D; // D->C
float vy = B - D; // D->B
height = D + d3d::Lerp(0.0f, uy, 1.0f - dx) + d3d::Lerp(0.0f, vy, 1.0f - dz);
}
return height;
}
bool Terrain::draw(D3DXMATRIX* world, bool drawTris)
{
HRESULT hr = 0;
if( _device )
{
_device->SetTransform(D3DTS_WORLD, world);
_device->SetStreamSource(0, _vb, 0, sizeof(TerrainVertex));
_device->SetFVF(TerrainVertex::FVF);
_device->SetIndices(_ib);
_device->SetTexture(0, _tex);
// 不使用光照直到我们开启
_device->SetRenderState(D3DRS_LIGHTING, false);
hr =_device->DrawIndexedPrimitive(
D3DPT_TRIANGLELIST,
0,
0,
_numVertices,
0,
_numTriangles);
_device->SetRenderState(D3DRS_LIGHTING, true);
if( drawTris )
{
_device->SetRenderState(D3DRS_FILLMODE, D3DFILL_WIREFRAME);
hr =_device->DrawIndexedPrimitive(
D3DPT_TRIANGLELIST,
0,
0,
_numVertices,
0,
_numTriangles);
_device->SetRenderState(D3DRS_FILLMODE, D3DFILL_SOLID);
}
if(FAILED(hr))
return false;
}
return true;
}
2.增加一个FPS类(计算帧频)
代码清单:
//////////////////////////////////////////////////////////////////////////////////////////////////
//
// File: fps.h
//
// by tianzhihen
//
// 2008.10.27, MSVC++ 8.0
//
//////////////////////////////////////////////////////////////////////////////////////////////////
#ifndef __fpsH__
#define __fpsH__
#include "d3dfont.h"
class FPSCounter
{
public:
FPSCounter(IDirect3DDevice9* device);
~FPSCounter();
bool render(D3DCOLOR color, float timeDelta);
private:
IDirect3DDevice9* _device;
CD3DFont* _font;
DWORD _frameCnt;
float _timeElapsed;
float _fps;
char _fpsString[9];
};
#endif // __fpsH__
//////////////////////////////////////////////////////////////////////////////////////////////////
//
// File: fps.cpp
//
// by tianzhihen
//
// 2008.10.27, MSVC++ 8.0
//
//////////////////////////////////////////////////////////////////////////////////////////////////
#include "fps.h"
#include <cstdio>
FPSCounter::FPSCounter(IDirect3DDevice9* device)
{
_device = device;
_font = new CD3DFont("Times New Roman", 24, 0);
_font->InitDeviceObjects( _device );
_font->RestoreDeviceObjects();
_frameCnt = 0;
_timeElapsed = 0.0f;
_fps = 0.0f;
}
FPSCounter::~FPSCounter()
{
if( _font )
{
_font->InvalidateDeviceObjects();
_font->DeleteDeviceObjects();
delete _font;
}
}
bool FPSCounter::render(D3DCOLOR color, float timeDelta)
{
if( _font )
{
_frameCnt++;
_timeElapsed += timeDelta;
if(_timeElapsed >= 1.0f)
{
_fps = (float)_frameCnt / _timeElapsed;
sprintf(_fpsString, "%f", _fps);
_fpsString[8] = '/0'; // mark end of string
_timeElapsed = 0.0f;
_frameCnt = 0;
}
_font->DrawText(20, 20, color, _fpsString);
}
return true;
}
3.增加相应DX框架文件。因为FPS类用到了d3dfont.h头文件,因此需添加相应的框架文件。列举如下:
d3dfont.h d3dfont.cpp dxutil.h dxutil.cpp d3dutil.h d3dutil.cpp
4.保持camera类不变。d3dUtility.cpp添加Lerp()函数。
float d3d::Lerp(float a, float b, float t)
{
return a - (a*t) + (b*t);
}
相应的d3dUtility.h须包含此函数声明。
float Lerp(float a, float b, float t);
5.在d3dUtility.h中添加一些颜色常量。
const D3DXCOLOR BEACH_SAND( D3DCOLOR_XRGB(255, 249, 157) );
const D3DXCOLOR DESERT_SAND( D3DCOLOR_XRGB(250, 205, 135) );
const D3DXCOLOR LIGHTGREEN( D3DCOLOR_XRGB( 60, 184, 120) );
const D3DXCOLOR PUREGREEN( D3DCOLOR_XRGB( 0, 166, 81) );
const D3DXCOLOR DARKGREEN( D3DCOLOR_XRGB( 0, 114, 54) );
const D3DXCOLOR LIGHT_YELLOW_GREEN( D3DCOLOR_XRGB(124, 197, 118) );
const D3DXCOLOR PURE_YELLOW_GREEN( D3DCOLOR_XRGB( 57, 181, 74) );
const D3DXCOLOR DARK_YELLOW_GREEN( D3DCOLOR_XRGB( 25, 123, 48) );
const D3DXCOLOR LIGHTBROWN(D3DCOLOR_XRGB(198, 156, 109));
const D3DXCOLOR DARKBROWN( D3DCOLOR_XRGB(115, 100, 87));
相关文章推荐
- DirectX&Direct 3D 游戏开发之——构建3D程序基本框架
- DirectX 3D 基本框架(一)
- DirectX 3D 基本框架(二)
- DirectX 3D 基本框架(五)
- DirectX 3D 基本框架(三)
- Introduction to 3D Game Programming with DirectX 11学习笔记 4.4 演示程序框架
- D3D10基本框架的示例和截图—《3D游戏程序设计入门(DirectX10.0)》
- o3d基本程序框架-(转 这个比我写的全面)
- DirectX 3D_实践之DirectX3D的基本绘制流程
- Directx学习笔记【二】 将win32基本框架封装成类
- DirectX学习笔记--3D基本数学知识整理
- 使用WTL+OGRE编写3D程序(1) - 基本框架
- DirectX 3D_基础之效果框架 手法和路径 HLSL的内置对象(纹理对象 采样器对象与采样器状态 顶点着色器对象和像素着色器对象)效果文件中的设备状态
- DirectX 9.0 3d 初始程序框架
- 逐梦旅程学习笔记 DirectX开发入门01:应用程序基本框架
- Windows 8 Directx开发学习笔记(一)应用基本框架
- vs2010引用DirectX&Direct 3D 混合模式程序集出错解决方案
- 为公司做的基本游戏框架
- MultipeerConnectivity框架,近场通信的基本使用
- 用MFC构造DIRECTX应用框架