需要用到的外部图片资源:
在ogre调用时需要多用到的几个外部dll:
OgreTerrain_d.dll
需要添加头文件
#include "Ogre\Ogre.h"
#include "Ogre\OgreFileSystemLayer.h"#include "Ogre\OgreTerrain.h"#include "Ogre\OgreTerrainGroup.h"#include "Ogre\OgreTerrainQuadTreeNode.h"#include "Ogre\OgreTerrainMaterialGeneratorA.h"#include "Ogre\OgreTerrainPaging.h"
定义类初始化需要的结构体
struct CrisTerrainInitStruct
{ CrisTerrainInitStruct():m_scenemanager(NULL),fMaxHoriz(1000),fMinHoriz(0),sMapFilename(""),sElevationFilename(""),fMapSize(TERRAIN_WORLD_SIZE){ fInputScale = fMaxHoriz - fMinHoriz;}SceneManager* m_scenemanager;String sMapFilename; //地图卫星图片String sElevationFilename;//高程图Real fMinHoriz;//最低点Real fMaxHoriz;//最高点Real fMapSize;//地形边长Real fInputScale; //地形高低差 对比像素的0~1 .可以不需要设置//位置放在000点,};
类的外部接口
void Init(CrisTerrainInitStruct* sInitData);
实现的一些重要步骤:
第一步 创建地形全局配置 TerrainGlobalOptions
mTerrainGlobals = OGRE_NEW TerrainGlobalOptions();
//TerrainGlobalOptions是一个类,定义了地形块的一些全局变量和默认值,需要的话我们可以改变他的变量参数,我们后面再做改变。第二步 创建地形分组Ogre::TerrainGroup
//实例化一个TerrainGroup对象
mTerrainGroup = OGRE_NEW TerrainGroup(mSceneMgr, Terrain::ALIGN_X_Z, TERRAIN_SIZE, m_sInitData->fMapSize);
第三步 配置地图块参数 configureTerrainDefaults
configureTerrainDefaults();
第四步 创建地形分块
//defineTerrain方法首先要指定该块地形在地形分组中的索引位置,然后第三个参数必须指定高度数据,用灰度图创建山地地形
for (long x = TERRAIN_PAGE_MIN_X; x <= TERRAIN_PAGE_MAX_X; ++x) for (long y = TERRAIN_PAGE_MIN_Y; y <= TERRAIN_PAGE_MAX_Y; ++y) defineTerrain(x, y, blankTerrain);
下面是我的代码:
头文件:
#pragma once#define DebugTerrain#include "Ogre\Ogre.h"#include "Ogre\OgreFileSystemLayer.h"#include "CrisConfig\CrisConfig.h"#include "Ogre\OgreTerrain.h"#include "Ogre\OgreTerrainGroup.h"#include "Ogre\OgreTerrainQuadTreeNode.h"#include "Ogre\OgreTerrainMaterialGeneratorA.h"#include "Ogre\OgreTerrainPaging.h"//分页多少#define TERRAIN_PAGE_MIN_X 0#define TERRAIN_PAGE_MIN_Y 0#define TERRAIN_PAGE_MAX_X 0#define TERRAIN_PAGE_MAX_Y 0#define TERRAIN_FILE_PREFIX String("testTerrain")#define TERRAIN_FILE_SUFFIX String("dat")#define TERRAIN_WORLD_SIZE 1200.0f#define TERRAIN_SIZE 513using namespace Ogre;struct CrisTerrainInitStruct{ CrisTerrainInitStruct():m_scenemanager(NULL),fMaxHoriz(1000),fMinHoriz(0),sMapFilename(""),sElevationFilename(""),fMapSize(TERRAIN_WORLD_SIZE) { fInputScale = fMaxHoriz - fMinHoriz; } SceneManager* m_scenemanager; String sMapFilename; //地图卫星图片 String sElevationFilename;//高程图 Real fMinHoriz;//最低点 Real fMaxHoriz;//最高点 Real fMapSize;//地形边长 Real fInputScale; //地形高低差 对比像素的0~1 .可以不需要设置//位置放在000点,};class CrisTerrain{public: CrisTerrain(); ~CrisTerrain(); void Init(CrisTerrainInitStruct* sInitData); //void setTerrainImage(const Ogre::String& szCfgFilename = "terrain_texture.jpg");protected: TerrainGlobalOptions* mTerrainGlobals; TerrainGroup* mTerrainGroup; TerrainPaging* mTerrainPaging; PageManager* mPageManager; void testOption();//为了小样例测试加载的,在大工程中可以直接不用private: CrisTerrainInitStruct* m_sInitData; void loadConfigFile(const Ogre::String& szCfgFilename = ""); Ogre::String m_szConfigFileName; CCrisConfigManager m_hConfigMgr; bool mFly; Real mFallVelocity; Real mBrushSizeTerrainSpace; Real mHeightUpdateCountDown; Real mHeightUpdateRate; Vector3 mTerrainPos; bool mTerrainsImported; SceneManager* mSceneMgr; /** @brief 实例化地形 */ void setupContent(); /** @brief 实例化地形参数 */ void configureTerrainDefaults(); void initBlendMaps(Terrain* terrain); void defineTerrain(long x, long y, bool flat = false); void getTerrainImage(bool flipX, bool flipY, Image& img);};
实现文件:
#include "Terrain.h"CrisTerrain::CrisTerrain(): mTerrainGroup(0) , mTerrainPaging(0) , mPageManager(0) , mFallVelocity(0) , mBrushSizeTerrainSpace(0.02) , mHeightUpdateCountDown(0) , mTerrainPos(0,0,0) , mTerrainsImported(false){}CrisTerrain::~CrisTerrain(){}void CrisTerrain::Init(CrisTerrainInitStruct* sInitData){ mSceneMgr = sInitData->m_scenemanager; m_sInitData = sInitData; setupContent(); //loadConfigFile("terrain.cfg");}void CrisTerrain::loadConfigFile(const String& szFilename){ if(!szFilename.empty()) m_szConfigFileName = szFilename; else return; //m_hConfigMgr.LoadFromResourceSystem(m_szConfigFileName); //String worldTexture = m_hConfigMgr.GetValueString("Ter", "WorldTexture", "testter.jpg"); //OutputDebugString(worldTexture.c_str()); }//void CrisTerrain::setTerrainImage(const Ogre::String& szCfgFilename)//{// Terrain::ImportData& defaultimp = mTerrainGroup->getDefaultImportSettings();// defaultimp.terrainSize = TERRAIN_SIZE;//不太了解,调试中,这个值越小,地图边缘锯齿现象越严重,太小的话,运行起来程序会跑死、出错// defaultimp.worldSize = m_sInitData->fMapSize;//假设为a,那么地图大小为 a x a// defaultimp.inputScale = 60;//决定地图最大落差(高度),即位图中白色和黑色部分的高度差// defaultimp.minBatchSize = 33;// defaultimp.maxBatchSize = 65;// // textures// defaultimp.layerList.resize(3);//这里设置了3层纹理,DDS为一种高级的纹理模式,DirectDrawSurface,觉得难以理解的话可以理解为一种特殊的.jpg图片模式,但是用DDS质材的话可以接收并显示地形阴影,用JPG就显示不出来,而且据我调试观察发现,第一个.dds质材是用来显示纹理图形,第二个.dds才是用来接收和显示阴影的//// defaultimp.layerList[0].worldSize = 1;//这个值关系到此贴图的细致程度,太大的话图片被拉伸得很大,看起来模糊// defaultimp.layerList[0].textureNames.push_back(szCfgFilename);// defaultimp.layerList[0].textureNames.push_back(szCfgFilename);// defaultimp.layerList[1].worldSize = 1;// defaultimp.layerList[1].textureNames.push_back(szCfgFilename);// defaultimp.layerList[1].textureNames.push_back(szCfgFilename);// defaultimp.layerList[2].worldSize = 2;// defaultimp.layerList[2].textureNames.push_back(szCfgFilename);// defaultimp.layerList[2].textureNames.push_back(szCfgFilename);//// mTerrainGroup->loadAllTerrains(true);//// if (mTerrainsImported)// {// TerrainGroup::TerrainIterator ti = mTerrainGroup->getTerrainIterator();// while(ti.hasMoreElements())// {// Terrain* t = ti.getNext()->instance;// initBlendMaps(t);// }// }//// mTerrainGroup->freeTemporaryResources();//}void CrisTerrain::testOption(){ //mEditMarker = mSceneMgr->createEntity("editMarker", "sphere.mesh"); //mEditNode = mSceneMgr->getRootSceneNode()->createChildSceneNode(); //mEditNode->attachObject(mEditMarker); //mEditNode->setScale(0.05, 0.05, 0.05); Ogre::FileSystemLayer* mFSLayer = OGRE_NEW_T(Ogre::FileSystemLayer, Ogre::MEMCATEGORY_GENERAL)(OGRE_VERSION_NAME); ResourceGroupManager::getSingleton().createResourceGroup("Terrain"); ResourceGroupManager::getSingleton().addResourceLocation(mFSLayer->getWritablePath(""), "FileSystem", "Terrain", false, false); MaterialManager::getSingleton().setDefaultTextureFiltering(TFO_ANISOTROPIC); MaterialManager::getSingleton().setDefaultAnisotropy(7); //mSceneMgr->setFog(FOG_LINEAR, ColourValue(0.7, 0.7, 0.8), 0, 1000, 2500); LogManager::getSingleton().setLogDetail(LL_BOREME); mSceneMgr->setAmbientLight(ColourValue(0.6, 0.6, 0.6)); create a few entities on the terrain //Entity* e = mSceneMgr->createEntity("tudorhouse.mesh"); //Vector3 entPos(mTerrainPos.x + 2043, 0, mTerrainPos.z + 1715); //Quaternion rot; //entPos.y = mTerrainGroup->getHeightAtWorldPosition(entPos) + 65.5 + mTerrainPos.y; //rot.FromAngleAxis(Degree(Math::RangeRandom(-180, 180)), Vector3::UNIT_Y); //SceneNode* sn = mSceneMgr->getRootSceneNode()->createChildSceneNode(entPos, rot); //sn->setScale(Vector3(0.12, 0.12, 0.12)); //sn->attachObject(e); //mSceneMgr->setSkyBox(true, "Examples/CloudyNoonSkyBox");}void CrisTerrain::setupContent(){ bool blankTerrain = false; //blankTerrain = true; mTerrainGlobals = OGRE_NEW TerrainGlobalOptions(); //TerrainGlobalOptions是一个类,定义了地形块的一些全局变量和默认值,需要的话我们可以改变他的变量参数,我们后面再做改变。#ifdef DebugTerrain testOption();#endif //创建地形分组Ogre::TerrainGroup /*实例化一个TerrainGroup对象 参数1:为他指定场管理器、 参数2:地形的平铺方向,平铺方向一般采用ALIGN_X_Z,也就是采用Y作为高度 参数3:unit16 TERRAINSIZE=2~n+1,比如512+1=513,不符合公式的可能会导致地图显示异常,表示“The size of each terrain down one edge in vertices (2^n+1)”楼主只能理解意思,不能完全正确 表达其中的专有名词,实际调试中,这个参数影响地图边缘的锯齿度,越小锯齿越明显,取值太小 的话,运行会错误; 参数4:Real TERRAINWORLDSIZE,地图大小,表示地图正方形的边长) */ mTerrainGroup = OGRE_NEW TerrainGroup(mSceneMgr, Terrain::ALIGN_X_Z, TERRAIN_SIZE, m_sInitData->fMapSize); //定义命名前缀 mTerrainGroup->setFilenameConvention(TERRAIN_FILE_PREFIX, TERRAIN_FILE_SUFFIX); //设置了该地形组的起始位置,在以后创建的地形块中均采用此位置作为相对位置 mTerrainGroup->setOrigin(mTerrainPos); mTerrainGroup->setResourceGroup("Terrain"); //配置地图块参数 configureTerrainDefaults configureTerrainDefaults(); for (long x = TERRAIN_PAGE_MIN_X; x <= TERRAIN_PAGE_MAX_X; ++x) for (long y = TERRAIN_PAGE_MIN_Y; y <= TERRAIN_PAGE_MAX_Y; ++y) defineTerrain(x, y, blankTerrain); // 开始前加载好 mTerrainGroup->loadAllTerrains(true); if (mTerrainsImported) { TerrainGroup::TerrainIterator ti = mTerrainGroup->getTerrainIterator(); while(ti.hasMoreElements()) { Terrain* t = ti.getNext()->instance; initBlendMaps(t); } } mTerrainGroup->freeTemporaryResources();}void CrisTerrain::getTerrainImage(bool flipX, bool flipY, Image& img){ img.load(m_sInitData->sElevationFilename, ResourceGroupManager::DEFAULT_RESOURCE_GROUP_NAME); if (flipX) img.flipAroundY(); if (flipY) img.flipAroundX();}void CrisTerrain::defineTerrain(long x, long y, bool flat){ // if a file is available, use it // if not, generate file from import // Usually in a real project you'll know whether the compact terrain data is // available or not; I'm doing it this way to save distribution size if (flat) { mTerrainGroup->defineTerrain(x, y, 0.0f); } else { String filename = mTerrainGroup->generateFilename(x, y); if (ResourceGroupManager::getSingleton().resourceExists(mTerrainGroup->getResourceGroup(), filename)) { mTerrainGroup->defineTerrain(x, y); } else { Image img; getTerrainImage(x % 2 != 0, y % 2 != 0, img); mTerrainGroup->defineTerrain(x, y, &img); mTerrainsImported = true; } }}void CrisTerrain::configureTerrainDefaults(){ // Configure global mTerrainGlobals->setMaxPixelError(8); // testing composite map mTerrainGlobals->setCompositeMapDistance(3000);//距离镜头超过3000部分使用地图合成(CompositeMap)模式表现 //mTerrainGlobals->setUseRayBoxDistanceCalculation(true); //mTerrainGlobals->getDefaultMaterialGenerator()->setDebugLevel(1); //mTerrainGlobals->setLightMapSize(256); // Configure default import settings for if we use imported image Terrain::ImportData& defaultimp = mTerrainGroup->getDefaultImportSettings(); defaultimp.terrainSize = TERRAIN_SIZE;//不太了解,调试中,这个值越小,地图边缘锯齿现象越严重,太小的话,运行起来程序会跑死、出错 defaultimp.worldSize = m_sInitData->fMapSize;//假设为a,那么地图大小为 a x a defaultimp.inputScale = m_sInitData->fInputScale;//决定地图最大落差(高度),即位图中白色和黑色部分的高度差 defaultimp.minBatchSize = 33; defaultimp.maxBatchSize = 65; // textures defaultimp.layerList.resize(3);//这里设置了3层纹理,DDS为一种高级的纹理模式,DirectDrawSurface,觉得难以理解的话//可以理解为一种特殊的.jpg图片模式,但是用DDS质材的话可以接收并显示地形阴影,用JPG就显示不出来,而且据我调试观//察发现,第一个.dds质材是用来显示纹理图形,第二个.dds才是用来接收和显示阴影的 defaultimp.layerList[0].worldSize = m_sInitData->fMapSize;//这个值关系到此贴图的细致程度,太大的话图片被拉伸得很大,看起来模糊 defaultimp.layerList[0].textureNames.push_back(m_sInitData->sMapFilename); defaultimp.layerList[0].textureNames.push_back(m_sInitData->sMapFilename); defaultimp.layerList[1].worldSize = m_sInitData->fMapSize; defaultimp.layerList[1].textureNames.push_back("white2.dds"); defaultimp.layerList[1].textureNames.push_back("white2.dds"); defaultimp.layerList[2].worldSize = m_sInitData->fMapSize; defaultimp.layerList[2].textureNames.push_back("white2.dds"); defaultimp.layerList[2].textureNames.push_back("white2.dds"); //defaultimp.layerList[0].worldSize = 100;//这个值关系到此贴图的细致程度,太大的话图片被拉伸得很大,看起来模糊 //defaultimp.layerList[0].textureNames.push_back("dirt_grayrocky_diffusespecular.dds"); //defaultimp.layerList[0].textureNames.push_back("dirt_grayrocky_normalheight.dds"); //defaultimp.layerList[1].worldSize = 30; //defaultimp.layerList[1].textureNames.push_back("grass_green-01_diffusespecular.dds"); //defaultimp.layerList[1].textureNames.push_back("grass_green-01_normalheight.dds"); //defaultimp.layerList[2].worldSize = 100; //defaultimp.layerList[2].textureNames.push_back("growth_weirdfungus-03_diffusespecular.dds"); //defaultimp.layerList[2].textureNames.push_back("growth_weirdfungus-03_normalheight.dds");}void CrisTerrain::initBlendMaps(Terrain* terrain){ TerrainLayerBlendMap* blendMap0 = terrain->getLayerBlendMap(1); TerrainLayerBlendMap* blendMap1 = terrain->getLayerBlendMap(2); Real minHeight0 = 70; Real fadeDist0 = 40; Real minHeight1 = 70; Real fadeDist1 = 15; float* pBlend1 = blendMap1->getBlendPointer(); for (Ogre::uint16 y = 0; y < terrain->getLayerBlendMapSize(); ++y) { for (Ogre::uint16 x = 0; x < terrain->getLayerBlendMapSize(); ++x) { Real tx, ty; blendMap0->convertImageToTerrainSpace(x, y, &tx, &ty); Real height = terrain->getHeightAtTerrainPosition(tx, ty); Real val = (height - minHeight0) / fadeDist0; Math::Clamp(val, (Real)0, (Real)1); val = (height - minHeight1) / fadeDist1; val = Math::Clamp(val, (Real)0, (Real)1); *pBlend1++ = val; } } blendMap0->dirty(); blendMap1->dirty(); //blendMap0->loadImage("blendmap1.png", ResourceGroupManager::DEFAULT_RESOURCE_GROUP_NAME); blendMap0->update(); blendMap1->update(); // set up a colour map /* if (!terrain->getGlobalColourMapEnabled()) { terrain->setGlobalColourMapEnabled(true); Image colourMap; colourMap.load("testcolourmap.jpg", ResourceGroupManager::DEFAULT_RESOURCE_GROUP_NAME); terrain->getGlobalColourMap()->loadImage(colourMap); } */}