2012-12-30 24 views
6

這不是一個OpenGL問題,而是更多的C++組織問題。OpenGL狀態集

我將會有一個簡單的場景圖(一棵n-tree),其節點(爲了這個問題)將會渲染一些幾何圖形。更具體地說,它們在draw()方法中都有一些OpenGL繪圖命令。

出於優化的原因,我想將相似的對象批量打包並一次繪製。出於這個原因,我想要表達一種我稱之爲「狀態集」的OpenGL。一個狀態集只是一堆OpenGL綁定,或者是在X對象上調用繪製之前獲取的命令,之後會被取消設置。

所以一個狀態集至少有set()unset(),並且在渲染系統使用這個狀態集的節點的繪製命令之前和之後將被調用系統調用。

我的問題是如何表達所說的狀態集?肯定有一堆功能可以做,但我寧願能夠命名一組並記住它。與節點A相似,狀態集爲LIGHTING_AND_SHADOW,節點B爲CEL_SHADING

由於這個原因,抽象類叫做stateSet,它本質上是一個接口,用於set()unset()方法,並且每個狀態集都從它繼承,這似乎是一個好主意。但是,它需要創建一堆對象才能獲得名稱。似乎可能會有更好的方法。

理想情況下,我想列出所有可以輕鬆召回的stateSets。例如,在渲染開始之前,能夠按照它們的stateSet對場景圖中的所有節點進行排序會很好。

任何想法?

+0

這聽起來像是你要求我們給你的狀態集命名。你能否詳細說明你正在尋找哪種幫助。 – Mads

+0

如果活動的GLSL程序是你的「狀態集」的一部分,那麼你可以讓這些「狀態集」成爲你的GLSL程序類的一部分:每個人都知道它需要設置什麼狀態以及它需要激活的程序。然後在渲染之前按節目對節點進行分組。 – Gigi

回答

2

您可以使用單例模式實現您的狀態。然後,另一個單身狀態跟蹤器類管理這些狀態類的實例,並且只在尚未設置的狀態下設置狀態。請參閱下面的粗略實施。這應該給你一個想法如何去了解它:

class SingletonStateClass1 { 
public: 
    static SingletonStateClass1* getInstance() { 
     if(! instanceFlag) { 
      single = new SingletonStateClass1(); 
      instanceFlag = true; 
      return single; 
     } 
     else { 
      return single; 
     } 
    } 
    void set() { 
     // Do setting stuff 
    } 
    void unset() { 
     // Do unsetting stuff 
    } 
    ~SingletonStateClass1() { 
     instanceFlag = false; 
    } 

private: 
    static bool instanceFlag; 
    static SingletonStateClass1 *single; 
    SingletonStateClass1() {} //private constructor 
}; 
bool SingletonStateClass1::instanceFlag = false; //needs to be set so that the first call to getInstance() works ok. 


//ASSUME THERE IS ANOTHER CLASS WITH SIMILAR DESIGN, NAMED: SingletonStateClass2 

class SingletonStateTracker { 
public: 
    static SingletonStateTracker* getInstance() { 
     if(! instanceFlag) { 
      single = new SingletonStateTracker(); 
      state1 = SingletonStateClass1::getInstance(); 
      state2 = SingletonStateClass2::getInstance(); 
      instanceFlag = true; 
      isSetState1 = false; 
      isSetState2 = false; 
      return single; 
     } 
     else { 
      return single; 
     } 
    } 

    // Only setting a state unsets the other states 
    void set1() { 
     if (!isSetState1) { 
      if (isSetState2) { 
       state2->unset(); 
       isSetState2 = false; 
      } 
      state1->set(); 
      isSetState1 = true; 
     } 
    } 
    void set2() { 
     if (!isSetState2) { 
      if (isSetState1) { 
       state1->unset(); 
       isSetState1 = false; 
      } 
      state2->set(); 
      isSetState2 = true; 
     } 
    } 

private: 
    static bool instanceFlag; 
    static bool isSetState1; 
    static bool isSetState2; 
    static SingletonStateTracker *single; 
    static SingletonStateClass1 *state1; 
    static SingletonStateClass2 *state2; 
    SingletonStateTracker() {} //private constructor 
}; 
bool SingletonStateTracker::instanceFlag = false; //needs to be set so that the first call to getInstance() works ok. 




class DrawableObject1 { 
public: 
    DrawableObject1() { 
     tracker = SingletonStateTracker::getInstance(); 
    } 
    void draw() const 
    { 
     tracker->set1(); 
     //DO YOUR OBJECT SPECIFIC OPENGL DRAW STUFF HERE 
    } 
private: 
    SingletonStateTracker* tracker; 
}; 

class DrawableObject2 { 
public: 
    DrawableObject2() { 
     tracker = SingletonStateTracker::getInstance(); 
    } 
    void draw() const 
    { 
     tracker->set2(); 
     //DO YOUR OBJECT SPECIFIC OPENGL DRAW STUFF HERE 
    } 
private: 
    SingletonStateTracker* tracker; 
}; 


/* Below two classes show a crude usage of the above design */ 
class Scene { 
    // ... other stuff ... 

public: 
    DrawableObject1 obj1a; 
    DrawableObject1 obj1b; 
    DrawableObject2 obj2; 
    // ... other stuff ... 
}; 

class Viewer { 
    // ... other stuff ... 
public: 
    void draw() { 
     scene->obj1a.draw(); //This call unsets state2, sets state1 
     scene->obj1b.draw(); //This call does not set any state since state1 is already set 
     scene->obj2.draw(); //This call unsets state1, sets state2 
    } 
private: 
    Scene* scene; 
    // ... other stuff ... 
}; 

請注意,上述設計是非常簡單的。您可以讓多個State Classes繼承您的問題中提到的通用界面。關鍵是要有一個跟蹤器(a.k.a Manager)類,通過這個類來設置對象的狀態。 Tracker類的工作是消除不必要的狀態設置,如果它已經設置,則取消設置其他狀態。

+0

這是非常好的,我可以運行這個。正如你所建議的,我將繼續使用set()unset()和getInstance()創建一個StateSet接口,並且管理器可以有各種各樣的好東西。我特別喜歡管理員在設置了另一個StateSet時調用unset()的能力,因此不需要用戶調用unset。再次感謝! -Cody –

+0

進一步的想法:從安全設計的角度來看,您可能想要私下將狀態類的定義封裝在管理器類中。這樣,這些類甚至不需要單身,因爲管理器確保每個這些狀態類只有一個靜態實例,並且沒有公共訪問其構造函數的權限。儘管經理仍然是辛格爾頓。這是一個記錄類,其中Singleton建議並廣泛使用。 – meyumer

1

爲此作出的叫stateSet抽象類,這是 本質上是set()unset()方法的接口,並具有 每個國家規定繼承它似乎是一個不錯的主意。但是,它本質上需要創建一堆對象才能獲得名稱 。

您的虛擬抽象類實現通過虛函數表工作,虛函數表通常作爲函數指針數組實現。在這種情況下你實例化的顯然沒有意義的對象確實保持有意義的狀態 - 那些函數指針。

作爲創建兩個函數指針的許多數組的替代方法,可能應該創建兩個函數指針數組,名稱索引到數組中,保留最後使用的索引,並檢查state_name是否不同在通過陣列進行間接處理之前。我建議通過static關鍵字從其他編譯單元隱藏所有全局狀態。

這種方法提供的自動安全性較低 - 語義上沒有任何東西阻止您將任何整數傳遞到stateSet(uint),並且除非您自己將它放在那裏,否則沒有範圍檢查原始數組。

這兩個選項基本上非常相似;所以給你自己的想法應有的考慮。