您好,欢迎访问三七文档
当前位置:首页 > 临时分类 > OpenSceneGraph基本渲染理论
1OpenSceneGraph基本渲染理论LeandroMottaBarrosStart:August17th02005译:FreeSouth2INDEX1.基础...........................................................................................................................41.1什么是场景图....................................................................................................41.2第二个问题:谁关心场景图?...........................................................................51.3一些与OSG相关的问题.....................................................................................51.4超级指针和OSG................................................................................................62.两个3DViewer..........................................................................................................102.1一个最简单的viewer.......................................................................................102.2另一个简单的(可能有BUG)的3DViewer......................................................123.进入StateSets...........................................................................................................153.1OpenGL-状态机................................................................................................153.2OSG和OpenGL状态........................................................................................163.3一个简单的(无BUG)3DViewer.....................................................................16341.基础在我们讨论OpenSceneGraph(OSG)之前,我们先来花一些时间来寻找一些关于个别常见有趣问题的相关线索。1.1什么是场景图就如它的名字所说的一样,场景图是一个用于组织图形图像数据结构在计算机中显示的应用程序。一个通常的想法是场景往往被分为很多的部分,而出于某种通常的目的,这些部分最终都会被组合到一场,所以,场景图就是一个代表每个结点都可被分割与重组的图。再定义的严格一些,场景图就是一个非循环的图,所以它同时也体现出结点与结点之间的等级关系。猜想一下,如果您渲染的场景中包含一辆卡车和一条路况还可以的马路。使用场景图的思想来体现该组织如图1.1所示:图1.1假如你按照上面的图例的渲染一个场景,然而卡车却停在了你不想让它出现的位置。从某种常理上讲,你一定会把它从某处移到合适的位置,幸运的是场景图的结点并不代表几何关系。在这种情况下,你可以申请一个结点,该结点用来代表移动,在场景图中体现为如图1.2所示:图1.2:一个场景图,由一条路以及移动后的卡车组成或许你一直在疑惑为什么看起来明明是树而场景图要称做一种图呢?问得好,确实例子中体现的是这种关系,然而事情总非像例子中所述的那样。现在让我们往图中添加两个盒子,一个在卡车上,另一个在马路上。同样,为了能够使这两个盒子显示在正确的位置,都需要在它们前面加上移动的几何结点。显而易见,在卡车上的盒子可以与卡车同时使用一个移动结点,因此当我们移动卡车时,盒子也会跟着移动。而事实上,因为两个盒子非常相似,故不需要为它们每个盒子都创建一个结点,可以使用一个结点而产生两次引用来达到这个目的,如图1.3所示。在渲染其间,盒子将会被访问两次,但是分享的是同一片内存区域,因此盒子在内存中只被加载了一次。当然场景图的功能不只是单单处理这些简单的问题,然而对于讲清楚场景图的基本概念即:场景图是什么?已经足够了。5故我们现在可以把更多的时间与精力花在第二个基本且重要的问题上。图1.3:一个场景图,由一条路,一个卡车以及一对盒子组成1.2第二个问题:谁关心场景图?任何一个人,只要他需要在计算机中组织他所要渲染的场景,而这些场景在现实中又是非常复杂的,他首先要面临的是效率问题,故明思议:需要在计算机中合理组织,高效显示的用户,关心场景图。1.3一些与OSG相关的问题根椐这一点,我们将围绕“一般”的场景图展开讨论。从现在开始,所有的例子都将会使用到OSG场景图,来代替传统的移动结点,我们将会使用真的在OSG中继承图中的类来做这些现实的事情。每一个结点在OSG中使用类osg::Node来表示,非常的方便快捷。尽管技术上可能需要,但是基于osg::Node专门的示例并不是很多。而我们真正的感觉兴趣的是一些基于osg::Node的子类,他们具有十分强大的功能。在这一章,我们将会讲到三个子类,它们分别是:osg::Geode,osg::Group,以及osg::PositionAttitudeTransform。Osg::Drawable类的实例可以用来在OSG中渲染一些数据。但是osg::Drawable本身并不是结点,所以我们不能直接把它加入到场景图当中去,故,使用一个几何结点osg::Geode来代替它变得十分必要。并不是所有的结点在OSG的场景图中都有父结点用来绑定它们。事实上,我们只需要在类osg::Group或其子类的实例下面增加新的结点做为他们的孩子。在OSG中,只需要使用osg::Geode以及一个osg::Group就可以创建如图1.1所示的场景图。结点如图1.4所示:图1.4:一个OSG场景图,由一条路、一个卡车组成。从osg::Node派生而来的实例,在图中椭圆形框中所示。而osg::Drawable则使用矩形框来表示。6这并不是使用OSG中的类来完成图1.1中所示功能的唯一方式。比之一个osg::Drawable来绑定一个osg::Geode而言,OSG实现图1.1的另一种方式如图1.5所示:图1.5:在OSG中如图1.4所完成的同样功能场景图功能的另一种方法在图1.4与图1.5中,实现了同样的功能,即实现图1.1所示的功能,同时也会面临同样的问题:卡车可能位于错误的位置,解决方案也和前面一样:移动卡车。在OSG中,移动一个结点最简单明了的方式是使用类osg::PositionAttitudeTransform来处理。一个osg::PositionAttitudeTransform类必须不但与移动相关,还必须与缩放以及属性相关。尽管做的事情可能不尽相同,但是与OSG中此类做同样事情也可以使用OpenGL中的glTranslate(),glRotate(),以及glScale(函数来完成。使用OSG来完成图1.2功能如图1.6所示:图1.6:一个OSG场景图,由一条路,一个移动过的卡车组成。由于某种编辑方面的原因,类osg::PositionAttitudeTransform被简写成了osg::PAT为了保持完整性,图1.7是使用OSG的方式来完成如图1.3所示的“一般”场景图。1.4超级指针和OSGSavethewhales.Feedthehungry.Freethemallocs.—fortune(6)令人悲观的是,事实上有相当一部分的C++使用者对于使用超级指针一无所知或者相当畏惧。由于在现实中越来越广泛的使用超级指针,故值得我们花一些时间来对它大加解释一番。不要惧怕跳过这一章,如果超级指针听起来就像希腊一样熟悉(当然,你并不是希腊,故继续吧)。让我们来以一个定义开讲:一个资源必须在它被使用之前被申请,而在它使用之后不久被释放,也许我们有很多的应用程序在使用同一片资源,一个不需要了而另一个却还需要使用这片资源。这两种情况都涉及到页面(在打开前必须处于关闭状态)和数据的移动(在移动前可能被加锁或做一些包裹处理)。在OpenGL当中,也同样有一些关于申请与释放资源的例子(一个示7例是纹理函数的名称被命名为glGenTextures(),它就必须被函数glDeleteTextures()释放)。图1.7:一个OSG场景,由一条路、一个卡车以及一对盒子组成。完美义者一般都设想以下理想情况:存在这样一些程序员,他们相信他们仅仅用手写代码就可以完成在任何时候需要释放内存时就释放该释放的内存,以及从来不会忘记用手写这些代码。这种设想往往会直接导致内存泄漏。好消息是:在有一些规则的制约之下,这种泄漏事故完全可以交由C++编译器去检查处理,这种做法往往比我们肆意妄为要可靠的多。在C++中资源管理的基本思想十分有必要在这里讨论一下,但是比较细致入微的讨论则超出了本文的能力范围。说起范围,“自动变量”的范围(就是变量在栈中分配)在C++的资源管理当中占有十分重要的地位:程序设计语言规则保证当一个对象被踢出某个范围时析构该对象的操作就必须被执行或是自动被执行。这是怎样避免内存泄漏的呢?花一点时间来看一下下面的类:classThingWrapper{public:ThingWrapper(){handle_=AllocateThing();}~ThingWrapper(){DeallocateThing(handle_);}ThingHandle&get(){returnhandle_;}private:ThingHandlehandle_;};它分配了一些事物在构造函数中,又释放掉这些事物在析构函数中。因此,我们可以在我们需要的时候这样使用这些事物:ThingWrapperthing;UseThing(thing.get());示例中演示了一个事物扩展如何分配一个事物(在事物扩展的构造函数当中)。但是最美妙的事情是当这些事物不被使用时它们会被自动的释放掉,析构函数在这时会被自动的执行。这就是内存自动管理的机制。这个事物扩展类是使用C++程序设计语言技术当中一种被叫做“资源使用即初始化”(RAII)的技术。一个超级指针仅仅是使用RAII自动管理堆内存的小类。类似于事物扩展类,我们可以假定一些如AllocateThing()和DeallocateThing()的函数来完成这些8功能,超级指针就是一个典型的在构造函数中分配内存,使用C++的标准操作在析构函数中来删除内存的技术。在事物扩展的事例当中,事物拥有者使用AllocateTing()来分配该事物,然后拥有者便有责任来管理他们的分配与释放操作。在OSG当中,有一些稍微有些复杂的细节来实现这些操作,也就是一些事物可能有多个拥有者。比如,在场景图1.7所示当中,类osg::geode中含有box绑定到两个父结点身上,到底哪个负责他们的分配与释放操作呢。在这种情况之下,只要还有一个引用指向该资源,该资源就不应该被释放。所以,大多数的OSG对象都有一个内部的计数器用来计算有多少个指针指向它。
本文标题:OpenSceneGraph基本渲染理论
链接地址:https://www.777doc.com/doc-4654299 .html