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