2010-11-26 58 views
1

我有一個代表3D模型(場景圖)的對象樹。樹節點具有不同的類型(作爲來自公共基類的派生類實現)。例如,有一個表示多邊形的節點,或者一個將座標變換(旋轉,平移)應用到其子節點的節點。這也是一個要求,第三方供應商應該能夠實現新的節點類型,並通過插件(我使用Qt作爲GUI框架)添加它們。因此,編譯時可能存在樹中的節點,其類型未知。在C++場景圖上實現MVC模式

現在我想實現一個類,作爲這個場景圖的視圖。對於每個樹節點類型,視圖必須採取適當的操作(繪製多邊形,變換等)。我的想法是爲每個節點類型實現視圖類,並根據節點類型讓頂級視圖類委派給這些類。 (第三方供應商將能夠實現自己的查看代理類)

所以我的問題是:我如何確定一個節點的性能和可擴展的方式?

我的想法而已:

  1. 我可以一個類型標識符添加到每個節點類。這可能只是一個整數(字符串不適合性能方面的原因)。問題在於管理第三方供應商的類型標識符。我怎樣才能確保相同的標識符不用於不同的節點類型(例如不同的供應商)?

  2. 我可以實現繪圖代碼,或者直接在節點中直接調用相應的繪圖委託對象。但是我的節點對象最好不知道他們的視圖對象。也不可能給每個節點對象一個專用的視圖對象(我們正在談論成千上萬的節點)。

那麼,你有什麼想法?是否有完全不同的方式來處理這個問題?記住:解決方案不應該要求哈希表查找或其他計算密集型算法,因爲我需要實時繪製圖形。

由於提前, McNumber

回答

2

一個場景圖通常寄居在MVC系統的視圖層。畢竟,場景意味着你看到的部分。通常,在設置適當的OpenGL上下文之後(或者你使用的定義爲等價物),你可以在場景圖的根節點上調用一些「渲染」方法,然後遞歸地渲染它的所有後代。

場景圖通常不代表其他類型的狀態。例如在一個有物理模擬的遊戲中,你應該圍繞一個場景圖來執行渲染,但物理對象列表由物理引擎單獨維護,並且它遵循一個非常獨立的結構。如果物理上彼此靠近的物體也以本地方式遍歷,物理引擎的效果最好。如果具有相似渲染特性(由相同紋理製成)的對象以本地方式遍歷,則渲染效果最佳。

因此,場景圖上的節點將知道如何查找它所表示的模型實例的位置,將其發送給渲染器,然後發出該對象類型的繪製基元。


有了這樣的方式,實際執行這樣的事情可能意味着思考種相互作用,在全球範圍內,場景圖的根節點必須迴應。在典型情況下,這可能意味着渲染。

class SceneNode 
{ 
    public: 
    virtual void render() = 0; 
}; 

從那裏做的最明顯的事情是做一個有孩子的節點,以便我們實際上有一個節點樹。

class ListSceneNode : public SceneNode 
{ 
    private: 
    typedef std::vector<std::shared_ptr<SceneNode> > ChildList; 
    ChildList children; 

    public: 
    void render() { 
     for(ChildList::iterator i = children.begin() ; i != children.end(); ++i) 
     i->render(); 
    } 
}; 
+0

謝謝你的答案!在某種遊戲中,這是完全可以接受的。但是我必須開發一個3D-CAD應用程序。該樹用於存儲關於當前編輯模型的實體的所有信息。此外,同樣的樹被用於模擬,測試等。爲這些任務分配不同的樹將是毫無意義的,因爲它們大多是相同的。我明確地想要分離模型(或許是比場景圖更好的詞)和繪圖算法。 – McNumber 2010-11-26 09:03:15

0

什麼打破觀看操作爲一組簡單的操作(移動到(X,Y)的位置,繪製的N長度等的線),爲使類的一部分。然後,每個模型節點都可以擁有自己的渲染操作,在該渲染操作中,它會在其接口中具有這些簡單操作的渲染對象上調用操作。

渲染類的實現可以通過Qt調用實現這些簡單的操作。頂層的View類然後只是在節點上調用渲染方法(它也可以傳遞適當的渲染對象作爲參數,以防你不希望它成爲節點類的永久屬性)。

0

一段時間不活動的線程,但我想知道如果你從那時起取得進展和/或仍在同一領域工作。

我有類似的問題。我將一個現有的代碼庫與一切集中在一起:模型(SceneGraph),GUI(win32)和渲染(OpenGL)到一個很好的模型/視圖框架(沒有單獨的控制器)。 GUI的Model/View分離工作,現在我正在處理OpenGL渲染。作爲對我自己的第一個「簡單」需求,我開始限制系統,因爲在模型層中不允許包含OpenGL標頭。這會立即強制您在視圖端有一個單獨的OpenGL「RenderGraph」,除了模型側的SceneGraph。 SceneGraph中的所有可能的節點都可以獲得他們自己的視圖表示(就像你說的那樣)。我喜歡這樣,因爲典型的OpenGL渲染數據(如頂點數組)保持在視圖方面。例如,可以想象一個對此數據沒有用處的光線跟蹤渲染,因此最好不要將其包含在模型中(只包含「半徑」或「位置」之類的東西)。

SceneGraph和Rendergraph的層次結構目前是相似的,但我可以想象,根據狀態變化,可能會有不同的結構(如TokenMacGuy提到)。當SceneGraph改變時(由GUI觸發,並由模型傳播),你必須在RenderGraph本地處理這個改變通知。這涉及到添加/移除/移動對象等操作。這有點麻煩,但它是可管理的。

我現在的主要問題是SceneGraph(Model)和「ViewGraph」(View/GUI)之間的關係與SceneGraph和RenderGraph(View/OpenGL)之間的關係有點不同。在第一種情況下,您可以在模型節點和視圖節點之間建立「水平」連接,而在第二種情況下,中間節點的更改通常會迫使整個RenderGraph從根節點向上重新渲染。我還沒有找到一種將其納入我的框架的優雅方法。

舉一個例子,假設你在SceneGraph中有一輛汽車的模型。在葉子的某處,你有「左前輪胎的閥門直徑」。這將在ViewGraph中的文本控件中表示,並且當用戶更改它時,會調整SceneGraph中相應的葉子。沒問題,這是一個本地變化。該模型接收到此更改並向RenderGraph發送通知以更新OpenGL渲染。 RenderGraph中接收此通知的節點現在不僅需要重新渲染自身,而且整個RenderGraph必須重新繪製。

親切的問候, 丹尼爾戴克斯