OGRE 3D程式設計(4)

來源:互聯網
上載者:User

說明:本來已經收藏了,但是有一個擔心如果原帖被刪掉的之後會不會看不到,所以想了想還是拷過來算了..

 

 

 

代碼4-7:手動啟動Ogre應用程式
    #include “Ogre.h”
    //建立一個沒有設定檔的Root執行個體
    Root *root = new Root(“”, ””);
    //載入渲染系統外掛程式
    root->loadPlugin(“RenderSystem_Direct3D9”);
    root->loadPlugin(“RenderSystem_GL”);
    //在這裡我們偽裝成使用者已經選擇了OpenGL渲染器
    String rName(“OpenGL Render Subsystem”);
    RenderSystemList * rList = root->getAvailableRenderers();
    RenderSystemList::iterator it = rList->begin();
    RenderSystem *rSys = 0;
    while(ii != rList->end()){
    rSys = * (it++);
    if(rSys->getName() == rName){
    //設定渲染器,並結束迴圈
    root->setRenderSystem(rSys);
    break;
    }
    }
    //如果沒有找到一個可用的OpenGL渲染器,就在這裡結束程式。
    if(root->getRenderSystem() == NULL){
    delete root;
    return -1;
    }
    //root初始化的時候,我們可以傳入一個false值來告知Root不用給我們建立渲染視窗。
    root->initialise(false);
    //在這裡我們仍然使用預設的參數來建立渲染視窗
    RenderWindow *window = rSys->createRenderWindow(
    “Manual Ogre Window”, //視窗的名字
    800, //視窗的寬度(像素)
    600, //視窗的高度(像素)
    false, //是否全螢幕顯示
    0); //其他參數,使用預設值
    //在這之後你就可以向之前所說的一樣創攝像機和視口了。
    在上面的代碼中沒有做任何值得讓人覺得驚奇的事情;我們假設已經從其他的代碼片斷中(比如遊戲的顯示控制)得到了參數來構建渲染視窗。如果我們不在參數列表(建構函式最後一個參數)中做特殊設定,那麼視窗名稱和視窗標題(等同於視窗的標題列和系統的元件匣)為相同字串。
    注意:RenderWindow(渲染視窗)對象是對RenderTarget(渲染目標)介面的一個實現,它被介面抽象成一個渲染表面(Rendering Surface)。在我們在我們要把情境渲染到沒有幀緩衝(non-frame-buffer)的貼圖之類的渲染目標的時,這種抽象就顯得非常有用。所有的RenderTarget執行個體都可以通過名稱到相應的Factory 方法(Ogre使用的一種設計模式)中來構造,在我們上面調用createRenderWindow()方法的第一個參數就是我們需要的名稱。
    在上面的例子createRenderWindow()方法中,所有參數我們都是用了最常用的設定,你可以通過線上API手冊或者直接去看OgreRenderSystem.h檔案去瞭解參數每一項的具體含義(在這裡我建議你先去看看,因為參數中的很多都經常被改變。我在這裡介紹了的一些,可能在不久也會過時。)
    如果你希望讓渲染視窗顯示在螢幕的左上方,或者想要讓渲染視窗的名稱和渲染視窗的標題是用不一樣的字串。那麼你就需要用到NameValuePairList類(參數列表)的支援,其實這不過是一個標準模板庫(STL)的map對象,被createRenderWindow方法作為最後一個參數傳入,你只要把你希望改變的屬性寫在這個map中,系統就把會這些設定過濾出來,其他你沒有填入的選項仍採用預設設定(參考代碼4-7)。
    NameValuePairList params;
    params[“left”] = “0”;
    params[“top”] = “0”;
    params[“title”] = “Alternate Window Title”;
    RenderWindow *window = rSys->createRenderWindow(
    “MainWindow”, //渲染目標的名字
    800, //視窗的寬度(像素)
    600, //視窗的高度(像素)
    false, //是否全螢幕顯示
    ?ms); //其他參數,這次我們在上面已經設定了
    上面的代碼建立了一個在螢幕的左上方現實的視窗,名稱為“MainWindow”而標題是“Alternate Window Title”。
    到現在為止,還沒有很完美的方法來重新設定渲染視窗或者渲染系統。舉例來說,如果你希望在程式啟動並執行時候從Direct3D渲染系統轉換到OpenGL系統,就只能關閉當前渲染系統,然後初始化一個新的OpenGL的渲染系統。雖然你也可以對渲染視窗做一些簡單的改變,比如改變大小(寬度和高度),移動它在螢幕中的位置。但是如果要改變一些複雜的屬性,比如全屏反鋸齒效果,就需要釋放這個視窗再去建立新的。
    正如同我們之前提到的,有些時候你可能需要多個渲染視窗同時運行。在類似關卡編輯器中經常會出現這種情況,提供不同的顯示地區來展示你的情境。這和簡單的使用多個視口來渲染不一樣,可以讓每個視口充滿整個上層Windows。
    你也可以把Ogre的渲染視窗插入到一些視窗系統或者組件系統中來(比如Qt或者wxWidgets)。通過RenderWindow的getCustomAttribute()方法來得到當前渲染視窗在系統中的控制代碼。相應的,你也可以讓Ogre使用你提供給它的視窗來作為渲染的父視窗。如下邊的代碼:
    //hWnd是一個Win32系統中存在的視窗的控制代碼。
    //渲染系統的指標所指的是一個初始化過的D3D9RenderSystem的執行個體。
    NameValuePairList opts;
    opts[“parentWindowHandle”] = StringConverter::toString(hWnd);
    //everything but “opts” is somewhat irrelevant in the context of an
    //explicitly parented window
    RenderWindow *window = RenderSystem->createRenderWindow(
    “WindowName”,
    800, 600,
    false, &opts);
    使用上面的代碼,允許讓你把Ogre渲染視窗插入到一個已經存在的視窗系統中。但同時要注意一些事情,Ogre的視窗訊息處理函數在這裡被忽略了,因此你要手動處理Ogre相關的訊息,比如當使用者點擊關閉按鍵時候,清理Ogre渲染視窗。
    攝像機和情境管理(Camera and SceneManager)
    在這裡為了避免過多地介紹這兩個對象,我會盡量只介紹那些能足夠展示它們功能的方法。儘管如此,還是希望你能瞭解,是這兩個類渲染了你的情境。
    情境管理器(SceneManager)
    我們會在下一個章節中詳細介紹這個類,所以我盡量避免在這裡過多的深入。儘管如此,為了目前章節的完整性,我還是需要講一下最基礎的知識,來協助你建立一個應用程式所使用的情境管理系。
    在你是用情境管理器之前,你首先需要構建一個相應的執行個體。
    SceneManager* sceneMgr = root->createSceneManager(ST_GENERIC, “MySceneManager”);
    在我們之前提到的外掛程式裡面,其中有一類是情境管理器的構造器,當Ogre載入它們時,這些構造器就把自己註冊到系統中,並同時綁定到某一種情境管理器類型:
    ·ST_GENERIC:最簡單的情境管理器的構造器類型,其情境管理器沒有對情境內容和結構做任何最佳化。在極其簡單的情境中(例如菜單介面)中才有其價值。
    ·ST_INTERIOR:這種情境管理器的構造器所產生的管理器,最佳化了室內近距離的渲染,比較適合高密度的情境。
    ·ST_EXTERIOR_CLOSE:最佳化了室外情境裡面的中近距離可視體,比較適合用一個簡單模型或者高度場產生的情境地圖。
    ·ST_EXTERIOR_FAR:Ogre曆史遺留的錯誤,已經不需要在考慮使用它。在需要的時候用ST_EXTERIOR_CLOSE和ST_EXTERIOR_REAL_FAR來代替這個選項。
    ·ST_EXTERIOR_REAL_FAR:這種類型的情境管理器特別適合那種需要動態載入的地形或者情境。動態載入的地形通常都非常巨大,甚至可能描繪了一個星球的地貌。
    在前面的例子中,我們建立了一個ST_GENERIC類型的情境管理器。如果我們要載入一個雷神之錘III(Quake3)的情境,使用ST_INTERIOR來載入情境管理器就沒錯,因為BSPSceneManager外掛程式已經把置身註冊到ST_INTERIOR類型中。如果你希望建立一個以高度場為基礎的地形,你就需要載入TerrainSceneManager(TSM)外掛程式所帶來的情境管理器,我們可以通過ST_EXTERIOR_CLOSE類型來建立。ST_GENERIC類型中並沒有一個特定的情境管理外掛程式,但是當你載入OctreeSceneManager外掛程式之後,它就會接管ST_GENERIC的職責。
    攝像機(Camera)
    攝像機的概念和真實世界中的一樣,會放在一個合適的位置(這意味著它擁有位置方向的屬性),為你的情境進行“拍攝” 每一幀的工作。同時它是一個不能被渲染的物體,所以就算你的一台攝像機的拍攝範圍你有另外一台攝像機出現,另外一台也不會被“拍攝”渲染出來(參考下面的攝像機視截體3D模型,你會更好理解我說的意思的)。攝像機(以及我們之後要提及的燈光)既可以掛在情境節點上面(這就意味著它可以被動畫控制器操作),也可以直接放到空間中(你可以通過手動的方法改變其位置和方向)。就像前面說的,攝像機有一個“可視地區”的概念,它的形狀是一個頂點在攝像機位置上的稜錐,並被遠截面和近截面所切割成的視截體。如4-2所示。


    圖4-2:攝像機視截體
    在圖示中,(x, y, z)代表攝像機所在點的座標。X和Y分別代表近截面的寬度和高度,Z代表從攝像機到近截面的距離。X’和Y’代表遠截面的寬度和高度,其中(Z+Z’)的和代表著從攝像機到遠截面的距離。其他的一些資訊有,近截面和遠截面的距離,攝像機的縱寬比率(X/Y),代表視方向和視截體下截面(或者上截面)的夾角W(代表了在Y軸的可視範圍),以及可以由攝像機類計算出來的與地平線的夾角等。
    現在假設我們需要建立一個這樣的攝像機:它擁有標準3:4的縱寬比;近截面距離攝像機5單位,遠截面距離1000單位;視線方向和視截體的下平面(以及上平面)擁有30度夾角(換句話說,就是的W等於30°)。下面的代碼實現了以上工作:
    //sceneManager是一個已經存在的情境管理器執行個體的指標。
    //我們在這裡構建名稱為“MainCam”的攝像機。
    Camera *camera = sceneMgr->createCamera(“MainCam”);
    //並不需要計算什麼,可以直接從視口中得到這個尺寸
    camera->setAspectRatio(1.333333f);
    //30度角可以讓我們看到一個長而遠的視野
    camera->setFOVy(30.0f);
    camera->setNearClipDistance(5.0f);
    camera->setFarClipDistance(1000.0f);
    系統根據攝像機的設定而產生的視截體,然後再剔除在視截體六個面外面的幾何體(意味著把這些集合體從當前幀的渲染列表中清除)。
    渲染模式(Rendering Modes)
    我們的攝像機支援3種不同的渲染模式:邊框,實體,“點”(只渲染頂點)。
    camera->setPolygonMode(PM_WIREFRAME);
    camera->setPolygonMode(PM_POINTS);
    camera->setPolygonMode(PM_SOLOD);
    PolygonMode mode = camera->getPolygonMode();
    這些設定可以一直持續到下一次重新設定的時候(也就是說,不用在每一幀都調用這些函數)。系統預設的參數是PM_SOLOD。
    位置和變換(Position and Translation)
    攝像機(視截體)是一個MovableObject(使用中的物件)介面的實現,因此也具有這對象的所有方法和特性。MovableObject的大部分屬性都是為了可以讓它掛接到一個情境節點上面,並“背著”攝像機到處“拍攝”可以被渲染的物體。當你想要有一些不同的攝像機“追尾”技術的時候,你就會覺得這是一個不錯的方法,在後面的章節中你會看到一些第三人稱“追尾”技術的實現;不過在這裡,我們首先來瞭解一下它內在用來改變位置和方向的方法。
    //確認我們已經有一個指向“Camera”類型執行個體的指標camera。
    camera->setPosition(200, 10, 200);
    //也可以用一個三維向量來設定攝像機座標,在我們得到情境座標時候這麼做會方便一些
    //camera->setPosition(Vector3(200, 10, 200));
    上面的代碼把攝像機設定到全局座標系的絕對點(200,10,200)上。這和我們使用move()方以及moveRelative()方法有很大的區別,後面兩種方法會把攝像機移動到當前位置的相對位置上。
    //假設攝像機還在我們之前設定的200, 10, 200空間位置上。
    camera->move(10, 0, 0); //攝像機移動到210, 10, 200
    camera->moveRelative(0, 0, 10); //攝像機移動到210, 10, 210
    在這裡要注意一下moveRelative()方法。它關注的是本地座標系,也就是說變換是根據當前攝像機所朝向的方向。在前面的例子中,攝像機仍然垂直地面,面向Z軸正方向。假如我們現在把攝像機向右轉90度角。這時候攝像機本地座標和世界的絕對座標就不同了,如果我們這時候再調用moveRelative(0, 0, 10),在本地座標移動10個z方向,但在全局座標卻是移動x方向,最後攝像機在全局座標系的位置是(220, 10, 200)。
    指向,方向,和“著眼點”(Direction,Orientation,and“Look-At”)

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.