利用SimpleRenderable实现DirectX 9 3D 游戏设计入门中 第十三章 地形渲染基础的简单地形,只是简单的实现了地形的基本框架,顶点,索引,纹理等,为简单起见高度都为1,适合新手做入门的学习,高手可以飘过了,效果图:
Terrain.h:
#ifndef _TERRAIN_H_ #define _TERRAIN_H_ #include <Ogre.h> #include "Common.h" using namespace Ogre; #define VERTEX_POS_BINDING 0 class CTerrain :public SimpleRenderable { public: //numVertsPerCol,numVertsPerRow为奇数时m_width,m_depth必定为偶数 CTerrain(int numVertsPerRow=513,int numVertsPerCol=513,int cellSize=10,float heightScal=1.0f); ~CTerrain(); public: bool InitData(); void LoadHeightmap(); void CreateVertexData(); void CreateIndexData(); // Overridden from MovableObject virtual Real getBoundingRadius() const; virtual const AxisAlignedBox& getBoundingBox() const; // Overridden from Renderable virtual Real getSquaredViewDepth(const Ogre::Camera* cam) const; private: String m_heightMapPath;//高度图 float *m_heightMap;//高度数据 float m_heightScal;//高度缩放值 int m_numVertsPerRow;//每行顶点数 int m_numVertsPerCol;//每列顶点数 int m_numCellsPerRow;//每行格子数 int m_numCellsPerCol;//每列格子数 int m_cellSize;//格子边长 int m_numVerts;//顶点总数 int m_numTriangles;//三角形总数 int m_width;//地形宽度 int m_depth;//地形深度 bool m_bSaveData;//是否保存顶点信息 AxisAlignedBox mAABB; Real mBoundingRadius; VertexData *pVertexData; IndexData *pIndexData; }; #endif
Terrain.cpp:
#include "Terrain.h" #include <fstream> CTerrain::CTerrain(int numVertsPerRow,int numVertsPerCol,int cellSize,float heightScal) { m_numVertsPerRow=numVertsPerRow; m_numVertsPerCol=numVertsPerCol; m_heightScal=heightScal; m_cellSize=cellSize; m_heightMapPath=""; m_bSaveData=true; m_numCellsPerRow=m_numVertsPerRow-1; m_numCellsPerCol=m_numVertsPerCol-1; m_numVerts=m_numVertsPerRow*m_numVertsPerCol; m_numTriangles=m_numCellsPerRow*m_numCellsPerCol*2; m_width=m_numCellsPerRow*m_cellSize; m_depth=m_numCellsPerCol*m_cellSize; m_heightMap=new float[m_numVerts]; } CTerrain::~CTerrain() { safeDelArry(m_heightMap); OGRE_DELETE(mRenderOp.vertexData); OGRE_DELETE(mRenderOp.indexData); } bool CTerrain::InitData() { LoadHeightmap(); CreateVertexData(); CreateIndexData(); return true; } void CTerrain::LoadHeightmap() { for (int i=0;i<m_numVerts;i++) { m_heightMap[i]=1.0f; } } void CTerrain::CreateVertexData() { mRenderOp.vertexData=new VertexData(); pVertexData=mRenderOp.vertexData; pVertexData->vertexCount=m_numVerts; pVertexData->vertexStart=0; mRenderOp.operationType=RenderOperation::OT_TRIANGLE_LIST; mRenderOp.useIndexes=true; VertexDeclaration *decl=pVertexData->vertexDeclaration; VertexBufferBinding *bind=pVertexData->vertexBufferBinding; size_t vOffset=0,textCoordSet=0; decl->addElement(0,vOffset,VET_FLOAT3,VES_POSITION); vOffset=vOffset+VertexElement::getTypeSize(VET_FLOAT3); decl->addElement(0,vOffset,VET_COLOUR,VES_DIFFUSE); vOffset += Ogre::VertexElement::getTypeSize(Ogre::VET_COLOUR); decl->addElement(0,vOffset,VET_FLOAT2,VES_TEXTURE_COORDINATES,textCoordSet++); vOffset=vOffset+VertexElement::getTypeSize(VET_FLOAT2); decl->addElement(0,vOffset,VET_FLOAT2,VES_TEXTURE_COORDINATES,textCoordSet++); HardwareVertexBufferSharedPtr pVerBuff; pVerBuff=HardwareBufferManager::getSingleton().createVertexBuffer(decl->getVertexSize(0),m_numVerts,HardwareBuffer::HBU_STATIC_WRITE_ONLY,false); float *pLock=static_cast<float *>(pVerBuff->lock(0,pVerBuff->getSizeInBytes(),HardwareBuffer::HBL_DISCARD)); RGBA colour,*pColour; RenderSystem *rs=Ogre::Root::getSingleton().getRenderSystem(); rs->convertColourValue(ColourValue(1.0f,1.0f,1.0f),&colour); float start_x,end_x,start_z,end_z; int index=0; start_x=-m_width/2; end_x=-start_x; start_z=-m_depth/2; end_z=-start_z; std::ofstream of; bool bopen=false; if (m_bSaveData) { of.open(L"vertexInfo.txt",std::ios::out|std::ios::trunc); if (of.is_open()) { bopen=true; of<<"------------------------------------------ "; of<<"vertex data info: "; }else { MessageBox( NULL, L"INFO",L"An exception has occured!", MB_OK | MB_ICONERROR | MB_TASKMODAL); } } float y=0.0f,tu=0.0f,tv=0.0f; int h=0,c=0; char tmepChar[128]={0}; for (float z=start_z;z<=end_z;z+=m_cellSize) { tu=h*m_cellSize/(float)m_width; h++; c=0; for (float x=start_x;x<=end_x;x+=m_cellSize) { tv=c*m_cellSize/(float)m_depth; c++; y=m_heightMap[index++]; *pLock=x; pLock++; *pLock=y; pLock++; *pLock=z; pLock++; pColour=static_cast<RGBA *>(static_cast<void *>(pLock)); *pColour=colour; pColour++; pLock=static_cast<float *>(static_cast<void *>(pColour)); *pLock=tu; pLock++; *pLock=tv; pLock++; *pLock=tu; pLock++; *pLock=tv; pLock++; if (m_bSaveData&&bopen) { sprintf(tmepChar,"x=%f y=%f z=%f u=%f v=%f ",x,y,z,tu,tv); of<<tmepChar; } } } pVerBuff->unlock(); bind->setBinding(0,pVerBuff); if (m_bSaveData&&bopen) of.close(); float boxHeght=20.0f; float vertices[8][3] = { start_x, boxHeght, start_z, // A -start_x, boxHeght, start_z, // B start_x, boxHeght, -start_z, // C -start_x, boxHeght, -start_z, // D start_x, boxHeght, start_z, // A -start_x, boxHeght, start_z, // B start_x, boxHeght, -start_z, // C -start_x, boxHeght, -start_z, // D }; for (int i=0;i<8;i++) { mAABB.merge(Ogre::Vector3(vertices[i][0], vertices[i][1], vertices[i][2])); } mBoundingRadius = Ogre::Math::boundingRadiusFromAABB(mAABB); } /*A---------B - - - - - - C-----------D */ void CTerrain::CreateIndexData() { mRenderOp.indexData=new IndexData(); pIndexData=mRenderOp.indexData; pIndexData->indexStart=0; pIndexData->indexCount=m_numTriangles*3; pIndexData->indexBuffer=HardwareBufferManager::getSingleton().createIndexBuffer(HardwareIndexBuffer::IT_16BIT,pIndexData->indexCount,HardwareBuffer::HBU_STATIC_WRITE_ONLY); unsigned short *pIndexLock=static_cast<unsigned short *>(pIndexData->indexBuffer->lock(0, pIndexData->indexBuffer->getSizeInBytes(),HardwareBuffer::HBL_DISCARD)); std::ofstream of; bool bopen=false; if (m_bSaveData) { of.open(L"indexInfo.txt",std::ios::out|std::ios::trunc); if (of.is_open()) { bopen=true; of<<"------------------------------------------ "; of<<"index data info: "; }else { MessageBox( NULL, L"INFO",L"An exception has occured!", MB_OK | MB_ICONERROR | MB_TASKMODAL); } } char tmepChar[128]={0}; unsigned short uvalue[6]; int index=0; for (unsigned short row=0;row<m_numCellsPerCol;row++) { for (unsigned short col=0;col<m_numCellsPerRow;col++) { //ACB uvalue[0]=row*m_numVertsPerRow+col; *pIndexLock=uvalue[0]; pIndexLock++; uvalue[1]=(row+1)*m_numVertsPerRow+col; *pIndexLock=uvalue[1]; pIndexLock++; uvalue[2]=row*m_numVertsPerRow+col+1;// *pIndexLock=uvalue[2]; pIndexLock++; //CDB uvalue[3]=uvalue[1]; uvalue[5]=uvalue[2]; uvalue[4]=(row+1)*m_numVertsPerRow+col+1; *pIndexLock=uvalue[3]; pIndexLock++; *pIndexLock=uvalue[4]; pIndexLock++; *pIndexLock=uvalue[5]; pIndexLock++; if (m_bSaveData&&bopen) { for (int j=0;j<6;j++) { sprintf(tmepChar,"index%d=%u ",index++,uvalue[j]); of<<tmepChar; if (j==5) { of<<std::endl; } } } } } pIndexData->indexBuffer->unlock(); if (m_bSaveData&&bopen) { of.close(); } } Real CTerrain::getBoundingRadius() const { return mBoundingRadius; } Real CTerrain::getSquaredViewDepth(const Ogre::Camera* cam) const { assert(mParentNode); return mParentNode->getSquaredViewDepth(cam); } const AxisAlignedBox& CTerrain::getBoundingBox() const { return mAABB; }
创建地形:
void CApplication::CreateTerrain() { pTerrain=new CTerrain(65,65,10,1.0f); pTerrain->InitData(); pTerrain->setMaterial("Examples/Terrain_Material"); SceneNode *node =pSceneManager->getRootSceneNode()->createChildSceneNode("TerrainNode",Vector3(0,0,0)); node->attachObject(pTerrain); node->showBoundingBox(true); }
材质:
material Examples/Terrain_Material : Examples/OgreDance { technique { pass { lighting off //scene_blend alpha_blend //cull_hardware none //cull_software none texture_unit { texture dirt_grayrocky_diffusespecular.dds tex_address_mode wrap } texture_unit { //colour_op_ex add src_texture src_current //colour_op_multipass_fallback one one texture grass_green-01_diffusespecular.dds tex_address_mode wrap } } } }