这不是一个OpenGL问题,而是一个C++组织问题.
我将要有一个简单的场景图(一个n树),其节点(为了这个问题)将渲染一些几何.更具体地说,它们在draw()方法中都有一些OpenGL绘图命令.
出于优化原因,我想将类似的对象一起批处理并一次性绘制它们.出于这个原因,我想要一种表达我称之为OpenGL的"状态集"的方式.状态集只是一堆OpenGL绑定,或者是在X对象上调用draw之前设置的命令,之后会被取消设置.
因此,状态集至少set()和unset()将被渲染系统在使用该状态集的节点的绘制命令之前和之后调用.
我的问题是如何表达状态集?当然有很多功能可以做,但我宁愿能够命名一套并回忆它.类似于节点A具有状态集LIGHTING_AND_SHADOW和节点B具有的状态集CEL_SHADING.
出于这个原因,创建一个抽象类stateSet,它本质上是set()和unset()方法的接口,并且每个状态集继承自它似乎是一个好主意.但是,它需要创建一堆对象才能获得一个名称.似乎可能有更好的方法.
理想情况下,我想列出一个stateSets可以轻松召回的清单.例如,在渲染开始之前,能够按照它们对场景图中的所有节点进行排序将是很好的stateSet.
有任何想法吗?
您可以使用单例模式来实现您的状态。然后,另一个单例状态跟踪器类管理这些状态类的实例,并且仅在尚未设置状态时设置状态。请参阅下面的粗略实现。这应该会让您了解如何去做:
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 ...
};
Run Code Online (Sandbox Code Playgroud)
请注意,上面的设计非常简单。正如您在问题中指出的那样,您可以有多个状态类来继承通用接口。关键是要有一个 Tracker(又名 Manager)类,通过它来设置对象状态。Tracker 类的工作是消除状态的不必要设置(如果已设置),并取消设置其他状态(如果当前已设置)。