OGRE_HOME
environment variable equal to the directory in which it is installed.
hg clone https://code.google.com/p/caelum
add_subdirectory ( Caelum )
Caelum/main/include
and ${CMAKE_BINARY_DIR}/Caelum/main/include
subdirectories to the list of include directories via the include_directories
command, and adding Caelum to the list of linked libraries through the target_link_libraries
command:
include_directories ( ${ OIS_INCLUDE_DIRS }
${ OGRE_INCLUDE_DIRS }
${ OGRE_SAMPLES_INCLUDEPATH }
"Caelum/main/include"
"${CMAKE_BINARY_DIR}/Caelum/main/include"
# ...
target_link_libraries ( LandscapeApp ${ OGRE_LIBRARIES } ${ OIS_LIBRARIES } Caelum )
#include <Caelum.h>
using namespace Caelum;
CaelumSystem
. This class controls all components and updates ( update ) their internal state when needed. Create an instance of this class, to do this, add a pointer to it in our LandscapeApplication
root class:
class LandscapeApplication : public BaseApplication
{
// ...
protected :
virtual void createScene( void );
Caelum :: CaelumSystem * mCaelumSystem;
};
createScene
method:
void LandscapeApplication :: createScene( void )
{
mCaelumSystem = new CaelumSystem(mRoot, mSceneMgr, CaelumSystem :: CAELUM_COMPONENTS_DEFAULT);
CAELUM_COMPONENTS_DEFAULT
is the default set, it includes all stable components.
CaelumSystem
and its components have a huge number of settings, most of which are accessible from the code as get/set
methods and described in the documentation ; Another more obvious way of tuning is the Ogitor 3D editor, created specifically for Ogre and supporting all the libraries described in this article (and some not described):
mCaelumSystem = new CaelumSystem(mRoot, mSceneMgr, CaelumSystem :: CAELUM_COMPONENTS_DEFAULT);
mRoot -> addFrameListener(mCaelumSystem);
mWindow -> addListener(mCaelumSystem);
// ...
mWindow -> addListener(mCaelumSystem);
mCaelumSystem -> getUniversalClock() -> setTimeScale( 100 ); //
FlatCloudLayer * cloudLayer = // ,
mCaelumSystem -> getCloudSystem() -> createLayer(); // :
cloudLayer -> setCloudCover( 0.8f ); //
cloudLayer -> setCloudSpeed(Vector2( 0.0001f , 0.0001f )); //
cloudLayer -> setHeight( 5000 ); //
${OGRE_Terrain_LIBRARIES}
to the list of linked libraries via the target_link_libraries
command:
target_link_libraries ( LandscapeApp ${ OGRE_LIBRARIES } ${ OGRE_Terrain_LIBRARIES } ${ OIS_LIBRARIES } Caelum )
LandscapeApplication::createScene
add to the LandscapeApplication::createScene
code to load one page of the terrain (taken by me from the Terrain example in Ogre), almost identical to the code from Ogre Basic Tutorial 3 :
mCamera -> setPosition(Vector3( 1683 , 50 , 2116 )); //
mCamera -> lookAt(Vector3( 1963 , 50 , 1660 ));
Vector3 lightdir( 0.55f , -0.3f , 0.75f ); //
lightdir.normalise();
Light * light = mSceneMgr -> createLight( "tstLight" );
light -> setType(Light :: LT_DIRECTIONAL);
light -> setDirection(lightdir);
light -> setDiffuseColour(ColourValue :: White);
light -> setSpecularColour(ColourValue( 0.4f , 0.4f , 0.4f ));
mTerrainGlobals = OGRE_NEW TerrainGlobalOptions; //
mTerrainGroup = OGRE_NEW TerrainGroup(mSceneMgr, //
Terrain :: ALIGN_X_Z, 513 , 12000 );
mTerrainGroup -> setOrigin(Vector3 :: ZERO);
mTerrainGlobals -> setLightMapDirection(light -> getDerivedDirection());
mTerrainGlobals -> setCompositeMapAmbient(mSceneMgr -> getAmbientLight());
mTerrainGlobals -> setCompositeMapDiffuse(light -> getDiffuseColour());
mSceneMgr -> destroyLight( "tstLight" );
mTerrainGroup -> defineTerrain( 0 , 0 ); // (0, 0)
mTerrainGroup -> loadAllTerrains( true ); // ,
mTerrainGroup -> freeTemporaryResources(); //
mTerrainGlobals
and mTerrainGroup
pointers to our main class:
#include <Terrain/OgreTerrain.h>
#include <Terrain/OgreTerrainGroup.h>
class LandscapeApplication : public BaseApplication
{
// ...
protected :
// ...
Ogre :: TerrainGlobalOptions * mTerrainGlobals;
Ogre :: TerrainGroup * mTerrainGroup;
};
include_directories (
# ...
"Hydrax"
)
add_subdirectory ( Hydrax )
# ...
target_link_libraries ( LandscapeApp ${ OGRE_LIBRARIES } ${ OGRE_Terrain_LIBRARIES } ${ OIS_LIBRARIES } Caelum Hydrax )
Hydrax::Hydrax
:
// LandscapeApplication.hpp
class LandscapeApplication : public BaseApplication
{
// ...
protected :
// ...
Hydrax :: Hydrax * mHydrax;
};
// LandscapeApplication.cpp
void LandscapeApplication :: createScene( void )
{
// ...
mHydrax = new Hydrax :: Hydrax(mSceneMgr, mCamera, mWindow -> getViewport( 0 ));
Hydrax :: Module :: ProjectedGrid * mModule = new Hydrax :: Module :: ProjectedGrid( //
mHydrax, // Hydrax
new Hydrax :: Noise :: Perlin( /* */ ), //
Ogre :: Plane(Ogre :: Vector3( 0 , 1 , 0 ), Ogre :: Vector3( 0 , 0 , 0 )), //
Hydrax :: MaterialManager :: NM_VERTEX, //
Hydrax :: Module :: ProjectedGrid :: Options( 64 )); //
mHydrax -> setModule(mModule);
mHydrax -> loadCfg( "HydraxDemo.hdx" );
mHydrax -> create();
}
mCaelumSystem->setGlobalFogDensityMultiplier(0.01)
Caelum options a bit (namely, by saying mCaelumSystem->setGlobalFogDensityMultiplier(0.01)
, i.e. reducing the fog density), you can make sure that the water created by Hydrax is actually in place:
void LandscapeApplication :: createScene( void )
{
// ...
cloudLayer -> setHeight( 5000 );
mCaelumSystem -> setManageSceneFog(Ogre :: FOG_NONE);
void LandscapeApplication :: createScene( void )
{
// ...
mHydrax -> create();
mHydrax -> getMaterialManager() -> addDepthTechnique(
mTerrainGroup -> getTerrain( 0 , 0 ) -> getMaterial() -> createTechnique());
// LandscapeApplication.hpp
class LandscapeApplication : public BaseApplication
{
// ...
protected :
virtual bool frameEnded( const Ogre :: FrameEvent & evt);
Ogre :: Vector3 mOriginalWaterColor;
// LandscapeApplication.cpp
void LandscapeApplication :: createScene( void )
{
// ...
mHydrax -> loadCfg( "HydraxDemo.hdx" );
mOriginalWaterColor = mHydrax -> getWaterColor();
// ...
bool LandscapeApplication :: frameEnded( const Ogre :: FrameEvent & evt)
{
Vector3 value = mCaelumSystem -> getSun() -> getSceneNode() -> _getDerivedPosition();
ColourValue cval = mCaelumSystem -> getSun() -> getBodyColour();
mHydrax -> setSunPosition(value);
mHydrax -> setSunColor(Vector3(cval.r,cval.g,cval.b));
Caelum :: LongReal mJulian = mCaelumSystem -> getUniversalClock() -> getJulianDay();
cval = mCaelumSystem -> getSunLightColour(mJulian,
mCaelumSystem -> getSunDirection(mJulian));
mHydrax -> setWaterColor(Vector3(cval.r - 0.3 , cval.g - 0.2 , cval.b));
Vector3 col = mHydrax -> getWaterColor();
float height = mHydrax -> getSunPosition().y / 10.0f ;
Hydrax :: HydraxComponent c = mHydrax -> getComponents();
if (height < 0 )
{
if (mHydrax -> isComponent(Hydrax :: HYDRAX_COMPONENT_CAUSTICS))
mHydrax -> setComponents(Hydrax :: HydraxComponent(
c ^ Hydrax :: HYDRAX_COMPONENT_CAUSTICS));
} else {
if ( ! mHydrax -> isComponent(Hydrax :: HYDRAX_COMPONENT_CAUSTICS))
mHydrax -> setComponents(Hydrax :: HydraxComponent(
c | Hydrax :: HYDRAX_COMPONENT_CAUSTICS));
}
if (height < -99.0f )
{
col = mOriginalWaterColor * 0.1f ;
height = 9999.0f ;
}
else if (height < 1.0f )
{
col = mOriginalWaterColor * ( 0.1f + ( 0.009f * (height + 99.0f )));
height = 100.0f / (height + 99.001f );
}
else if (height < 2.0f )
{
col += mOriginalWaterColor;
col /= 2.0f ;
float percent = (height - 1.0f );
col = (col * percent) + (mOriginalWaterColor * ( 1.0f - percent));
}
else
{
col += mOriginalWaterColor;
col /= 2.0f ;
}
mHydrax -> setWaterColor(col);
mHydrax -> setSunArea(height);
mHydrax -> update(evt.timeSinceLastFrame);
return true ;
}
mCamera -> setFarClipDistance( 1000000 );
technique HydraxDepth
{
scheme HydraxDepth
pass
{
lighting off
texture_unit
{
colour_op_ex modulate src_manual src_current 0 0 0
}
}
}
include_directories (
# ...
"PagedGeometry/include"
"${CMAKE_BINARY_DIR}/PagedGeometry/include"
# ...
add_subdirectory ( PagedGeometry )
# ...
target_link_libraries ( LandscapeApp ${ OGRE_LIBRARIES } ${ OGRE_Terrain_LIBRARIES } ${ OIS_LIBRARIES }
Caelum Hydrax PagedGeometry )
Forests::PagedGeometry
key class (and auxiliary Forests::GrassLoader
) to our main class, not forgetting the Forests::GrassLoader
files for this:
#include <PagedGeometry.h>
#include <GrassLoader.h>
class LandscapeApplication : public BaseApplication
{
// ...
protected :
// ...
Forests :: PagedGeometry * grass, * trees, * bushes;
Forests :: GrassLoader * grassLoader;
};
LandscapeApplication
constructor as follows:
LandscapeApplication :: LandscapeApplication( void ) : grass( NULL ), trees( NULL ), bushes( NULL )
{
}
static TerrainGroup * terrainGroup = NULL ;
static float getTerrainHeight( float x, float z, void * userData)
{
OgreAssert(terrainGroup, "Terrain isn't initialized" );
return terrainGroup -> getHeightAtWorldPosition(x, 0 , z);
}
NULL
, it is necessary to initialize it with a pointer to an instance of the TerrainGroup
class, which we will do with the following line after the landscape initialization code in the createScene
method:
terrainGroup = mTerrainGroup;
createScene
method:
//
grass = new PagedGeometry(mCamera);
grass -> addDetailLevel < GrassPage > ( 160 ); // : 60
grassLoader = new GrassLoader(grass);
grass -> setPageLoader(grassLoader);
grassLoader -> setHeightFunction(getTerrainHeight); // ,
GrassLayer * l = grassLoader -> addLayer( "3D-Diggers/plant1sprite" ); //
l -> setMinimumSize( 0.9f , 0.9f ); // ...
l -> setMaximumSize( 2 , 2 ); // ...
l -> setAnimationEnabled( true ); //
l -> setSwayDistribution( 7.0f ); //
l -> setSwayLength( 0.1f ); // - 0.1
l -> setSwaySpeed( 0.4f ); //
l -> setDensity( 3.0f ); //
l -> setRenderTechnique(GRASSTECH_SPRITE); //
l -> setFadeTechnique(FADETECH_GROW); //
l -> setColorMap( "terrain_texture2.jpg" ); //
l -> setDensityMap( "densitymap.png" ); //
l -> setMapBounds(TBounds( 0 , 0 , 3000 , 3000 )); //
//
trees = new PagedGeometry(mCamera);
trees -> addDetailLevel < WindBatchPage > ( 150 , 30 ); // 150 180
trees -> addDetailLevel < ImpostorPage > ( 900 , 50 ); // 900 950
TreeLoader2D * treeLoader = new TreeLoader2D(trees, TBounds( 0 , 0 , 5000 , 5000 ));
trees -> setPageLoader(treeLoader);
treeLoader -> setHeightFunction(getTerrainHeight); // ,
treeLoader -> setColorMap( "terrain_lightmap.jpg" ); //
Entity * tree1 = mSceneMgr -> createEntity( "Tree1" , "fir05_30.mesh" ); //
Entity * tree2 = mSceneMgr -> createEntity( "Tree2" , "fir14_25.mesh" );
trees -> setCustomParam(tree1 -> getName(), "windFactorX" , 15 ); //
trees -> setCustomParam(tree1 -> getName(), "windFactorY" , 0.01f );
trees -> setCustomParam(tree2 -> getName(), "windFactorX" , 22 );
trees -> setCustomParam(tree2 -> getName(), "windFactorY" , 0.013f );
// 5000
Vector3 position = Vector3 :: ZERO;
Radian yaw;
Real scale;
for ( int i = 0 ; i < 5000 ; i ++ )
{
yaw = Degree(Math :: RangeRandom( 0 , 360 ));
position.x = Math :: RangeRandom( 0 , 2000 ); // Y , ..
position.z = Math :: RangeRandom( 2300 , 4000 ); // - getTerrainHeight,
scale = Math :: RangeRandom( 0.07f , 0.12f );
if (Math :: UnitRandom() < 0.5f )
{
if (Math :: UnitRandom() < 0.5f )
treeLoader -> addTree(tree1, position, yaw, scale);
}
else
treeLoader -> addTree(tree2, position, yaw, scale);
}
// /
bushes = new PagedGeometry(mCamera);
bushes -> addDetailLevel < WindBatchPage > ( 80 , 50 );
TreeLoader2D * bushLoader = new TreeLoader2D(bushes, TBounds( 0 , 0 , 5000 , 5000 ));
bushes -> setPageLoader(bushLoader);
bushLoader -> setHeightFunction(getTerrainHeight);
bushLoader -> setColorMap( "terrain_lightmap.jpg" );
Entity * fern = mSceneMgr -> createEntity( "Fern" , "farn1.mesh" ); //
Entity * plant = mSceneMgr -> createEntity( "Plant" , "plant2.mesh" ); //
Entity * mushroom = mSceneMgr -> createEntity( "Mushroom" , "shroom1_1.mesh" ); //
bushes -> setCustomParam(fern -> getName(), "factorX" , 1 ); //
bushes -> setCustomParam(fern -> getName(), "factorY" , 0.01f );
bushes -> setCustomParam(plant -> getName(), "factorX" , 0.6f );
bushes -> setCustomParam(plant -> getName(), "factorY" , 0.02f );
// 20000
for ( int i = 0 ; i < 20000 ; i ++ )
{
yaw = Degree(Math :: RangeRandom( 0 , 360 ));
position.x = Math :: RangeRandom( 0 , 2000 );
position.z = Math :: RangeRandom( 2300 , 4000 );
if (Math :: UnitRandom() < 0.8f ) {
scale = Math :: RangeRandom( 0.3f , 0.4f );
bushLoader -> addTree(fern, position, yaw, scale);
} else if (Math :: UnitRandom() < 0.9 ) {
scale = Math :: RangeRandom( 0.2f , 0.6f );
bushLoader -> addTree(mushroom, position, yaw, scale);
} else {
scale = Math :: RangeRandom( 0.3f , 0.5f );
bushLoader -> addTree(plant, position, yaw, scale);
}
}
LandscapeApplication
:
LandscapeApplication ::~ LandscapeApplication( void )
{
if (grass)
{
delete grass -> getPageLoader();
delete grass;
grass = NULL ;
}
if (trees)
{
delete trees -> getPageLoader();
delete trees;
trees = NULL ;
}
if (bushes)
{
delete bushes -> getPageLoader();
delete bushes;
bushes = NULL ;
}
mSceneMgr -> destroyEntity( "Tree1" );
mSceneMgr -> destroyEntity( "Tree2" );
mSceneMgr -> destroyEntity( "Fern" );
mSceneMgr -> destroyEntity( "Plant" );
mSceneMgr -> destroyEntity( "Mushroom" );
}
Forests::PagedGeometry
need to call the update()
method on each frame so that our forest is rendered, swaying smoothly under the gusts of virtual wind:
bool LandscapeApplication :: frameEnded( const Ogre :: FrameEvent & evt)
{
// ...
grass -> update();
trees -> update();
bushes -> update();
return true ;
}
Source: https://habr.com/ru/post/128377/