您的位置:首页 > 其它

Ogre1.8地形和天空盒的建立过程详解(一块地形)

2013-08-13 10:55 357 查看
编译环境 WIN7 32 VS2008 Ogre的版本 1.8

Ogre的地形算法是采用Geometry MIPMap的算法,当然贴图也是采用MIPMap的算法,这里有Ogre LOD算法的论文解释:http://www.flipcode.com/articles/article_geomipmaps.pdf

看到Ogre的Terrain,突然也想自己实现一个地形的打算,不过估计要过一段时间了,现在来说,ClipMap算法应该更适应现在的游戏,具体的内容可以查看http://www.docin.com/p-118698727.html,对于了解现在LOD的地形算法,这是一篇相当不错的论文

为了简化,就一个main.cpp文件,这个cpp文件中包含了监听器类和Application类以及main入口函数:

#include <Ogre.h>

#include <OIS/OIS.h>

#include <iostream>

#include <OgreTerrain.h>

#include <OgreTerrainLayerBlendMap.h>

#include <OgreTerrainGroup.h>

class MyFrameListener : public Ogre::FrameListener

{

private:

OIS::InputManager *m_pInputManage;

OIS::Keyboard *m_pKeyBoard;

OIS::Mouse *m_pMouse;

Ogre::Camera *m_pCamera;

Ogre::Viewport *m_pViewport;

Ogre::Timer m_Time;

bool m_bWirmline;

float m_fMovementSpeed;

public:

MyFrameListener( Ogre::RenderWindow *pWin, Ogre::Camera *pCamera, Ogre::Viewport *pViewport )

{

m_pCamera = pCamera;

m_fMovementSpeed = 10;

m_Time.reset();

m_pViewport = pViewport;

m_bWirmline = true;

OIS::ParamList Params;

size_t WindowHandle = 0;

std::ostringstream WinHandleString;

pWin->getCustomAttribute( "WINDOW", &WindowHandle );

WinHandleString<<WindowHandle;

Params.insert( std::make_pair( "WINDOW", WinHandleString.str() ) );

m_pInputManage = OIS::InputManager::createInputSystem( Params );

m_pKeyBoard = static_cast<OIS::Keyboard*>( m_pInputManage->createInputObject( OIS::OISKeyboard, false ) );

m_pMouse = static_cast<OIS::Mouse*>( m_pInputManage->createInputObject( OIS::OISMouse, false ) );

}

~MyFrameListener()

{

m_pInputManage->destroyInputObject( m_pKeyBoard );

m_pInputManage->destroyInputObject( m_pMouse );

OIS::InputManager::destroyInputSystem( m_pInputManage );

}

bool frameStarted( const Ogre::FrameEvent& evt )

{

m_pKeyBoard->capture();

bool bWalk = false;

if( m_pKeyBoard->isKeyDown( OIS::KC_ESCAPE ) )

{

return false;

}

if( m_pKeyBoard->isKeyDown( OIS::KC_R ) && m_Time.getMilliseconds() > 250 )

{

m_Time.reset();

if( m_bWirmline )

{

m_pCamera->setPolygonMode( Ogre::PolygonMode::PM_WIREFRAME );

m_bWirmline = false;

}

else

{

m_pCamera->setPolygonMode( Ogre::PolygonMode::PM_SOLID );

m_bWirmline = true;

}

}

Ogre::Vector3 translate( 0, 0, 0 );

if( m_pKeyBoard->isKeyDown( OIS::KC_W ) )

{

translate += Ogre::Vector3( 0, 0, -1 );

}

if( m_pKeyBoard->isKeyDown( OIS::KC_S ) )

{

translate += Ogre::Vector3( 0, 0, 1 );

}

if( m_pKeyBoard->isKeyDown( OIS::KC_D ) )

{

translate += Ogre::Vector3( 1, 0, 0 );

}

if( m_pKeyBoard->isKeyDown( OIS::KC_A ) )

{

translate += Ogre::Vector3( -1, 0, 0 );

}

m_pCamera->moveRelative( translate * m_fMovementSpeed * evt.timeSinceLastFrame * m_fMovementSpeed * 8 );

m_pMouse->capture();

float fDotX = m_pMouse->getMouseState().X.rel * evt.timeSinceLastFrame * -1;

float fDotY = m_pMouse->getMouseState().Y.rel * evt.timeSinceLastFrame * -1;

m_pCamera->yaw( Ogre::Radian( fDotX ) );

m_pCamera->pitch( Ogre::Radian( fDotY ) );

return true;

}

bool frameRenderingQueued( const Ogre::FrameEvent& evt )

{

return true;

}

bool frameEnded( const Ogre::FrameEvent& evt)

{

return true;

}

};

class MyApplication

{

private:

Ogre::Root *m_pRoot;

Ogre::SceneManager *m_pSceneManage;

MyFrameListener *m_pFrameListener;

bool m_bKeepRunning;

Ogre::TerrainGlobalOptions *m_pTerrGloOp;

Ogre::TerrainGroup *m_pTerrGroup;

bool m_bLoadNewMap;

public:

MyApplication()

: m_pRoot( NULL ),

m_pSceneManage( NULL ),

m_pFrameListener( NULL ),

m_bKeepRunning( true ),

m_pTerrGloOp( NULL ),

m_bLoadNewMap( false )

{

}

~MyApplication()

{

if( m_pTerrGloOp )

{

delete m_pTerrGloOp;

}

if( m_pTerrGroup )

{

delete m_pTerrGroup;

}

if( m_pRoot )

{

delete m_pRoot;

m_pRoot = NULL;

}

}

void RenderOneFrame()

{

Ogre::WindowEventUtilities::messagePump();

m_bKeepRunning = m_pRoot->renderOneFrame();

}

bool KeepRunning()

{

return m_bKeepRunning;

}

void LoadResources()

{

Ogre::ConfigFile cf;

cf.load( "resources_d.cfg" );

Ogre::ConfigFile::SectionIterator SecIter = cf.getSectionIterator();

Ogre::String SectionName, DataName, TypeName;

while( SecIter.hasMoreElements() )

{

SectionName = SecIter.peekNextKey();

Ogre::ConfigFile::SettingsMultiMap *SetMap = SecIter.getNext();

Ogre::ConfigFile::SettingsMultiMap::iterator SetIter;

for( SetIter = SetMap->begin(); SetIter != SetMap->end(); ++SetIter )

{

TypeName = SetIter->first;

DataName = SetIter->second;

Ogre::ResourceGroupManager::getSingleton().addResourceLocation( DataName, TypeName, SectionName );

}

}

Ogre::ResourceGroupManager::getSingleton().initialiseAllResourceGroups();

}

int StartUp()

{

if( !m_pRoot )

{

m_pRoot = new Ogre::Root( "plugins_d.cfg" );

if( !m_pRoot->showConfigDialog() )

{

return -1;

}

}

Ogre::RenderWindow *pWindow = m_pRoot->initialise( true );

m_pSceneManage = m_pRoot->createSceneManager( Ogre::ST_GENERIC );

Ogre::Camera *pCamera = m_pSceneManage->createCamera( "Camera1" );

pCamera->setPosition( 0, 1400, 100 );

pCamera->lookAt( 0, 0, 0 );

pCamera->setNearClipDistance( 5 );

Ogre::Viewport *pViewport = pWindow->addViewport( pCamera );

pViewport->setBackgroundColour( Ogre::ColourValue( 0, 0, 0, 1 ) );

pCamera->setAspectRatio( Ogre::Real( pViewport->getActualWidth() ) / Ogre::Real( pViewport->getActualHeight() ) );

LoadResources();

CreateScene();

m_pFrameListener = new MyFrameListener( pWindow, pCamera, pViewport );

m_pRoot->addFrameListener( m_pFrameListener );

return 0;

}

void ConfigureTerrain( Ogre::Light *pLight )

{

m_pTerrGloOp = new Ogre::TerrainGlobalOptions();

m_pTerrGloOp->setMaxPixelError( 8 );

m_pTerrGloOp->setCompositeMapDistance( 3000 );

m_pTerrGloOp->setCompositeMapAmbient( m_pSceneManage->getAmbientLight() );

m_pTerrGloOp->setLightMapDirection( pLight->getDerivedDirection() );

m_pTerrGloOp->setCompositeMapDiffuse( pLight->getDiffuseColour() );

m_pTerrGroup = new Ogre::TerrainGroup( m_pSceneManage, Ogre::Terrain::ALIGN_X_Z, 513, 12000 );

m_pTerrGroup->setFilenameConvention( Ogre::String( "SaveTerrain" ), Ogre::String( "dat" ) );

m_pTerrGroup->setOrigin( Ogre::Vector3::ZERO );

Ogre::Terrain::ImportData &Imp = m_pTerrGroup->getDefaultImportSettings();

Imp.maxBatchSize = 65; //一个tile中最多包含的顶点数

Imp.minBatchSize = 33; //一个tile中最少包含的顶点数

Imp.inputScale = 600;

Imp.layerList.resize( 3 );

Imp.layerList[0].worldSize = 100;

Imp.layerList[0].textureNames.push_back( "dirt_grayrocky_diffusespecular.dds" );

Imp.layerList[0].textureNames.push_back( "dirt_grayrocky_normalheight.dds" );

Imp.layerList[1].worldSize = 30;

Imp.layerList[1].textureNames.push_back( "grass_green-01_diffusespecular.dds" );

Imp.layerList[1].textureNames.push_back( "grass_green-01_normalheight.dds" );

Imp.layerList[2].worldSize = 200;

Imp.layerList[2].textureNames.push_back( "growth_weirdfungus-03_diffusespecular.dds" );

Imp.layerList[2].textureNames.push_back( "growth_weirdfungus-03_normalheight.dds" );

}

void InitBlend( Ogre::Terrain *pTerrain )

{

Ogre::TerrainLayerBlendMap *pBlend1 = pTerrain->getLayerBlendMap( 1 );

Ogre::TerrainLayerBlendMap *pBlend2 = pTerrain->getLayerBlendMap( 2 );

Ogre::Real MinHeight1 = 70;

Ogre::Real FadeDist1 = 40;

Ogre::Real MinHeight2 = 70;

Ogre::Real FadeDist2 = 15;

float *pBlend1Point = pBlend1->getBlendPointer();

float *pBlend2Point = pBlend2->getBlendPointer();

for( Ogre::uint16 y = 0; y < pTerrain->getLayerBlendMapSize(); ++y )

{

for( Ogre::uint16 x = 0; x <pTerrain->getLayerBlendMapSize(); ++x )

{

Ogre::Real tx, ty;

pBlend1->convertImageToTerrainSpace( x, y, &tx, &ty );

Ogre::Real height = pTerrain->getHeightAtTerrainPosition( tx, ty );

Ogre::Real val = ( height - MinHeight1 ) / FadeDist1;

val = Ogre::Math::Clamp( val, static_cast<Ogre::Real>( 0 ), static_cast<Ogre::Real>( 1 ) );

*pBlend1Point++ = val;

val = ( height - MinHeight2 ) / FadeDist2;

val = Ogre::Math::Clamp( val, static_cast<Ogre::Real>( 0 ), static_cast<Ogre::Real>( 1 ) );

*pBlend2Point++ = val;

}

}

pBlend1->dirty();

pBlend2->dirty();

pBlend1->update();

pBlend2->update();

}

void GetTerrainImage( bool bFlipx, bool bFlipy, Ogre::Image &img )

{

img.load( "terrain.png", Ogre::ResourceGroupManager::DEFAULT_RESOURCE_GROUP_NAME );

if( bFlipx )

{

img.flipAroundY();

}

if( bFlipy )

{

img.flipAroundX();

}

}

void DefineTerrain( long x, long y )

{

Ogre::String FileName = m_pTerrGroup->generateFilename( x, y );

if( Ogre::ResourceGroupManager::getSingleton().resourceExists( m_pTerrGroup->getResourceGroup(), FileName ) )

{

m_pTerrGroup->defineTerrain( x, y );

}

else

{

Ogre::Image img;

GetTerrainImage( x % 2, y % 2, img );

m_pTerrGroup->defineTerrain( x, y, &img );

m_bLoadNewMap = true;

}

}

void CreateScene()

{

Ogre::Light *pLight = m_pSceneManage->createLight( "Light1" );

pLight->setType( Ogre::Light::LT_DIRECTIONAL );

pLight->setDirection( Ogre::Vector3(0.55, -0.3, 0.75) );

pLight->setSpecularColour( Ogre::ColourValue( 0.4f, 0.4f, 0.4f ) );

pLight->setDiffuseColour( Ogre::ColourValue::White );

m_pSceneManage->setAmbientLight( Ogre::ColourValue( 0.2f, 0.2f, 0.2f ) );

ConfigureTerrain( pLight );

DefineTerrain( 0, 0 );

m_pTerrGroup->loadAllTerrains( true );

Ogre::TerrainGroup::TerrainIterator iter = m_pTerrGroup->getTerrainIterator();

while( iter.hasMoreElements() )

{

Ogre::Terrain *t = iter.getNext()->instance;

InitBlend( t );

}

if( m_bLoadNewMap )

{

//如果要反复修改TerrainGroup的数据,就不必保存地形了

m_pTerrGroup->saveAllTerrains( true ); //注意,保存的是地形顶点和TerrainGroup的数据,TerrainGlobalOption的数据不会被保存

m_bLoadNewMap =false;

}

m_pTerrGroup->freeTemporaryResources();

Ogre::ColourValue FadeColour( 0.9, 0.9, 0.9 );

m_pSceneManage->setFog( Ogre::FOG_LINEAR, FadeColour, 0.0f, 15000.0f, 28000.0f );

Ogre::Plane plane;

plane.d = 1000;

plane.normal = Ogre::Vector3::NEGATIVE_UNIT_Y;

m_pSceneManage->_setSkyPlane( true, plane, "Examples/CloudySky", 500, 20, true, 0.5f, 150, 150 );

}

};

int main()

{

MyApplication app;

app.StartUp();

while( app.KeepRunning() )

{

app.RenderOneFrame();

}

return 0;

}

  

不过在这里主要讲下Terrain::getLayerBlendMapSize()函数,这个函数返回的是Terrain的mLayerBlendMapSize。一开始没有设置的话,mLayerBlendMapSize默认是1024。也就是说将Blend Layer平铺完这个地形,然后分成1024个“区域”,然后计算高度平铺适合的纹理,混合等。可以通过Ogre::TerrainGlobalOptions::setLayerBlendMapSize( value )函数设置。

参考:http://www.cnblogs.com/WindyMax/

截图:

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