Ogre 3Dのリアルな風景

こんにちは

最も強力なレンダリングエンジンOgre3Dの 1つに関する Haberの 興味深い 記事いくつか読んで、大気効果、水面、緑豊かな植生のある現実的な風景を使用したモデリングの経験を共有することにしました。 カットの下-これに必要なすべてのライブラリをOgreにねじ込むためのレシピ。



今後、最終結果は次のようになります。















必要なライブラリは次のとおりです。



ステップ1:アプリケーションスケルトン



アプリケーションのスケルトンとして、わずかに変更されたOgre Wikiチュートリアルフレームワークを使用します。これは、小さな複雑なアプリケーションを作成するのに十分な柔軟性があるため、ogre-wikiのガイドの共通フレームワークです。 さらに、非常に多くの機能、特にWASDキーに沿ったカメラの移動、マウスのレビュー、FPSカウンターなどの便利な機能が含まれています。 コンパイルには、Microsoft Visual C ++ 2008とCMakeビルドシステムを使用しました(後者を使用すると、Ogreがサポートする任意のアーキテクチャでプロジェクトをコンパイルできます)。

すべてのソースをGithubに投稿しました(ただし、gitを混乱させないために、 このアドレスからダウンロードできます)。 コンパイルには、 2008th studio Ogreによって事前に組み立てられたブランチ1.7とCMakeが必要です。 後者がOgreを正しく見つけるためには、 OGRE_HOME



環境変数を、それがインストールされているディレクトリと同じように追加する必要があります。

さらに、テストアプリケーションを実行するには、2つのアーカイブが必要です。テクスチャ、モデル、およびその他の必要なものを含むmedia.zipは、プロジェクトディレクトリに直接展開する必要があります。 configs.zipには 、Ogre構成ファイルが含まれています。これをアセンブリディレクトリに解凍する必要があります。

プロジェクトをコンパイルするには、まずCMake GUIを実行し、 「ソースコードの場所」フィールドでプロジェクトディレクトリを選択し、 「バイナリのビルド場所」フィールドで-任意、たとえば、プロジェクトディレクトリのビルドサブディレクトリを選択できます。 次に、[ 構成 ]ボタンをクリックし、コンパイラのリストでVisual Studio 2008を選択します。すべてがうまくいき、CMakeが何も存在しないと誓わなかった場合は、[ 生成 ] クリックします。







その結果、Visual Studio LandscapeApp.slnソリューションファイルがビルドディレクトリに表示されます。このディレクトリを使用して、コードを変更し、テストプロジェクトをコンパイルおよび実行できます。

実際、コンパイルと起動後、標準のOgreレンダリングサブシステム選択ウィンドウが表示されます。







たとえば、 Direct3D9 Rendering Subsystemを選択して[OK]をクリックし、明らかにオフスケールである孤独なFPSカウンターのある黒いウィンドウを観察します-それでも、シーンは何とか空です。 ちなみに、Fキーでカウンターを折りたたんだり展開したりして、干渉しないようにすることができます。







まあ、ある有名な政治家が言ったように、「主なことは始めることです!」



ステップ2:天国



Caelumは、現在の時刻と観測者の座標、雲、気象現象(雨、雪、霧)などを考慮して、空、太陽、月、星の色などのフォトリアリスティックな大気効果を作成するためのGNU Lesser GPLライセンスの下で配布されるOgreプラグインです。 d。

Google CodeリポジトリからCaelumの最新バージョンをダウンロードします。 フォーラムメッセージから判断すると、このプロジェクトには新しいメンテナーがおり、特定の動きがあります。新しい機能がプロジェクトに追加され、古いエラーが修正されます。



hg clone https://code.google.com/p/caelum







より便利にするために、必要なすべてのソースをテストプロジェクトのツリーにコピーし、コンパイラの警告を修正するために小さな変更を加えました。 Caelumの作成者はCMakeビルドシステムを使用しているため、ビルドシステムへの追加は行に限定されます

add_subdirectory ( Caelum )







CMakeLists.txtファイルで、 include_directories



コマンドを使用してCaelum/main/include



および${CMAKE_BINARY_DIR}/Caelum/main/include



サブディレクトリをリストに追加し、 target_link_libraries



コマンドを使用してリンクライブラリのリストにCaelumを追加しinclude_directories





コード
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 )









コード自体にはもう少し変更が必要です。 開始するには、メインのLandscapeApplication.hppヘッダーファイルにCaelumヘッダーファイルを含めます。

#include <Caelum.h>







そして、LandscapeApplication.cppソースコードファイルに適切なネームスペースを含めます。

using namespace Caelum;







さらに、Caelum自体は、空と大気をレンダリングするための別個のコンポーネントのセットであり、 CaelumSystem



ルートクラスによって制御されます。 このクラスは、すべてのコンポーネントを監視し、必要に応じて内部状態を更新します。 このクラスのインスタンスを作成しましょう。このため、ルートLandscapeApplication



クラスにポインターを追加します。

コード
class LandscapeApplication : public BaseApplication

{

// ...

protected :

virtual void createScene( void );

Caelum :: CaelumSystem * mCaelumSystem;

};









createScene



メソッドでコンストラクターを呼び出します。

void LandscapeApplication :: createScene( void )

{

mCaelumSystem = new CaelumSystem(mRoot, mSceneMgr, CaelumSystem :: CAELUM_COMPONENTS_DEFAULT);







最も重要なのは最後のパラメーターです。これは、使用するCaelumコンポーネントを示すビットマスクです。 CAELUM_COMPONENTS_DEFAULT



デフォルトセット。すべての安定したコンポーネントが含まれます。

CaelumSystem



とそのコンポーネントには膨大な数の設定があり、そのほとんどはget/set



メソッドの形式でコードから利用でき、 ドキュメントに記載されています 。 別のより明確なチューニング方法は、3DエディターOgitorです。これは、Ogre 専用に作成され、この記事で説明されているすべてのライブラリをサポートしています(一部は説明されていません)。







ファイナルタッチ-時間の経過とともに大気効果を変更するには、フレームごとにCaelumを更新する必要があります。 CaelumSystemインスタンスをFrame ListenerおよびRender Target Listener Ogreリストに追加するだけです:

mCaelumSystem = new CaelumSystem(mRoot, mSceneMgr, CaelumSystem :: CAELUM_COMPONENTS_DEFAULT);

mRoot -> addFrameListener(mCaelumSystem);

mWindow -> addListener(mCaelumSystem);







出来上がり-太陽がゆっくりと日没に近づいている青い空、珍しい雲、灰色の霧に迎えられます。







エンターテイメントを増やすためにCaelumのオプションを調整します。

コード
// ...

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 ); //









その結果、空は次のようになります。















地球の表面をアプリケーションに追加して、太陽と月が行く場所を持つようになりました。



ステップ3:地球



ネイティブのOgre地形レンダリングサブシステム( Ogre Terrain System )を使用して、地球の表面をアプリケーションに追加します。 このシステムは、Ogre Steve Streetの作成者が2009年に旧式の地形レンダリングアドオンを置き換えるために作成したもので、完全に独立したオプションコンポーネントです(ただし、Ogreパッケージに含まれるバージョン1.7から)。 Ogre Terrain Systemには、私たちのような小さなテストアプリケーションを作成するために必要なものがすべて含まれています。また、個別の小さなページでRAMにロードされる巨大な世界については、たとえばogreフォーラムで詳細を確認できます 。 さらに、GSoC'11プロジェクトの1つは、地形のページ読み込みメカニズム改善することです。

まず、CMakeに意図を知らせます。CMakeLists.txtファイルで、 target_link_libraries



コマンドを使用して、リンクされたライブラリのリストに${OGRE_Terrain_LIBRARIES}



を追加します。

target_link_libraries ( LandscapeApp ${ OGRE_LIBRARIES } ${ OGRE_Terrain_LIBRARIES } ${ OIS_LIBRARIES } Caelum )







次に、 LandscapeApplication::createScene



メソッドにコードをLandscapeApplication::createScene



、地形の1ページをロードします(Ogreの「地形」の例から取得しました)。これは、 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



mTerrainGroup



ポインターをメインクラスに追加します。

コード
#include <Terrain/OgreTerrain.h>

#include <Terrain/OgreTerrainGroup.h>



class LandscapeApplication : public BaseApplication

{

// ...

protected :

// ...

Ogre :: TerrainGlobalOptions * mTerrainGlobals;

Ogre :: TerrainGroup * mTerrainGroup;

};









特別なパラメーターが指定されていない場合、座標(0、0)のページは、上記のmedia.zipアーカイブに追加したterrain_00000000.datファイルからロードされます

結果はもうすぐです:











ステップ4:水



Ogre-Hydraxの投影グリッドを使用して水面をレンダリングするために最も広く使用されているライブラリは、GNU Lesser GPLの下でライセンスされています。

ここ (最初の投稿の下部にあるリンク)アーカイブからダウンロードします。さらに作業を進めるには、テストプロジェクトのツリーにコピーしたHydrax-v0.5.1 / Hydrax / src / Hydraxカタログが必要です。

残念ながら、HydraxはCMakeビルドシステムをサポートしていないため、Hydrax / CMakeLists.txtファイルを作成する必要がありましたが、ソースファイルとヘッダーファイルを単に一覧表示するよりも少し複雑です。 Hydraxをビルドシステム(主にCMakeLists.txt)に統合するには、次を追加する必要があります。

コード
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();

}









アプリケーションを起動すると、予期しない画像が観察されます。







水の代わりにインク。 どうしたの?

実際、CaelumはOgreのフォグオプションを調整して、Caelumが使用する大気モデルと最も一致するようにします。 ただし、これらのオプションは、Hydrax水が適切にレンダリングされないようにします。 Caelumオプションを少しmCaelumSystem->setGlobalFogDensityMultiplier(0.01)



(つまり、 mCaelumSystem->setGlobalFogDensityMultiplier(0.01)



と言うことで、つまりフォグ密度を下げるmCaelumSystem->setGlobalFogDensityMultiplier(0.01)



mCaelumSystem->setGlobalFogDensityMultiplier(0.01)



によって作成された水が実際に配置されていることを確認できます。







フォグパラメータの注意深い調整はこの記事の範囲を超えているため、テストアプリケーションでは、フォグをオフにします。

void LandscapeApplication :: createScene( void )

{

// ...

cloudLayer -> setHeight( 5000 );

mCaelumSystem -> setManageSceneFog(Ogre :: FOG_NONE);







ここでは、次の驚きを待っています。







このような不快な画像は、3番目のステップで追加したランドスケープが通常のオーガエンティティではないという事実の結果です。したがって、Hydraxは水面を計算するときに考慮しません。 この状況を修正するには、テレインマテリアルに深度テクニックを追加するだけで十分です。

void LandscapeApplication :: createScene( void )

{

// ...

mHydrax -> create();



mHydrax -> getMaterialManager() -> addDepthTechnique(

mTerrainGroup -> getTerrain( 0 , 0 ) -> getMaterial() -> createTechnique());







その結果、目に楽しい次の画像が得られます。







アプリケーションを注意深く見てみると、CaelumとHydraxは互いに知りさえしないと結論付けることができます。たとえば、日没後、月が昇る前に、 コースティクスは水上に残ります。







さらに、水面での太陽のまぶしさの位置は、実際の太陽の位置とは一致しません。さらに、日没後でもまぶしさは残ります。







この問題を解決するために、前述のOgitorエディターのCaelumとHydraxの統合を担当するわずかに変更されたコードを使用します。

ねこ
// 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 );







第二に、まったく見えないはずの水の下に「なくなった」太陽の下の部分には、印象的な白い縁があります。 この問題の根本は景観の問題と同じです。太陽(および月)は普通のOgreオブジェクトではありません。 修正するには、これらのオブジェクトのマテリアルに深度テクニックを追加する必要もあります。 これに最適な場所は、media / CaelumディレクトリのSun.materialおよびmoon.materialファイルです。 これらのファイルに記述されている各資料に次の段落を追加する必要があります。

technique HydraxDepth

{

scheme HydraxDepth

pass

{

lighting off

texture_unit

{

colour_op_ex modulate src_manual src_current 0 0 0

}

}

}







必要なすべての修正を含むmedia_fixed.zipアーカイブは、 ここからダウンロードできます 。 それらを使用してアプリケーションを起動すると、すべてが適切に配置されます。







ステップ5:植生



最後の仕上げは、居心地の良い風景に植物を追加することです。 Ogre Paged Geometry Engineライブラリは、これに最適です。なぜなら、大量の小さなメッシュを長い距離でレンダリングできるためです。これは、たとえば、木、茂み、草、石などのある森林シーンの構築に特に役立ちます。 このライブラリは、無料ライセンスの中で最もリベラルなものの1つ-MIT(およびOgre自体)の下で配布されます。

Paged Geometryの最新バージョンはこのアドレスにダウンロードできます 。ここでも、必要なすべてのファイルをテストプロジェクトのソースツリーにコピーしました。 ライブラリはCMakeをサポートしているため、CMakeLists.txtに追加する必要があるのは、ヘッダーファイルの場所、ライブラリファイルの場所、およびライブラリソース自体の場所の数行のみです。

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 )







さらに、このアプリケーションでは、次の3つのタイプのオブジェクトの追加に制限しています。

  1. ハーブ;
  2. 木;
  3. その他の植生(茂み、花、キノコ)。


これを行うには、メインクラスにキークラスForests::PagedGeometry



(および補助Forests::GrassLoader



)のインスタンスへのポインターを追加します。これに必要なファイルを忘れないでください。

#include <PagedGeometry.h>

#include <GrassLoader.h>



class LandscapeApplication : public BaseApplication

{

// ...

protected :

// ...

Forests :: PagedGeometry * grass, * trees, * bushes;

Forests :: GrassLoader * grassLoader;

};







次に、 LandscapeApplication



コンストラクターを次のように変更して、これらのポインターをゼロで初期化します。

LandscapeApplication :: LandscapeApplication( void ) : grass( NULL ), trees( NULL ), bushes( NULL )

{

}







さらに、指定された座標xとzを持つポイントの風景の高さを返す関数が必要です。 この関数を呼び出すと、Paged Geometryはすべての小道具を地面に正しく配置します。 クラスメソッドではなく、必要な関数になります。 this



暗黙的にクラスメソッドに渡されるポインタであり、ライブラリは単にそこから取得する場所がありません。 したがって、グローバル変数が必要です。これは、ランドスケープ自体と機能間の接続のために、ランドスケープページのグループを管理するクラスへのポインタです。 まあ、私たちの計画を実現します。

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



であるため、 TerrainGroup



クラスのインスタンスへのポインターで初期化する必要がありますTerrainGroup



メソッドのランドスケープ初期化コードの後に​​次の行を作成しcreateScene





terrainGroup = mTerrainGroup;







最後に、 createScene



メソッドで必要なすべてのオブジェクトの初期化コードを追加できます。

コード
//

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



インスタンスでは、各フレームがupdate()



メソッドを呼び出して、フォレストが仮想風の突風の下でスムーズに揺れるようにupdate()



必要があります。

bool LandscapeApplication :: frameEnded( const Ogre :: FrameEvent & evt)

{

// ...

grass -> update();

trees -> update();

bushes -> update();

return true ;

}







アプリケーションを起動することにより、牧歌的な森林景観を観察できます。











...幸いなことに、ここには落とし穴はありません。 注目に値する唯一のことはパフォーマンスの低下です:パフォーマンスを改善するための多くのテクニックにもかかわらず(通常のLODから始まり、ランドスケープサブシステムと同様のページ分割メカニズムで終わり、実際のツリーを長距離のスプライトに置き換える)、Paged Geometry表示される植生インスタンスの数と画質を慎重に調整する必要があります。 ここでも、Paged GeometryをサポートするOgitorエディターを使用することをお勧めします。これにより、植生を適切な場所(ペイントでブラシをかけるようなもの)に簡単にスケッチし、必要なパラメーターをすべて調整できます。



完全にコンパイルされ、すぐに実行できるテストプロジェクトは、 ここからダウンロードできます



この場所を読んでくれたすべての人に感謝します-さらに素敵なスクリーンショット:











そして、ビデオ(私が作ったのではなく、問題のライブラリ-Ogre、Hydrax、Caelumを使用して作成されました):







また、記事の準備に役立つhabrayuzer Sergey ViruScD 、Ogreエンジンおよび優れた構文強調表示のためにdumpz.orgの作成者に協力するAndrey engine9に感謝します。



UPD :アンチエイリアスが有効な状態でスクリーンショットを再取得しました。コメントをありがとうm1el



All Articles