與Ogre共舞:第三步,來一個三角片
自從上一步學會開啟一個黑漆漆的小視窗後,該是來點什麼的時候了。在這步裡,我們將會在視窗裡擺上一個三角片-一個構成3D世界最基本的物件。擺好之後,或許還可以上點顏色。我們會開始接觸Ogre最重要的子系統-SceneManager,以及利用ManualObject來產生三角片。同樣的,這個範例依照我個人的偏好,不使用Ogre的設定檔與提供的資源。
第一個要上場的,就是掌控整個3D場景中所有物件的SceneManager。SceneManager握有物件的生殺大權,透過一個樹狀的結構管理物件的相對關係。Ogre支援多個SceneManager,可以同時管理不同類型的場景。ScnenManager是由Root物件所建立的:
// create the SceneManager, in this case a generic one
SceneManager *scene_mgr = root->createSceneManager( ST_GENERIC );
上面的敘述會建立一個一般性(ST_GENERIC)的ScnenManager,這裡暫時不討論SceneManager的形式。還記得"Hello, Ogre!"建立的步驟嗎?在正式啟動Ogre的描繪迴圈之前,我們已經手動建立好一個視窗。但是,光有視窗,Ogre仍然不知道該怎麼把3D場景「畫」在視窗上。這中間還需要一台攝影機,把3D場景「拍下來」,然後顯示在視窗上。所以,由SceneManager建立一部攝影機,就取名叫做"MainCamera":
// create the Camera
Camera *camera = scene_mgr->createCamera( "MainCamera" );
順帶一提,在Ogre裡建立物件或資源,大多數都需要給一個名稱。除了作為辨識外,Ogre在查詢物件時,非常仰賴這個名稱。這個設計一開始讓人有點不習慣,不過在往後會大量的使用,因此稍微熟悉一下。
接著,建立ViewPort物件,讓相機(Camera)與描繪視窗(RenderWindow)有所連結。ViewPort可以看成在描繪視窗中,真正要顯示相機看到的部份。換句話說,一個ViewPort最大的尺寸就是描繪視窗的大小。Ogre支援多個ViewPort,也就是說,你也可以設計成利用分割畫面,達到兩人同時進行遊戲的效果。當然,那樣至少需要兩個相機。一般的情況下,我們只需要一個ViewPort就好,並利用ViewPort設定畫面的背景顏色。ViewPort預設使用100%描繪視窗的寬與高,背景顏色這裡設定為黑色。
// create the Viewport
Viewport *viewport = render_win->addViewport( camera );
viewport->setBackgroundColour( ColourValue::Black ); // same as ColourValue( 0, 0, 0 )
現在,我們要設定一些相機的參數。在3D描繪中,相機能看到的範圍,是用一個平截頭錐體(frustum)來表示。底下的程式碼第1~4行分別設定了投影平面的縱橫比、近端截面的位置、遠端截面的位置、以及相機的視角。其中的Real是Ogre裡的浮點數型態,Degree是用來將角度(degree)轉換為弧度(radius)的。設定完後,我們會得到一個畫面縱橫比與ViewPort一致、最近距離是1、最遠距離達到1000、視角為45度的相機。最後,我們把相機的位置設定在z軸500個單位處(相機的視線方向為負z軸)。又,補充一下,Ogre的座標系統與OpenGL使用的一樣(右手座標系),+x 朝向螢幕右方,+y 朝向螢幕上方,+z 朝向正在看這篇文章的你(所以你的視線方向就是 -z)。
camera->setAspectRatio( Real( viewport->getActualWidth() ) / Real( viewport->getActualHeight() ) );
camera->setNearClipDistance( 1 );
camera->setFarClipDistance( 1000 );
camera->setFOVy( Degree( 45 ) );
camera->setPosition( 0, 0, 500 );
到這裡,能讓Ogre描繪場景的元件都已經準備就緒了。剩下兩個步驟,就可以完成這次的目標囉!第一個步驟是建立一個材質,第二個是建立一個三角面。在Ogre中,材質基本上會由ResourceManager載入,使用者可以直接使用材質名稱來使用材質。但是在底層,材質是如何建立的?下面的例子建立一個名叫"ManualObjNoLighting"的材質,材質所數的群組名稱是DEFAULT_RESOURCE_GROUP_NAME,唯一的屬性就是「不使用燈光」(其他都用預設值)。
// create a material with nothing and no lighting
MaterialPtr mtl = MaterialManager::getSingleton().create( "ManualObjNoLighting",
ResourceGroupManager::DEFAULT_RESOURCE_GROUP_NAME );
mtl->setLightingEnabled( false );
建立一個三角面,這裡使用ManualObject來完成。如果有用過OpenGL,那一定對ManualObject的操作方式非常熟悉。是的,跟OpenGL畫圖的指令很類似。
// create the triangular face by using ManualObject
ManualObject* manual = scene_mgr->createManualObject( "triangular_face" );
manual->begin( "ManualObjNoLighting", RenderOperation::OT_TRIANGLE_LIST );
manual->position(-100.0, 100.0, 0.0);
manual->position(-100.0, -100.0, 0.0);
manual->position( 100.0, -100.0, 0.0);
manual->end();
ManualObject物件由SceneManager管理與創建,第2行,由SceneManager建立一個使用"ManualObjNoLighting"材質,名叫"triangular_face"的ManualObject物件,並利用回傳的指標操作。接著,第3行呼叫ManualObject::begin()指令,準備開始填頂點位置等資料。OT_TRIANGLE_LIST指示ManualObject接下來所輸入的頂點資料,為每三個表示一個三角面。第4~6行就是三角面的頂點位置,按照逆時鐘方向的順序填入。當所有的頂點資料填完以後,第7行,呼叫ManualObject::end()完成物體的建立。ManualObject支援以索引值(index)定義表面的方式建立物體,不過這個例子只有簡單的一個三角面,就先省略了。
最後,不要忘記把剛剛建立的物件加入SceneManager裡,這裡直接把物體加入RootSceneNode:
// attach the object to the root node
scene_mgr->getRootSceneNode()->attachObject( manual );
好啦~該讓Ogre畫出來了。執行Root::startRendering()啟動描繪迴圈,你應該可以看到一個白色的三角形,在視窗的中間。

光這樣好像太單調了,加個顏色吧!把剛剛建立ManualObject的部份改成:
// create the triangular face by using ManualObject
ManualObject* manual = scene_mgr->createManualObject( "triangular_face" );
manual->begin( "ManualObjNoLighting", RenderOperation::OT_TRIANGLE_LIST );
manual->position(-100.0, 100.0, 0.0);
manual->colour( ColourValue::Red ); // ColourValue( 1, 0, 0 );
manual->position(-100.0, -100.0, 0.0);
manual->colour( ColourValue::Green ); // ColourValue( 0, 1, 0 );
manual->position( 100.0, -100.0, 0.0);
manual->colour( ColourValue::Blue ); // ColourValue( 0, 0, 1 );
manual->end();
是不是漂亮多了?

[下載] 範例程式 (VC2008 專案)
ogre_tutorial_3.zip 3.4 Kb
好文拜收阿!
講解的十分詳細,連我這個ogre新手都能看得懂
請務必繼續新的教學!
迴響 由 艾薩克 | 三月 19, 2009
謝謝支持~我會盡量努力的!
迴響 由 chia0418 | 三月 20, 2009