zoukankan      html  css  js  c++  java
  • Ogre1.8地形和天空盒的建立(一块地形)

    转自:http://www.cnblogs.com/WindyMax/

    研究Ogre的程序笔记

    编译环境 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的地形算法,这是一篇相当不错的论文

    关于Ogre地形的代码解释,网上很多高手都已经给出很全面的解释了,我也就不多说了

    #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 )函数设置...= =~~一开始困扰了我很久。

    总得来说,Ogre的源码很适合想了解游戏引擎的新手研究,里面的东西不会很高深,各种设计模式也很值得去学习,无论是不是专业的游戏开发人员。待续...

  • 相关阅读:
    第十四周 Leetcode 315. Count of Smaller Numbers After Self(HARD) 主席树
    POJ1050 To the Max 最大子矩阵
    POJ1259 The Picnic 最大空凸包问题 DP
    POJ 3734 Blocks 矩阵递推
    POJ2686 Traveling by Stagecoach 状态压缩DP
    iOS上架ipa上传问题那些事
    深入浅出iOS事件机制
    iOS如何跳到系统设置里的各种设置界面
    坑爹的私有API
    业务层网络请求封装
  • 原文地址:https://www.cnblogs.com/hnfxs/p/3254670.html
Copyright © 2011-2022 走看看