OSG使用场景树的方式来组织场景结构,在场景树的最底端是叶子节点(Geode),叶子节点用来存储场景中可以被渲染的对象,这些对象包括几何体、图片、文字等。用来表达所有这些可绘制体的对象就是本文提到的Drawable。
Drawable是所有可绘制对象的基类,提供了操作这些可绘制对象的方法和属性,Drawable派生的类如下图所示(OSG3.4.0):
本文及后续的文章会详细介绍所有的派生类类型,并对这些类的使用场景和使用方式给出说明。
在编写OpenGL代码的时候,所有需要绘制的代码,都是写在glutDisplayFunc回调函数中的,可绘制的类型有很多,比如使用顶点数据绘制的几何体、使用像素绘制的图片等,它们会被最终转换成Drawable的派生类,并添加到场景中,典型的转换方式如下图所示:
也就是说Drawable将场景真正需要渲染的部分(写在渲染函数体内),根据不同的渲染类型,转换成不同的类来描述。
osg::Drawable在3.4版本之前继承自osg::Object,在3.4版本以后继承自osg::Node,在osg3.4版本之前,osg::Drawable使用的回调和osg::Node使用的回调是不同的,在3.4版本之后,由于osg::Drawable继承自osg::Node,因此回调函数将二者统一起来了。
具体来说,在3.4版本之前,编写回调的方式:
//Node节点的回调 (更新、事件、筛选回调:三种都是使用NodeCallback)
class MyNodeCallback : public osg::NodeCallback
{
//必须实现的成员
virtual void operator() (Node *node, NodeVisitor *nv);
}
//设置回调的函数:
void setUpdateCallback (NodeCallback *nc);
void setEventCallback (NodeCallback *nc);
void setCullCallback (NodeCallback *nc) ;
//-------------------------------------------------------------
//Drawable节点的回调(更新回调)
class MyDrawableUpdateCallback : public osg::Drawable::UpdateCallback
{
//必须实现的成员
virtual void update (osg::NodeVisitor *, osg::Drawable *);
}
//Drawable节点的回调(事件回调)
class MyDrawableEventCallback : public osg::Drawable::EventCallback
{
//必须实现的成员
virtual void event (osg::NodeVisitor *, osg::Drawable *);
}
//Drawable节点的回调(筛选回调)
class MyDrawableCullCallback : public osg::Drawable::CullCallback
{
//必须实现的成员
virtual bool cull (osg::NodeVisitor *nv, osg::Drawable *drawable, osg::RenderInfo *renderInfo) const;
}
//Drawable节点的回调(绘制[渲染]回调)
public MyDrawableDrawCallback : public osg::Drawable::DrawCallback
{
//必须实现的成员
virtual void drawImplementation (osg::RenderInfo &, const osg::Drawable *) const;
}
可以看到在3.4版本之前的处理方式:
1. osg::Node有3种回调(对应一帧渲染过程中的3个阶段):更新、事件、筛选
2. osg::Drawable有4种回调(相比Node多出来一个绘制,因为Drawable就是场景中可绘制的对象,自然比Node多一个渲染过程)
3. 每一个不同的回调类都需要实现特定的方法,这个方法会在回调过程中被调用。
在3.4版本之后,OSG由于将Drawable的父类修改为osg::Node,也同时调整了回调的类继承结构,现在OSG中大部分的回调都继承自一个统一的回调类——osg::Callback,同时由于调整了Node类中加载回调的函数参数,使得这些函数可以被Drawable使用,也就是将参数统一调整为Callback类型:
void setUpdateCallback (Callback *nc);
void setEventCallback (Callback *nc);
void setCullCallback (Callback *nc) ;
这样Drawable类中不需要重新实现这些函数,同时Drawable自己的UpdateCallback由于继承自Callback,也可以传入到这些函数中。
新的Callback类需要所有继承它的类都实现一个方法
virtual bool run (osg::Object *object, osg::Object *data)
这个方法会在回调中被调用。这样就省去了3.1种每一个不同的回调类都有一个需要实现的方法(并且这些方法名字不同)。在3.4版本中,原来的osg::NodeCallback被标记为Deprecated。
OSG通过修改Drawable的继承关系,同时调整了回调的类结构,让整个代码看起来更加清晰,代码的复用率更高。
在OSG中大量使用了访问者设计模式(Visitor Pattern),在Drawable中,使用这种方式来获取内部的属性。
Drawable定义了2个仿函数的类:
1. AttributeFunctor
2. ConstAttributeFunctor
同时也定义了与这两个仿函数类相关的两个访问器:
1. AttributeFunctorArrayVisitor
2. ConstAttributeFunctorArrayVisitor
Drawable还定义了接收仿函数的几个类成员函数:
1. virtual void accept(AttributeFunctor&)
2. virtual void accept(ConstAttributeFunctor&) const
3. virtual void accept(PrimitiveFunctor&) const
4. virtual void accept(PrimitiveIndexFunctor&) const
这4种专门用于可绘制对象数据访问的仿函数类,其中AttributeFunctor和ConstAttributeFunctor是用来获取顶点属性数组、PrimitiveFunctor是用来获取图元数据、PrimitiveIndexFunctor用来获取图元索引数据,通过继承和重写其中的成员函数,可以在获取几何体顶点数据的同时对它们进行一些自定义的操作。
从这些定义来看,这些遍历器需要访问的是顶点的各种数据信息,很显然并不是每一个Drawable的子类都可以使用这些函数和访问器,它只供有顶点数据的子类,具体来说就是osg::Geometry子类,其他的如osg::DrawPixels由于是像素数据,因此并不能使用,字体类osg::TextBase及其派生类同样无法使用这些函数。