2011年11月21日 星期一

真-OGRE菜鳥教程(3)---在視窗中顯示ManualObject

FIRST:接續上一個範例

在上一個範例中,你只產生了一個黑摸摸的視窗,現在你可以先在上個範例中插入以下的內容

RenderWindow *render_win =
root->createRenderWindow( "Hello, Ogre!", 320, 240, false);//上個範例產生視窗的程式
//接下來是要插入的內容
SceneManager *scene_mgr = root->createSceneManager( ST_GENERIC );

Camera *camera = scene_mgr->createCamera( "MainCamera" );

Viewport *viewport = render_win->addViewport( camera );
viewport->setBackgroundColour( ColourValue::Black );

camera->setAspectRatio( Real( viewport->getActualWidth() ) / Real( viewport->getActualHeight() ) );
camera->setNearClipDistance( 1 );
camera->setFarClipDistance( 1000 );
camera->setFOVy( Degree( 45 ) );
camera->setPosition( 0, 0, 500 );

MaterialPtr mtl = MaterialManager::getSingleton().create( "ManualObjNoLighting", ResourceGroupManager::DEFAULT_RESOURCE_GROUP_NAME );
mtl->setLightingEnabled( false );

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

scene_mgr->getRootSceneNode()->attachObject( manual );
//插入內容結束
root->startRendering();//上個範例開始渲染視窗的程式

插入程式後按下F5,你將會看到如下的白色三角形出現在視窗裡
恭喜!你已經能在OGRE場景中放置物件並渲染到視窗了~~~,接下來開始解說
/**** **** **** **** **** **** **** ****/
2TH:SceneManager

SceneManager掌控3D場景中所有的物件(的生殺大權),透過一個樹狀的結構管理物件的相對關係,Ogre支援多個SceneManager,可以同時管理不同類型的場景。

記得我們說過,SceneManager是OGRE的子系統,而Root則表示OGRE本身,所以創建一個自然是從Root要囉,剛才插入的第一行程式

SceneManager *scene_mgr = root->createSceneManager( ST_GENERIC );

即是做此動作,ST_GENERIC表示我們要創建的是一個"一般性"的SceneManager(其他類型的設定可以從OGRE Wiki上面找到),不過單有SceneManager是不夠的,接下來


/**** **** **** **** **** **** **** ****/
3TH:Camera以及Viewport

事實上,OGRE在生成畫面時首先需要一個Scene(也就是SceneManager結構中所有物件的集合),然後需要一個Camera,正如字面上的,Camera會"拍"Scene,而視窗顯示的內容其實就是Camera拍到的內容,下一行程式創造了一個Camera物件,名為"MainCamera"

Camera *camera = scene_mgr->createCamera( "MainCamera" );

另外,這個字串"MainCamera"是OGRE用來搜尋物件、資源時使用的標籤,由於使用Map結構提昇搜尋效能,這個字串是絕對不能重複的,否則OGRE會不爽給你看,所以命名要注意

然後,只是把Camera架起來是不夠的,你還需要指定Camera要看得方向、視角才行,ViewPort即是為一個Camera描述其真正顯示在視窗中的部份,所以接下來的

viewport *viewport = render_win->addViewport( camera );
viewport->setBackgroundColour( ColourValue::Black );

為render(即視窗)加入一個綁定在camera物件上的 viewport物件,並將其所視範圍的背景色設定成黑色,另外,viewport預設使用跟視窗大小相同的寬、高,然後再為camera設定其他屬性

camera->setAspectRatio( ...);                    #投影平面的縱橫比,通常等同viewport
camera->setNearClipDistance( 1 );          #近端截面的位置,設定成最近看到1單位距離
camera->setFarClipDistance( 1000 );      # 遠端截面的位置,設定成最遠看到1000單位距離
camera->setFOVy( Degree( 45 ) );           #相機的視角,使用弧度制
camera->setPosition( 0, 0, 500 );             #相機的位置,注意OGRE使用右手座標

場景已經搭好了,接下來輪到加入主角ManualObject了


/**** **** **** **** **** **** **** ****/
4TH:ManualObject

通常在OGRE我們會使用資源檔來建立模型,可是非常簡單的點線、面我們可以在程式中用ManualObject來產生,用法很像OpenGL

在建立ManualObject之前我們需要為他準備材質,材質表示物件反射光的方式,以下的程式建立了一個屬性是"不使用燈光"的材質

MaterialPtr mtl = MaterialManager::getSingleton().create( "ManualObjNoLighting", ResourceGroupManager::DEFAULT_RESOURCE_GROUP_NAME );
mtl->setLightingEnabled( false );

接著終於可以來建立ManualObject了,首先設定一個由scene_mgr管理,名為"triangular_face"的ManualObject物件

ManualObject* manual = scene_mgr->createManualObject( "triangular_face" );

在設定其材質,以及造型,由於是三角所以填入3個點 ,注意點的座標順序必須是逆時針(玩過OpenGL的人有福了),顏色預設是白色
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();

OK...但是還差一步,我們剛才只設定manual是由scene_mgr管理,要讓manual能被顯示,還必須讓他加到scene_mgr的"場景"裡,以下

scene_mgr->getRootSceneNode()->attachObject( manual );

就是把manual綁進場景節點的函式,然後就結束囉~~~,到此就是剛才能讓你看到白色三角形的程式碼的基本解說,如果你覺得白色太單調的話,可以把建立manual的程式碼改成下面的

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

那麼你就可以看到彩色的三角形囉~~~

END:

OGRE基礎教程(0)---/*好想看企鵝鼓可是沒時間...*/宣言

真-OGRE菜鳥教程(2)---基本OGRE程式運作解說

FRIST:瞭解OGRE的架構

OGRE由Root與三大子系統組成,分別是

1.Render Systems:負責Ogre繪圖與底層描繪硬體API(OpenGL, Direct3D)之間的溝通。
2.Scene Management:負責管理3D物件的場景,例如物件的類型、位置、姿態等等。
3.Resource Management:負責3D場景中相關的資源,包括模型、材質、字型等等,資源通常以檔案甚至壓縮檔案的形式存在,因此也包含載入、分配等管理。

OGRE藉著三大系統以及PLUGIN功能,形成了提供穩固核心及擴充彈性的黃金四角!!!

接下來要講解的程式碼與真-OGRE菜鳥教程(1)中的完全相同,只是在這裡筆者分段解釋

首先是第一部份

#include <Ogre.h>//line 0
using namespace Ogre;

int main(int argc, char *argv[])
{

這一部份首先引入的OGRE的表頭檔,並宣告使用OGRE的名稱空間,然後開始main函數,尚無特別之處

/**** **** **** **** **** **** **** ****/

2TH:重要的ROOT

Root *root = new Root( "", "" );     #傳空字串表示不載入資源甘plugin
                                                        #Root()將會載入預設引數的Root(plugins.cfg, ogre.cfg)

接下來的這一行定義了一個Root物件,但是Root物件有啥功能呢?事實上,Root物件代表了Ogre的一切!一旦Root物件被建立,Ogre就算是被啟動。而當Root物件被消滅時,Ogre也就完全結束了。

Root管理所有其他的子系統,提供存取方式,負責取得RenderSystem與創建SceneManager等,在本範例程式中,先呈現Root跟RenderSystem的關係,建立一個單純的Ogre視窗。

/**** **** **** **** **** **** **** ****/
3TH:loadPlugin()

函式將由Root物件呼叫,就像函式名稱一樣,他會載入一個Plugin給Root,而範例程式中


#ifdef _DEBUG                                                        #表示在Debug模式時
    root->loadPlugin( "RenderSystem_GL_d" );     #載入"RenderSystem_GL_d"渲染系統
#else                                                                          #否則(就是Release模式時)
    root->loadPlugin( "RenderSystem_GL" );         #載入"RenderSystem_GL"渲染系統
#endif


是的,RenderSystem是可以作為Plugin一樣由外部插入的,這裡顯示了OGRE的彈性


另外,Plugin是可以重複載入多次的,以下的程式表示要載入Direct3D9的渲染系統,即使直接插入範例中也不會出錯(雖然也沒用)


#ifdef _DEBUG
    root->loadPlugin( "RenderSystem_Direct3D9_d" );
#else
    root->loadPlugin( "RenderSystem_Direct3D9" );
#endif


另外,像"RenderSystem_GL"事實上是一個簡稱,在Windows系統下等同於"RenderSystem_GL.dll",在Linux系統下等同於"RenderSystem_GL.so"(皆表示動態函式庫)


/**** **** **** **** **** **** **** ****/

4TH:設定Root要用的RenderSystem

如同上方的說明,事實上RenderSystem是可以重複載入多個的,因此接下來的

const RenderSystemList &render_sys_list = root->getAvailableRenderers();

#render_sys_list會從root->getAvailableRenderers()那裡取得可用的RenderSystem列表,此表的內容當然就是我們經Plugin給他的東西


RenderSystemList::const_iterator it_rs( render_sys_list.begin() );//line 15

#建立一個佚代器,用於遍歷render_sys_list

while ( it_rs != render_sys_list.end() )//line 17
{
    RenderSystem *render_sys = *(it_rs++);
    if ( render_sys->getName().find( "GL" ) != String::npos )
    {
        root->setRenderSystem( render_sys );
        break;
    }
}
#說白了就是一直找一個叫"GL"的RenderSystem直到找完整個render_sys_list

接著為了預防沒有找到
if ( root->getRenderSystem() == NULL )
{
    delete root;
    return -1;
}
#做一點例外處理


/**** **** **** **** **** **** **** ****/

5TH:來設定視窗囉

接下來的
root->initialise( false );

#root->initialise()函數預設引數為true,刻意改成false表示不使用預設的視窗,而是要自己手動設定,也就是用

RenderWindow *render_win = root->createRenderWindow( "Hello, Ogre!",            320,             240,                              false);
#                                                                                         視窗標題           視窗寬度     視窗高度    是否使用全螢幕狀態
來設定我們的螢幕

但是這只是設定,並不是啟動視窗的指令啊,我們要只是Root該開始渲染了,所以下一行

root->startRendering();     #就是startRendering()讓視窗開始執行囉~~~

    return 0;
}

END:/*心悸了...熬到三點就快掛了*/
接下來來嘗試加點東西到視窗裡吧

真-OGRE菜鳥教程(1b)---開始簡單的OGRE專案後篇

4TH:編譯通過得人
你,壞孩子,一定是偷用1.6.x的OGRE了對吧,請砍掉重練,否則本教程是基於OGRE1.7.x的,出了其他問題概不負責呦~~

解釋,因為OGRE從1.7版以後將這一函式

RenderSystemList *render_sys_list = root->getAvailableRenderers();//line 14
從傳指標改成傳參考,所以程式碼應該成

const RenderSystemList &render_sys_list = root->getAvailableRenderers();//line 14
RenderSystemList::const_iterator it_rs( render_sys_list.begin() );//line 15
while ( it_rs != render_sys_list.end() )//line 17

/**** **** **** **** **** **** **** ****/

5TH:再次按下F5

編譯應該是會通過得,後你將看到

因為OGRE有使用動態函式檔,而我們沒有配置給他,請回到之前編譯出來的Ogre資料夾中,進入C:\Ogre->bin->debug中,將

plugins_d.cfg resources_d.cfg 以及"不是"Sample開頭的DLL檔都複製起來,然後貼到你的OGRE專案的DEBUG資料夾中(筆者是C:\Documents and Settings\USER\桌面\ogre_easy\Debug)


如圖(當然你也可以將輸出目錄直接設定成OGRE的bin目錄,如此可以避免很多問題,請讀者自行嘗試)

/**** **** **** **** **** **** **** ****/

6TH:再再次按下F5
如果看到像下面的圖一樣有一個一片漆黑的視窗,恭喜你歷經千辛萬苦執行了第一個OGRE程式!!!

筆者再這裡遇到的問題有
1.畫面中出現了一隻松鼠...是的,因為筆者搞錯resources_d.cfg(資源)檔,結果一渲染就變成一張很久以前用過得圖.....只要確定你是從C:\Ogre->bin->debug得到資源檔就不可能會有這個問題

2.畫面不是純黑的,一一些花花綠綠白白的點顛,這是因為我們的程式沒做任何動作(也就是沒渲染就輸出到畫面),所以某些記憶體沒初始化就送進畫面被輸出了,所導致的怪異現象

筆者從使用DX渲染(下一張解釋)改成OpenGL渲染後就在也弄不出以上的兩個問題了,而且基本上都不算是真的問題...

END:
接下來將解說基本的OGRE程式

真-OGRE菜鳥教程(1a)---開始簡單的OGRE專案

FIRST:開一個新的[WIN32 主控台應用程式]專案






筆者將專案命名為ogre_easy,位置在桌面,不過專案名稱跟位置依讀者習慣即可,不會有任何影響,接著按下右下方的確定後,在按[下一步],將其他項目改為空專案後,按右下方的[完成]即可





/**** **** **** **** **** **** **** ****/

2TH:配置專案

開新專案後的第一件事就是(以Debug模式為例),選取[專案]->[屬性]->[組態屬性]->[連結器]->[輸入]->[其他相依性中]加入

OgreMain_d.lib OIS_d.lib (若是Release模式則改成 OgreMain.lib OIS.lib)






並將[專案]->[屬性]->[組態屬性]->[一般]->[字元集]改為[使用多位元組字元集]後,按下右下方的確定

即配置完成

/**** **** **** **** **** **** **** ****/

 3TH:開始程式

 首先新增一個空的main.cpp如下圖
然後請貼上以下的程式碼

#include <Ogre.h>//line 0
using namespace Ogre;

int main(int argc, char *argv[])
{
    Root *root = new Root( "", "" );

#ifdef _DEBUG
    root->loadPlugin( "RenderSystem_GL_d" );
#else
    root->loadPlugin( "RenderSystem_GL" );
#endif

    RenderSystemList *render_sys_list = root->getAvailableRenderers();//line 14
    RenderSystemList::iterator it_rs( render_sys_list->begin() );//line 15

    while ( it_rs != render_sys_list->end() )//line 17
    {
        RenderSystem *render_sys = *(it_rs++);
        if ( render_sys->getName().find( "GL" ) != String::npos )
        {
            root->setRenderSystem( render_sys );
            break;
        }
    }

    if ( root->getRenderSystem() == NULL )
    {
        delete root;
        return -1;
    }

    root->initialise( false );

    RenderWindow *render_win = root->createRenderWindow( "Hello, Ogre!", 320, 240, false );

    root->startRendering();

    return 0;
}

然後按下F5,是的這裡只是先讓讀者測試環境是否配置正確,關於程式的節說將於下一章進行

NEXT:
接後半部




真-OGRE菜鳥教程(0)---無責任宣言

在開始一個OGRE專案之前,首先來篇免責聲明:

/**** **** **** **** **** **** **** ****/
1.在開始真-OGRE菜鳥教程之前請先詳細閱讀OGRE菜鳥教程,以避免無謂的提問
2.自真-OGRE菜鳥教程開始後,筆者僅提供個人遭遇的錯誤,若讀者有遇到別的問題應盡量回覆,讓大家討論、解決,畢竟前人走過得死路不應讓後人在走一次
/*專題跟手機都還沒做完啊~~~(炸)*/
3.範例程式,只示範Ogre的運作,尚未使用設定檔與資源 檔,此部份將由OGRE基礎教程解說
4.#include <OGRE菜鳥教程>
/**** **** **** **** **** **** **** ****/

END:
來開始一個簡單的OGRE專案吧

OGRE菜鳥教程(3)---在專案中配置OGRE

FIRST:使用OgreSDK的配置

OgreSDK的配置較為簡單,首先開啟Microsoft Visual C++ 2008 Express Edition,選擇[工具]->[選項]->[VC++目錄]->[顯示目錄]->[Include檔案]中新增下面兩個路徑
C:\OgreSDK_vc9_v1-7-2\include\OGRE
C:\OgreSDK_vc9_v1-7-2\include\OIS

->[程式庫檔]中新增下面兩個路徑
C:\OgreSDK_vc9_v1-7-2\lib\debug
C:\OgreSDK_vc9_v1-7-2\lib\release

即可配置完成

/**** **** **** **** **** **** **** ****/

2TH:自行編譯源碼的配置
如果不調整位置的話應該是
要分別引入3個路徑較保險

以及
建議分別引入4條路徑

到此為止算是配置完成了,另外要注意的就是使用OGRE推薦的DX版本的人,記得將目錄底部的---bin\x86路徑放到[工具]->[選項]->[VC++目錄]->[顯示目錄]->[可執行檔]中,不過這些問題通常要等到真的在編譯專案才會突然跑出來...

END:
接下來,為了讓問題浮現,來開始一個OGRE專案吧