第三章 Terrain, Sky, and Fog

BasicTutorial3_manual.h


#ifndef __BasicTutorial3_h_
#define __BasicTutorial3_h_
//1 begin
#include <OgreTerrain.h>
#include <OgreTerrainGroup.h>
//1 end
#include "BaseApplication.h"
#if OGRE_PLATFORM == OGRE_PLATFORM_WIN32

#endif


class BasicTutorial3 : public BaseApplication
{
//1 begin
private:
	Ogre::TerrainGlobalOptions* mTerrainGlobals;
	Ogre::TerrainGroup* mTerrainGroup;
	bool mTerrainImported;
	void defineTerrain(long x,long y);
	void initBlendMaps(Ogre::Terrain* terrain);
	void configureTerrainDefaults(Ogre::Light* light);
	//part2 1 begin
	OgreBites::Label* mInfoLabel;
	//part2 1 end
//1 end
public:
    BasicTutorial3(void);
    virtual ~BasicTutorial3(void);

protected:
    virtual void createScene(void);
	virtual void createFrameListener(void);
	virtual void destroyScene(void);
	virtual bool frameRenderingQueued(const Ogre::FrameEvent& evt);

};

#endif // #ifndef __BasicTutorial3_h_

BasicTutorial3_manual.cpp

#include "BasicTutorial3_manual.h"

//-------------------------------------------------------------------------------------
BasicTutorial3::BasicTutorial3(void)
{
}
//-------------------------------------------------------------------------------------
BasicTutorial3::~BasicTutorial3(void)
{
}
//1 begin
void BasicTutorial3::destroyScene(void)
{
	//part2 3 begin
	OGRE_DELETE mTerrainGroup;
	OGRE_DELETE mTerrainGlobals;
	//part2 3 end
}
void getTerrainImage(bool flipX,bool flipY,Ogre::Image& img)
{
	//5 begin : get Terrain Image
	img.load("terrain.png",Ogre::ResourceGroupManager::DEFAULT_RESOURCE_GROUP_NAME);
	if(flipX)
		img.flipAroundY();
	if(flipY)
		img.flipAroundX();
	//5 end

}
void BasicTutorial3::defineTerrain(long x,long y)
{
	//4 begin : define terrain
	Ogre::String filename = mTerrainGroup->generateFilename(x,y);
	if(Ogre::ResourceGroupManager::getSingleton().resourceExists(mTerrainGroup->getResourceGroup(),filename))
	{
		mTerrainGroup->defineTerrain(x,y);
	}
	else
	{
		Ogre::Image img;
		getTerrainImage(x%2!=0,y%2!=0,img);
		mTerrainGroup->defineTerrain(x,y,&img);
		mTerrainImported=true;

	}
	//4 end
}
void BasicTutorial3::initBlendMaps(Ogre::Terrain* terrain)
{
	//6 begin:init Blend Maps
	Ogre::TerrainLayerBlendMap* blendMap0 = terrain->getLayerBlendMap(1);
	Ogre::TerrainLayerBlendMap* blendMap1 = terrain->getLayerBlendMap(2);
	Ogre::Real minHeight0=70;
	Ogre::Real fadeDist0=40;
	Ogre::Real minHeight1=70;
	Ogre::Real fadeDist1=15;
	float* pBlend0=blendMap0->getBlendPointer();
	float* pBlend1=blendMap1->getBlendPointer();
	for(Ogre::uint16 y=0;y<terrain->getLayerBlendMapSize();++y)
	{
		for(Ogre::uint16 x=0;x<terrain->getLayerBlendMapSize();++x)
		{
			Ogre::Real tx,ty;
			blendMap0->convertImageToTerrainSpace(x,y,&tx,&ty);
			Ogre::Real height = terrain->getHeightAtTerrainPosition(tx,ty);
			Ogre::Real val=(height-minHeight0)/fadeDist0;
			val=Ogre::Math::Clamp(val,(Ogre::Real)0,(Ogre::Real)1);
			*pBlend0++=val;
			val = (height-minHeight1)/fadeDist1;
			val=Ogre::Math::Clamp(val,(Ogre::Real)0,(Ogre::Real)1);
			*pBlend1++=val;
		}
	}
	blendMap0->dirty();
	blendMap1->dirty();
	blendMap0->update();
	blendMap1->update();

	//6 end
}
void BasicTutorial3::configureTerrainDefaults(Ogre::Light* light)
{
	//3 begin : configure Terrain Defaults
	mTerrainGlobals->setMaxPixelError(8);
	//MaxPixelError decides how precise our terrain is going to be. A lower number will mean a more accurate terrain, at the cost of performance
	mTerrainGlobals->setCompositeMapDistance(3000);//CompositeMapDistance decides how far the Ogre terrain will render the lightmapped terrain.
	mTerrainGlobals->setLightMapDirection(light->getDerivedDirection());
	mTerrainGlobals->setCompositeMapAmbient(mSceneMgr->getAmbientLight());
	mTerrainGlobals->setCompositeMapDiffuse(light->getDiffuseColour());
	Ogre::Terrain::ImportData& defaultimp=mTerrainGroup->getDefaultImportSettings();
	defaultimp.terrainSize=513;
	defaultimp.worldSize=12000.0f;
	defaultimp.inputScale=600;
	defaultimp.minBatchSize=33;
	defaultimp.maxBatchSize=65;
	defaultimp.layerList.resize(3);
	defaultimp.layerList[0].worldSize=100;
	//'worldSize' decides how big each splat of textures is going to be. A smaller value will increase the resolution of the rendered texture layer.
	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("greass_green-01_normalheight.dds");
	defaultimp.layerList[2].worldSize=200;
	defaultimp.layerList[2].textureNames.push_back("growth_weirdfungus-03_diffusespecular.dds");
	defaultimp.layerList[2].textureNames.push_back("growth_weirdfungus-03_normalheight.dds");
	/*
	The default material generator takes two textures per layer:

	diffuse_specular - diffuse texture with a specular map in the alpha channel
	normal_height - normal map with a height map in the alpha channel
	*/
	//3 end
}
void BasicTutorial3::createScene(void)
{
	//2 begin :First, let's modify our Camera object for our terrain. 
	mCamera->setPosition(Ogre::Vector3(1683,50,2116));
	mCamera->lookAt(Ogre::Vector3(1685,50,2116));
	mCamera->setNearClipDistance(0.1);
	mCamera->setFarClipDistance(50000);
	if(mRoot->getRenderSystem()->getCapabilities()->hasCapability(Ogre::RSC_INFINITE_FAR_PLANE))
	{
		mCamera->setFarClipDistance(0);//enable infinite far clip distance if we can
	}
	Ogre::Vector3 lightdir(0.55f,-0.3,0.75f);
	lightdir.normalise();
	Ogre::Light* light=mSceneMgr->createLight("tstLight");
	light->setType(Ogre::Light::LT_DIRECTIONAL);
	light->setDirection(lightdir);
	light->setDiffuseColour(Ogre::ColourValue::White);
	light->setSpecularColour(Ogre::ColourValue(0.4f,0.4f,0.4f));
	mTerrainGlobals=OGRE_NEW Ogre::TerrainGlobalOptions();
	//we create a new set of global terrain options, using the TerrainGlobalOptions class. This is an options class 
	//that just stores default options for all terrains we will create and provides a few getters and setters. 
	//There are also local options to each TerrainGroup called DefaultImportSettings, 
	mTerrainGroup=OGRE_NEW Ogre::TerrainGroup(mSceneMgr,Ogre::Terrain::ALIGN_X_Z,513,12000.0f);
	//Then we construct our TerrainGroup object - a helper class to manage a grid of terrains but it does not do any paging
	//The TerrainGroup class constructor takes our SceneManager instance, Terrain alignment option, terrain size and terrain world size as parameters. 
	mTerrainGroup->setFilenameConvention(Ogre::String("BasicTutorial3Terrain"),Ogre::String("dat"));
	//Then we tell the TerrainGroup what name we would like it to use when saving our terrain, using the setFilenameConvention function. 
	mTerrainGroup->setOrigin(Ogre::Vector3::ZERO);

	configureTerrainDefaults(light);

	for(long x=0;x<=0;++x)
		for(long y=0;y<=0;++y)
			defineTerrain(x,y);
	mTerrainGroup->loadAllTerrains(true);
	//if we just imported our terrains, we would like our blendmaps to be calculated
	if(mTerrainImported)
	{
		Ogre::TerrainGroup::TerrainIterator ti=mTerrainGroup->getTerrainIterator();
		while(ti.hasMoreElements())
		{
			Ogre::Terrain* t=ti.getNext()->instance;
			initBlendMaps(t);
		}
	}
	mTerrainGroup->freeTemporaryResources();//Now, all there is left to do is clean up after the initial terrain creation
	//2 end

	//part3 1 begin:add a Sky

	//part3 1.1 begin
	//mSceneMgr->setSkyBox(true,"Examples/SpaceSkyBox");
	//第3个参数是天空盒离摄像机的距离,默认为5000
	// the fourth parameter sets whether or not the SkyBox is drawn before the rest of the scene or afterwards. 
	// the fourth parameter that controls whether to draw the SkyBox first or not is set to true by default.
	// If the SkyBox is drawn first, then anything rendered afterwards (like our Terrain) will be drawn on top of it,
	//thus making the SkyBox always appear in the background
	//part3 1.1 end

	//part3 1.2|1.1 begin
	//mSceneMgr->setSkyDome(true, "Examples/CloudySky", 2, 8);
	// A giant cube is created around the Camera and rendered onto, but the biggest difference is that the texture is 
	//"projected" onto the SkyBox in a spherical manner. You are still looking at a cube, but it looks as if the texture
	//is wrapped around the surface of a sphere. The primary drawback to this method is that the bottom of the cube 
	//will be untextured, so you always need to have some type of terrain that hides the base.

	//you can turn the SkyDome off by calling 'mSceneMgr->setSkyDome(false, "");'

	//The third parameter is the curvature used for the SkyDome. The API reference suggests using values between 2 and 65;
	//lower for better distance effect, but higher values for less distortion and a smoother effect. Try setting 
	//the third paramater to 2 and 65 and look at the difference.

	//The fourth parameter is the number of times the texture is tiled, which you will need to tweak depending on the
	//size of your texture. Be sure to note that this parameter is a Real value (floating point) and not an integer. 
	//part3 1.2|1.1 end

	//part3 1.3|1.2 begin
	// This basic use of a SkyPlane is really only useful when you have high walls (or hills) all around
	//the viewpoint. 
	// 	Ogre::Plane plane;
	// 	plane.d=1000;
	// 	plane.normal=Ogre::Vector3::NEGATIVE_UNIT_Y;
	// 	mSceneMgr->setSkyPlane(true,plane,"Examples/SpaceSkyPlane",1500,75);
	// that the fourth parameter is the size of the SkyPlane
	//the fifth parameter is how many times to tile the texture
	//The sixth parameter to the skyplane is the familiar "renderFirst" parameter which we have already covered 
	//in the SkyBox and SkyDome sections.
	// The seventh parameter allows you to specify the curvature of the SkyPlane, so that we are no longer using
	//a plane, but a curved surface instead. 
	//We also have to now set the number of x and y segments used to create the SkyPlane (initially the SkyPlane 
	//was one big square, but if we want curvature we need to have the plane made up of smaller squares).
	//The eighth and ninth parameters to the function are the number of x and y segments, 
	//you can clear the SkyPlane by calling 'mSceneMgr->setSkyPlane(false, Ogre::Plane(), "");'
	//part3 1.3|1.2 end
	//part3 1 end


	//part4 1 begin
	//Ogre::ColourValue fadeColour(0.9,0.9,0.9);
	//mWindow->getViewport(0)->setBackgroundColour(fadeColour);
	//part4 1.1 begin
	//mSceneMgr->setFog(Ogre::FOG_LINEAR, fadeColour, 0.0, 50, 500);
	//part4 1.1 end
	//The first parameter to the setFog function is the type of fog (in this case, linear).
	//The second parameter to setFog is the color of the fog we are using
	//The third parameter is not used in linear fog. The fourth and fifth parameters specify the range where the fog gets thicker. 
	//part4 1.2 begin
	//mSceneMgr->setFog(Ogre::FOG_EXP, fadeColour, 0.005);
	//part4 1.2 end
	//part4 1.3 begin
	//mSceneMgr->setFog(Ogre::FOG_EXP2, fadeColour, 0.003);
	//part4 1.3 end
	//part4 1 end
	//part4 2 begin
	/*
	Ogre::ColourValue fadeColour(0.9, 0.9, 0.9);
	mSceneMgr->setFog(Ogre::FOG_LINEAR, fadeColour, 0.0, 300, 600);
	mWindow->getViewport(0)->setBackgroundColour(fadeColour);

	Ogre::Plane plane;
	plane.d = 100;
	plane.normal = Ogre::Vector3::NEGATIVE_UNIT_Y;

	mSceneMgr->setSkyPlane(true, plane, "Examples/CloudySky", 500, 20, true, 0.5, 150, 150);*/

	//part4 2 end
	//part4 3 begin : fog as darkness
	Ogre::ColourValue fadeColour(0.1, 0.1, 0.1);
	mWindow->getViewport(0)->setBackgroundColour(fadeColour);
	mSceneMgr->setFog(Ogre::FOG_LINEAR, fadeColour, 0.0, 10, 150);

	Ogre::Plane plane;
	plane.d = 10;
	plane.normal = Ogre::Vector3::NEGATIVE_UNIT_Y;

	mSceneMgr->setSkyPlane(true, plane, "Examples/SpaceSkyPlane", 100, 45, true, 0.5, 150, 150);
	//part4 3 end
}
void BasicTutorial3::createFrameListener(void)
{
	//part2 2 begin
	BaseApplication::createFrameListener();
	mInfoLabel=mTrayMgr->createLabel(OgreBites::TL_TOP,"TInfo","",350);
	//part2 2 end
}
bool BasicTutorial3::frameRenderingQueued(const Ogre::FrameEvent& evt)
{
	bool ret=BaseApplication::frameRenderingQueued(evt);
	//part2 1 begin
	if(mTerrainGroup->isDerivedDataUpdateInProgress())
	{
		mTrayMgr->moveWidgetToTray(mInfoLabel,OgreBites::TL_TOP,0);
		mInfoLabel->show();
		if(mTerrainImported)
		{
			mInfoLabel->setCaption("Building terrain,please wait...");
		}
		else
		{
			mInfoLabel->setCaption("Updating textures,patience...");
		}
	}
	else
	{
		mTrayMgr->removeWidgetFromTray(mInfoLabel);
		mInfoLabel->hide();
		if(mTerrainImported)
		{
			mTerrainGroup->saveAllTerrains(true);
			mTerrainImported=false;
		}
	}
	//part2 1 end
	return ret;
}
//1 end
//-------------------------------------------------------------------------------------



#if OGRE_PLATFORM == OGRE_PLATFORM_WIN32
#define WIN32_LEAN_AND_MEAN
#include "windows.h"
#endif

#ifdef __cplusplus
extern "C" {
#endif

#if OGRE_PLATFORM == OGRE_PLATFORM_WIN32
	INT WINAPI WinMain( HINSTANCE hInst, HINSTANCE, LPSTR strCmdLine, INT )
#else
	int main(int argc, char *argv[])
#endif
	{
		// Create application object
		BasicTutorial3 app;

		try {
			app.go();
		} catch( Ogre::Exception& e ) {
#if OGRE_PLATFORM == OGRE_PLATFORM_WIN32
			MessageBox( NULL, e.getFullDescription().c_str(), "An exception has occured!", MB_OK | MB_ICONERROR | MB_TASKMODAL);
#else
			std::cerr << "An exception has occured: " <<
				e.getFullDescription().c_str() << std::endl;
#endif
		}

		return 0;
	}

#ifdef __cplusplus
}
#endif


你可能感兴趣的:(第三章 Terrain, Sky, and Fog)