在這裏我們將學習OGRE的方方面面:SceneManager,SceneNode,Entity.我們會重點介紹一些在OGRE中使用的概念.
隨着我們瞭解得越來越多,我們將能夠編寫自己得遊戲,代碼量會越來越大!
讓我們開始吧:
首先讓我們來寫一些代碼,這些是我們遊戲得基本框架,隨着我們框架得逐步完善,你將慢慢明白
OGRE的流程:
#include "ExampleApplication.h"
class TutorialApplication : public ExampleApplication
{
protected:
public:
TutorialApplication()
{
}
~TutorialApplication()
{
}
protected:
void createScene(void)
{
}
};
#if OGRE_PLATFORM == OGRE_PLATFORM_WIN32
#define WIN32_LEAN_AND_MEAN
#include "windows.h"
INT WINAPI WinMain( HINSTANCE hInst, HINSTANCE, LPSTR strCmdLine, INT )
#else
int main(int argc, char **argv)
#endif
{
// Create application object
TutorialApplication app;
try {
app.go();
} catch( 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
fprintf(stderr, "An exception has occured: %s/n",
e.getFullDescription().c_str());
#endif
}
return 0;
}
如果你是在windows平臺下開發,並且已經安裝了 OGRE SDK,確定把"[OgreSDK_DIRECTORY]/samples/include"添加到工程的引用庫裏面.請先正確編譯和運行上面的代碼再接着看以下內容,這將使你更加有信心.儘管它運行時只有的界面和一個盒子,這將使OGRE世界中的"Hello World".
請確定再可執行文件的目錄下有以下兩個文件:plugins.cfg,resources.cfg.plugins.cfg告訴OGRE將使用哪個運行庫(Direct3D9 or OpenGL).Resources.cfg被ExampleApplication所使用並且指定紋理,網格腳本的路徑.以上兩個文件都使文本文件,必要時編輯它們,以確保路徑時正確的。否則將出現錯誤。
OGRE是如何工作的?
這是一個相當寬泛的問題,只研究一點顯然不能夠得到答案。我們將相繼介紹
SceneManagers,Entities,SceneNodes.這三個類是OGRE的基石.
SceneManager 基礎:
我們再屏幕上看到的一切都通過SceneManager來管理,當你把一個物體放到場景中去的時候,SceneManager就是我們來跟蹤它們位置的類.當你創建了一個相機來觀察場景的時候,SceneManager將用來跟蹤相機的位置,當你創建了飛機,燈光等等,SceneManager來跟蹤他們.
正如我們以後將要看到的一樣,有很多中SceneManager,有用來渲染terrain的SceneManager,有用來渲染BSP圖的SceneManager等等.
Octree Scene Manager
Terrain Scene Manager
Nature Scene Manager
Paging Scene Manager
BSP Scene Manager
DotSceneOctree SceneManager
我們將再以後詳細介紹每個 SceneManager
Entity 基礎:
一個Entity就是我們將要渲染到屏幕上的一個對象,我們可以把Entity想象成任何3D網格模型.一個系統任務可以是一個Entity,一條魚是一個Entity,遊戲中的地形也是Entity.但是,燈光,例子,相機等等都不是 Entity.
這裏有一點我們需要注意,那就是OGRE將所要渲染的物體與它們的位置分開了,這就意味着我們不能只創建一個Entity,然後把它放置到現場中,只能通過將它與一個SceneNode綁定才能夠放置它到場景中,SceneNode中包括了位置的信息.
SceneNode 基礎:
在前面我們已經提到,SceneNode中維護着與它綁定的對象的位置,當你創建了一個Entity對象時,只有你將它與一個SceneNode對象綁定時才能在場景中渲染它.它們之間的這種關心時對應的,我們也不能直接將一個SceneNode對象直接在場景中渲染,直到有Entity綁定在它身上.
一個SceneNode可以由很多對象綁定到它身上,比如說有一個人在走動情景,我們想在他周圍加上燈光.我們可以這樣來實現:讓我們首先來創建一個SceneNode對象,然後創建人物Entity,並且把它綁定在先創建的那個SceneNode上,然後我們再創建燈光對象,並且將燈光與SceneNode綁定.不僅如此,SceneNode還可以跟其它的SceneNode綁定,這樣就可以形成一個有層次的結構.我們應該記住很重要
的一點,那就是一個SceneNode的位置是跟它父節點的位置是相關的,並且每個SceneManager都包含一個
SceneNode層次結構的根節點.
現在回到我們剛纔的"hello world",找到函數:TutorialApplication::createScene,現在我們只關
心這個函數.我們要做的第一件事情就是打開環境光.這通過調用函數setAmbientLight來實現,它接受一
個顏色參數以用來指定光的顏色.這裏需要注意的是顏色值RGB的分量都是在0和1之間的.
mSceneMgr->setAmbientLight(ColourValue(1,1,1));
接下來我們就要創建一個Entity,看下面的代碼:
Entity *ent1=mSceneMgr->createEntity("Robot","robot.mesh");
Ok,現在你的頭腦中肯定產生了很多問題:mSceneMgr是什麼?在上個函數中的各個參數的含義是什麼?
現在讓我來告訴你:mSceneMgr包含了當前的SceneManger對象(ExampleApplication爲我們做了這些).再
來看createEntity的參數,第一個參數是我們所要創建的Entity的名字,每個Entity都必須有一個唯一的
名字.如果創建一個同名的Entity就會有錯誤發生."robot.mesh"是我們所創建的Entity所用到的網格.
我們所要用到的網格被ExampleApplication預先導入了.
好,我們現在創建了Entity,按照我們前面所說,現在該爲它創建一個SceneNode.因爲每個
SceneManager都有個根節點,現在我們就來創建它的子節點:
SceneNode * node1=mSceneMgr->getRootSceneNode()->createChildSceneNode("RobotNode");
上面的語句首先是調用了getRootSceneNode來得到當前的SceneManager,然後就來創建它的子節點.
參數就是我們所創建的SceneNode的名字,同Entity一樣,不能有重名的.
最後我們要把Entity綁定在SceneNode上,以使得Entity有一個位置用來渲染.
node1->attachObject(ent1);
好的,現在就來了編譯我們的程序,就將看到一個人物站在場景中.
注意:robot.mesh沒有在ogreCore.zip中,修改resources.cfg:
FileSystem=../../media/materials/programs
FileSystem=../../media/materials/scripts
FileSystem=../../media/materials/textures
FileSystem=../../media/models
以使得我們的程序能正常工作.
座標與向量:
在我們繼續之前,先來看一下OGRE中的座標系跟向量對象. OGRE跟其它的圖形引擎一樣使用x,z來表
示水平平面, 用y來表示垂直方向.面對你的顯示器,x軸是從左到右,右邊是正方向;y軸是從下到上,上
方是正方向;z軸是從裏向外,外面是正方向.
OGRE是用向量類來表示位置跟方向的,Vector2,Vector3,Vector4是OGRE中定義的三種向量,然而我們
最常使用的是Vector3.在繼續前進之前請確定你右足夠的向量方面的數學知識,這對以後的學習是非常
重要的.
添加更多對象:
現在你明白了座標系統如何工作的,現在讓我們繼續看我們的代碼.我們如何來指定對象的位置呢?大
多數的函數都是右默認值的,比如說,SceneNode::createChildSceneNode成員函數右三個參
數:SceneNode的名字,位置,朝向.它的位置,正如我們先前看到的一樣默認是在(0,0,0)處,現在讓我們來
重新創建一個節點,這次我們讓它處在不同的位置:
Entity *ent2 = mSceneMgr->createEntity( "Robot2", "robot.mesh" );
SceneNode *node2 = mSceneMgr->getRootSceneNode()->createChildSceneNode(
"RobotNode2", Vector3( 50, 0, 0 ) );
node2->attachObject( ent2 );
這裏的代碼大多數跟以前是一樣的,有兩處小區別:一個是名稱,再一個就是對象的初始位置,這
次我們是把對象放在了(50,0,0)處.
下面我們來列舉一些Entity的常用函數:
setVisible()
isVisible()
getName()
getParentSceneNode()
至於Entity類是如何實現的,大家現在先不要急於瞭解這些,以後的學習中慢慢體會,一開始就過度
瞭解細節有可能打擊我們的積極性.
SceneNode的一些常用函數:
//位置相關
getPositiion()
setPosition()
translate()
//旋轉
scale()
yaw()
roll()
pitch()
resetOrientation()
setOrientation()
getOrientation()
rotate()
//其它
attachObject()
numAttachedObject()
getAttachedObject()
detachObject()
detachAllObjects()
讓我們來看一下下面這段代碼:
Entity *ent1 = mSceneMgr->createEntity( "Robot", "robot.mesh" );
SceneNode *node1 = mSceneMgr->getRootSceneNode()->createChildSceneNode(
"RobotNode" );
node1->attachObject( ent1 );
Entity *ent2 = mSceneMgr->createEntity( "Robot2", "robot.mesh" );
SceneNode *node2 = mSceneMgr->getRootSceneNode()->createChildSceneNode(
"RobotNode2", Vector3( 50, 0, 0 ) );
node2->attachObject( ent2 );
如果我們把第五行:
SceneNode *node2 = mSceneMgr->getRootSceneNode()->createChildSceneNode(
"RobotNode2", Vector3( 50, 0, 0 ) );
改爲:
SceneNode *node2 = node1->createChildSceneNode( "RobotNode2", Vector3( 50, 0, 0 ) );
現在,RobotNode2是RobotNode的一個子節點,這就意味着node1移動,node2就會跟着移動,但是移動
node2不會影響到node1.下面這行代碼就只移動了node2:
node2->translate( Vector3( 10, 0, 10 ) );
下面的這段代碼是移動的node1,因爲node2是node1的子節點,所以niode2也就跟着移動了.
node1->translate( Vector3( 25, 0, 0 ) );
練習一下這些代碼:
縮放:
Entity *ent = mSceneMgr->createEntity( "Robot", "robot.mesh" );
SceneNode *node = mSceneMgr->getRootSceneNode()->createChildSceneNode( "RobotNode" );
node->attachObject( ent );
node->scale( .5, 1, 2 );
ent = mSceneMgr->createEntity( "Robot2", "robot.mesh" );
node = mSceneMgr->getRootSceneNode()->createChildSceneNode( "RobotNode2", Vector3( 50,
0, 0 ) );
node->attachObject( ent );
node->scale( 1, 2, 1 );
旋轉:
Entity *ent = mSceneMgr->createEntity( "Robot", "robot.mesh" );
SceneNode *node = mSceneMgr->getRootSceneNode()->createChildSceneNode(
"RobotNode", Vector3( -100, 0, 0 ) );
node->attachObject( ent );
node->yaw( Degree( -90 ) );
ent = mSceneMgr->createEntity( "Robot2", "robot.mesh" );
node = mSceneMgr->getRootSceneNode()->createChildSceneNode( "RobotNode2");
node->attachObject( ent );
node->pitch( Degree( -90 ) );
ent = mSceneMgr->createEntity( "Robot3", "robot.mesh" );
node = mSceneMgr->getRootSceneNode()->createChildSceneNode( "RobotNode3", Vector3(
100, 0, 0 ) );
node->attachObject( ent );
node->roll( Degree( -90 ) );