您的位置:首页 > 其它

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));
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: