博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
[Ogre][地形][原创]基于OgreTerrain的地形实现
阅读量:7002 次
发布时间:2019-06-27

本文共 13065 字,大约阅读时间需要 43 分钟。

 需要用到的外部图片资源:

 

在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);	}	*/}

  

 

转载地址:http://rqevl.baihongyu.com/

你可能感兴趣的文章
Eclipse中安装Maven插件 M2eclipse
查看>>
java日期时间处理小结
查看>>
在 Ubuntu 中安装 MySQL 指南
查看>>
Java你不知道的那些事儿—Java隐藏特性(上)
查看>>
DBA_实践指南系列8_Oracle Erp R12数据维护模式Adadmin(案例)
查看>>
iOS应用的真机调试
查看>>
Revit API注册事件
查看>>
乐在其中设计模式(C#) - 状态模式(State Pattern)
查看>>
【原创】构建高性能ASP.NET站点 第六章—性能瓶颈诊断与初步调优(上篇)—识别性能瓶颈...
查看>>
实现 iPhone 电子书的分页显示功能的代码
查看>>
JFACE-SWT开发记录
查看>>
比NotePad++更好的文本代码(C#)编辑器Sublime Text
查看>>
linux下查找文件并按时间顺序排序的方法
查看>>
修改android studio中的avd sdk路径、avd sdk找不到的解决方案
查看>>
FDDI即光纤分布式数据接口
查看>>
0天掌握iOS开发之Day2 - 内存管理 (给学生讲解的课件,总结的不错)...
查看>>
jquery的ajax同步和异步的理解及示例
查看>>
hdu 1698:Just a Hook(线段树,区间更新)
查看>>
[leetcode] Path sum路径之和
查看>>
angular学习笔记(十六) -- 过滤器(2)
查看>>