场景的组织及渲染(一)

·        在OSG 中存在两棵树,即场景树和渲染树。场景树是一棵由 Node组成的树,这些Node可能是矩阵变换、状态切换或真正的可绘制对象,它反映了场景的空间结构,也反映了对象的状态。本章重点介绍场景树,在第 5章将会对渲染树作详细的介绍。

1. OSG场景树

1.1 OSG场景树节点

        场景图形采用一种自顶向下的、分层的树状数据结构来组织空间数据集,以提升渲染的效率。例如,有一个房子,房子里面有窗户、门和家具等,这时场景图就可以描述为如图3-1所示:。

图3-1场景组织图

        上面的场景中包含一个组节点——房子和3个子节点——窗、门、家具,其中,每个子节点包含所需要绘制的信息。

        通过图 3-1 可以看到,场景图形树结构的顶部是一个根节点,从根节点向下延伸,各个组节点中均包含了几何信息和用于控制其外观的渲染状态信息。根节点和各个组节点都可以有0个或多个子成员。在场景图形的最底部,各个叶节点包含了构成场景中物体的实际几何信息。由此,可以这样来描述场景树:OSG程序使用组节点来组织和排列场景中的几何体。

        场景树通常包括了多种类型的节点,以执行各种各样的用户功能,例如,开关节点可以设置其子节点可用或不可用;细节层次(LOD)节点可以根据观察者的距离调用不同的子节点,变换节点可以改变子节点几何体的坐标变换状态。面向对象的场景图形使用继承的机制来提供这种多样性,所有的节点类都有一个共有的基类,同时各自派生出实现特定功能的方法。

1.2 OSG中的父节点与子节点

        OSG主要包含3大基本类节点,即NodeGeode(叶节点)和Group(组节点)。OSG中其他的大部分节点都继承自 Group节点,少部分继承自 Node节点及Geode 节点,但Geode和Group 均继承自Node 节点。

        Geode(叶节点),顾名思义,作为叶节点,它不会再有其他的子节点,但它可以包含几何体信息。Geode的英文全称为 Geometry Node,即几何体节点。Node、Group和Geode 的继承关系图如图3-2、图3-3和图3-4所示。

图3-2 Node 的继承关系图

图3-3 Group 的继承关系图

图3-4 Geode的继承关系图

        这里没有列举节点所有的继承关系,除了继承自 Node 和Geode 以外的所有节点均继承自 Group节点。

        osg:Node类继承于osg::Objcct 类osg::Object类是应用程序无法直接实例化的虚基类,它提供了一系列接口,用于保存与获取节点名称,指定保存数据是静态的还是动态更改的,还继承osg::Referenced类的内存管理机制。

        通常情况下,一个子节点至少有一个父节点,要获得该子节点的父节点指针,可以使用 getParent()函数。

        通过图3-4可知,OSG中的节点直接或间接地以osg::Objcct和osg::Referenced 为基类,继承它的一系列的接口,用于保存和获取名称,同时定义自己特定的方法来执行不同功能。

2. Geode

        osg:Geode是OSG中的叶节点,它用于保存几何信息以便渲染。同时,作为叶节点,它就不会再包含子节点。在应用程序中,所有相关的几何体的渲染都必须与Geode 节点相关联。在osgGeode类中,也提供了addDrawable()函数来关联应用程序中需要渲染的几何体信息。

2.1 Billboard节点

        Billboard的继承关系图如图3-5所示。

        从图3-5可以看出,Billboard 节点继承自 Geode 节点,因此它也是一个叶节点,不可再包含其他的子节点,只能像叶节点那样通过添加Drawable 来绘制信息。Billboard 有下面3种模式:

  1. enum Mode  
  2. {  
  3.     POINT_ROT_EYE,// 绕视点  
  4.     POINT_ROT_WORLD,// 绕世界坐标  
  5.     AXIAL_ROT// 绕轴  
  6. }; 

        Billboard,从英文名可以看出是一种布告板技术,这是一种非常实用的技术,很多特殊效果都利用它来实现。布告板实现的原理是: 将图形绘制在朝向视点的多边形表面上,根据视点的观察方向来确定多边形的方向,随着观察角度的变化,多边形的方向也随之变换。osg::Billboard 布告板与 Alpha纹理和动画融合技术相结合可以实现很多没有实心表面的现象,如后面会讲到的粒子系统中的烟、火.雾、爆炸、雨、雪及云朵等。

        在OSG 中使用了几种常见的布告板技术,主要包括面向世界的布告板轴向布告板。其中,面向世界的布告板包括面向视平面的布告板和面向视点的布告板技术。图3-6表示了这两种技术的区别。

        在轴向布告板技术中,经过纹理贴图的多边形通常不直接朝向视点,而是允许多边形围绕某个固定世界空间轴旋转,但调整多边形使其在此范围内尽可能朝向视点。这种布告板技术通常用来在场景中显示树木,它不是用实心表面来显示树木,而是使用一个四边形表面纹理显示树木。此时,一个树木布告板以树干为轴心作为世界的向上向量,保持世界的向上向量固定,视点观察方向作为树木旋转的第二个调整向量,一旦视点旋转矩阵生成,就可以对树木位置进行旋转变换。

        但轴向布告板技术存在一个问题,当观察者处于空中飞行模式下,从树木顶部飞过并且垂直向下看时,看到的树木就像一个切面一样,非常难看。似乎对于这样的问题,前面的功夫都白费了。可以使用细节层次LOD模型或者替代模型弥补效果,或者可以使用一个球形树木表面来改善。

2.2 布告板示例

        通过上面的解释,读者应该已经明白了什么是 Billboard 技术。现在就通过一个使用 Billboard的例子来讲解如何在程序中使用它。

        在下面的程序中会使用到如何绘制几何体、PositionAttitudeTransform 节点以及纹理贴图,在后面的章节都会讲到这些,读者主要的任务是学习如何使用Billboard技术代码如程序清单3-1所示。

  1. osg::ref_ptr<osg::Node> createBillboardTree(osg::ref_ptr<osg::Image> image)  
  2. {  
  3.     //创建四边形  
  4.     osg::ref_ptr<osg::Geometry> geometry = new osg::Geometry();  
  5.   
  6.     //设置顶点  
  7.     osg::ref_ptr<osg::Vec3Array> v = new osg::Vec3Array();  
  8.     v->push_back(osg::Vec3(-0.5f, 0.0f, -0.5f));  
  9.     v->push_back(osg::Vec3(0.5f, 0.0f, -0.5f));  
  10.     v->push_back(osg::Vec3(0.5f, 0.0f, 0.5f));  
  11.     v->push_back(osg::Vec3(-0.5f, 0.0f, 0.5f));  
  12.   
  13.     geometry->setVertexArray(v.get());  
  14.   
  15.     //设置法线  
  16.     osg::ref_ptr<osg::Vec3Array> normal = new osg::Vec3Array();  
  17.     normal->push_back(osg::Vec3(1.0f, 0.0f, 0.0f) ^ osg::Vec3(0.0f, 0.0f, 1.0f));  
  18.   
  19.     geometry->setNormalArray(normal.get());  
  20.     geometry->setNormalBinding(osg::Geometry::BIND_OVERALL);  
  21.   
  22.     //设置纹理坐标  
  23.     osg::ref_ptr<osg::Vec2Array> vt = new osg::Vec2Array();  
  24.     vt->push_back(osg::Vec2(0.0f, 0.0f));  
  25.     vt->push_back(osg::Vec2(1.0f, 0.0f));  
  26.     vt->push_back(osg::Vec2(1.0f, 1.0f));  
  27.     vt->push_back(osg::Vec2(0.0f, 1.0f));  
  28.   
  29.     geometry->setTexCoordArray(0, vt.get());  
  30.   
  31.     //绘制四边形  
  32.     geometry->addPrimitiveSet(new osg::DrawArrays(osg::PrimitiveSet::QUADS, 0, 4));  
  33.   
  34.     if (image.get())  
  35.     {  
  36.         //状态属性对象  
  37.         osg::ref_ptr<osg::StateSet> stateset = new osg::StateSet();  
  38.   
  39.         //创建一个Texture2D属性对象  
  40.         osg::ref_ptr<osg::Texture2D> texture = new osg::Texture2D();  
  41.         //关联image  
  42.         texture->setImage(image.get());  
  43.         //关联Texture2D纹理对象,第三个参数默认为ON  
  44.         stateset->setTextureAttributeAndModes(0, texture, osg::StateAttribute::ON);  
  45.         //启用混合  
  46.         stateset->setMode(GL_BLEND, osg::StateAttribute::ON);  
  47.         //关闭光照  
  48.         stateset->setMode(GL_LIGHTING, osg::StateAttribute::OFF);  
  49.   
  50.         geometry->setStateSet(stateset.get());  
  51.     }  
  52.   
  53.     //创建Billboard对象一  
  54.     osg::ref_ptr<osg::Billboard> billboard1 = new osg::Billboard();  
  55.   
  56.     //设置旋转模式为绕视点  
  57.     billboard1->setMode(osg::Billboard::POINT_ROT_EYE);  
  58.     //添加Drawable,并设置其位置,默认位置为osg::Vec3(0.0f,0.0f,0.0f) ;  
  59.     billboard1->addDrawable(geometry.get(), osg::Vec3(5.0f, 0.0f, 0.0f));  
  60.   
  61.     osg::ref_ptr<osg::Billboard> billboard2 = new osg::Billboard();  
  62.     //设置旋转模式为绕轴转,因此还需要设置转轴  
  63.     billboard2->setMode(osg::Billboard::AXIAL_ROT);  
  64.     //设置旋转轴  
  65.     billboard2->setAxis(osg::Vec3(0.0f, 0.0f, 1.0f));  
  66.     billboard2->addDrawable(geometry.get(), osg::Vec3(10.0f, 0.0f, 0.0f));  
  67.   
  68.     osg::ref_ptr<osg::Group> billboard = new osg::Group();  
  69.     billboard->addChild(billboard1.get());  
  70.     billboard->addChild(billboard2.get());  
  71.   
  72.     return billboard.get();  
  73.   
  74. }  
  75.   
  76. void billBoard_3_1(const string &strDataFolder)  
  77. {  
  78.     osg::ref_ptr<osgViewer::Viewer> viewer = new osgViewer::Viewer();  
  79.     osg::ref_ptr<osg::GraphicsContext::Traits> traits = new osg::GraphicsContext::Traits;  
  80.     traits->x = 40;  
  81.     traits->y = 40;  
  82.     traits->width = 600;  
  83.     traits->height = 480;  
  84.     traits->windowDecoration = true;  
  85.     traits->doubleBuffer = true;  
  86.     traits->sharedContext = 0;  
  87.   
  88.     osg::ref_ptr<osg::GraphicsContext> gc = osg::GraphicsContext::createGraphicsContext(traits.get());  
  89.   
  90.     osg::ref_ptr<osg::Camera> camera = new osg::Camera;  
  91.     camera->setGraphicsContext(gc.get());  
  92.     camera->setViewport(new osg::Viewport(0, 0, traits->width, traits->height));  
  93.     GLenum buffer = traits->doubleBuffer ? GL_BACK : GL_FRONT;  
  94.     camera->setDrawBuffer(buffer);  
  95.     camera->setReadBuffer(buffer);  
  96.     viewer->addSlave(camera.get());  
  97.   
  98.     osg::ref_ptr<osg::Group> root = new osg::Group();  
  99.   
  100.     // 读取图像  
  101.     string strImagePath = strDataFolder + "Images/tree0.rgba";  
  102.     osg::ref_ptr<osg::Image> image = osgDB::readImageFile(strImagePath);  
  103.   
  104.     //缩放一下,以达到合适的大小  
  105.     osg::ref_ptr<osg::PositionAttitudeTransform> pat = new osg::PositionAttitudeTransform();  
  106.     pat->setScale(osg::Vec3(5.0f, 5.0f, 5.0f));  
  107.     pat->addChild(createBillboardTree(image.get()));  
  108.   
  109.     root->addChild(pat.get());  
  110.   
  111.     //读取cow的模型,以对比  
  112.     string strDataPath = strDataFolder + "cow.osg";  
  113.     root->addChild(osgDB::readNodeFile(strDataPath));  
  114.   
  115.     //优化场景数据  
  116.     osgUtil::Optimizer optimizer;  
  117.     optimizer.optimize(root.get());  
  118.   
  119.     viewer->setSceneData(root.get());  
  120.   
  121.     viewer->realize();  
  122.   
  123.     viewer->run();  
  124. }  

        运行程序,截图如图3-7所示。

图3-7布告板示例截图

        通过上面简单的示例,相信读者已经学会使用 Billboard 技术关于Biboard类的更多方法,请参考函数帮助。

3. Group

        osg::Group 类是OSG的组节点,它允许用户程序为其添加任意数量的子节点,子节点也可以继续分发子节点。osg::Group 作为一个基类,派生出了很多实用的节点类,如 osg::LOD、osg::Switch、osg::Transform、osg::PositionAttitudeTransform、osg::PagedLOD、osg::lmpostor 和 osg::AutoTransform等,后面的几节会对它们逐一进行介绍。

        osg::Group 类是从osg::Referenced 类派生出来的,在通常情况下,只有父节点引用了这个Group对象,所以当释放场景图的根节点时,会引发连锁的内存释放动作,这样就不会产生内存的泄露。

        osg::Group类作为OSG的核心部分,可以使用户程序通过Group 来有效地组织场景图中的数据。osg::Group类的强大之处在于管理子节点的接口,同时,osg::Group 类还从osg::Node类继承了用于管理父节点的接口,OSG允许节点有多个父节点。

3.1 位置变换节点

        位置变换节点(osg::PositionAttitudeTransform)是一个位置变换节点,继承自osg::Transform,主要作用是提供模型的位置变换、大小缩放、原点位置的设置以及坐标系的变换。

        osg::PositionAttitudeTransform 继承关系图如图3-8所示。

图3-8 osg::PositionAttitudeTransform 的继承关系图

        osg::PositionAttitudeTransform的常用主要成员函数如下

  1. void setPosition(const Vec3d &pos) // 设置位置  
  2. const Vec3d& getPosition() const   // 得到位置  
  3. void setAttitude(constQuat &quat)  // 设置姿态,参数为四元数  
  4. const Quat& getAttitude() const    // 得到姿态  
  5. void setScale(const Vec3d &scale)  // 设置缩放  
  6. const Vec3d &getScale()const       // 得到缩放  
  7. void setPivotPoint(const Vec3d &pivot) // 设置原点(自定义原点位置,一旦设置以后,所有变换均基于该原点)  
  8. const Vec3d&getPivotPoint() const // 得到原点  

 

3.2 位置变换节点示例

        下面通过例子来讲解如何使用osg::PositionAttitudeTransform节点,代码如程序清单3-2所示。

  1. void positionAttitudeTransform(const string &strDataFolder)  
  2. {  
  3.     // 创建Viewer对象,场景浏览器  
  4.     osg::ref_ptr<osgViewer::Viewer> viewer = new osgViewer::Viewer();  
  5.     osg::ref_ptr<osg::GraphicsContext::Traits> traits = new osg::GraphicsContext::Traits;  
  6.     traits->x = 40;  
  7.     traits->y = 40;  
  8.     traits->width = 600;  
  9.     traits->height = 480;  
  10.     traits->windowDecoration = true;  
  11.     traits->doubleBuffer = true;  
  12.     traits->sharedContext = 0;  
  13.   
  14.     osg::ref_ptr<osg::GraphicsContext> gc = osg::GraphicsContext::createGraphicsContext(traits.get());  
  15.   
  16.     osg::ref_ptr<osg::Camera> camera = new osg::Camera;  
  17.     camera->setGraphicsContext(gc.get());  
  18.     camera->setViewport(new osg::Viewport(0, 0, traits->width, traits->height));  
  19.     GLenum buffer = traits->doubleBuffer ? GL_BACK : GL_FRONT;  
  20.     camera->setDrawBuffer(buffer);  
  21.     camera->setReadBuffer(buffer);  
  22.     viewer->addSlave(camera.get());  
  23.   
  24.     // 创建场景组节点  
  25.     osg::ref_ptr<osg::Group> root = new osg::Group();  
  26.   
  27.     // 创建一个节点,读取牛的模型  
  28.     string strDataPath = strDataFolder + "cow.osg";  
  29.     osg::ref_ptr<osg::Node> node = osgDB::readNodeFile(strDataPath);  
  30.   
  31.     // 创建位置变换节点pat1  
  32.     osg::ref_ptr<osg::PositionAttitudeTransform> pat1 = new osg::PositionAttitudeTransform();  
  33.     // 设置位置为osg::Vec3(-10.0f,0.0f,0.0f)  
  34.     pat1->setPosition(osg::Vec3(-10.0f, 0.0f, 0.0f));  
  35.     // 设置缩放,X,Y,Z方向都缩小一倍  
  36.     pat1->setScale(osg::Vec3(0.5f, 0.5f, 0.5f));  
  37.     // 添加子节点  
  38.     pat1->addChild(node.get());  
  39.   
  40.     // 创建位置变换节点pat2  
  41.     osg::ref_ptr<osg::PositionAttitudeTransform> pat2 = new osg::PositionAttitudeTransform();  
  42.     // 设置位置为osg::Vec3(10.0f,0.0f,0.0f)  
  43.     pat2->setPosition(osg::Vec3(10.0f, 0.0f, 0.0f));  
  44.     // 添加子节点  
  45.     pat2->addChild(node.get());  
  46.   
  47.     // 添加到场景  
  48.     root->addChild(pat1.get());  
  49.     root->addChild(pat2.get());  
  50.   
  51.     // 优化场景数据  
  52.     osgUtil::Optimizer optimizer;  
  53.     optimizer.optimize(root.get());  
  54.   
  55.     // 设置场景数据  
  56.     viewer->setSceneData(root.get());  
  57.     // 初始化并创建窗口  
  58.     viewer->realize();  
  59.     // 开始渲染  
  60.     viewer->run();  
  61. }  

        运行程序,截图如图3-9所示

图3-9位置变换节点示例截图

3.3 矩阵变换节点

        矩阵变换节点(osg::MatrixTransform)同样继承自osg::Transform,其主要作用是负责场景中的知阵变换、矩阵的运算及坐标系的变换。后面要讲的动画更新也是用 MatrixTransform来设置移动和旋转通过使用矩阵变换节点(osg::MatrixTransform)可以对场景中的模型进行转平移等操作.

        osg::MatrixTransform的继承关系图如图3-10所示。

图3-10 osg::MatrixTransform 的继承关系图

        osg::MatrixTransform的常用主要成员函数如下

  1. void setMatrix(constMatrix &mat)// 设置矩阵  
  2. const Matrix &getMatrix() const // 得到矩阵  
  3. void preMult(constMatrix &mat)  // 递乘,比较类似于++a  
  4. void postMult(constMatrix&mat)  // 递乘,比较类似于a++  
  5. const Matrix &getInverseMatrix() const// 得到逆短阵  

3.4 矩阵变换节点示例

        矩阵变换节点(osg::MatrixTransform)示例的代码如程序清单3-3所示。

  1. void matrixTransform(const string &strDataFolder)  
  2. {  
  3.     //创建Viewer对象,场景浏览器  
  4.     osg::ref_ptr<osgViewer::Viewer> viewer = new osgViewer::Viewer();  
  5.     osg::ref_ptr<osg::GraphicsContext::Traits> traits = new osg::GraphicsContext::Traits;  
  6.     traits->x = 40;  
  7.     traits->y = 40;  
  8.     traits->width = 600;  
  9.     traits->height = 480;  
  10.     traits->windowDecoration = true;  
  11.     traits->doubleBuffer = true;  
  12.     traits->sharedContext = 0;  
  13.   
  14.     osg::ref_ptr<osg::GraphicsContext> gc = osg::GraphicsContext::createGraphicsContext(traits.get());  
  15.   
  16.     osg::ref_ptr<osg::Camera> camera = new osg::Camera;  
  17.     camera->setGraphicsContext(gc.get());  
  18.     camera->setViewport(new osg::Viewport(0, 0, traits->width, traits->height));  
  19.     GLenum buffer = traits->doubleBuffer ? GL_BACK : GL_FRONT;  
  20.     camera->setDrawBuffer(buffer);  
  21.     camera->setReadBuffer(buffer);  
  22.     viewer->addSlave(camera.get());  
  23.   
  24.     //创建场景组节点  
  25.     osg::ref_ptr<osg::Group> root = new osg::Group();  
  26.   
  27.     //创建一个节点,读取牛的模型  
  28.     string strDataPath = strDataFolder + "cow.osg";  
  29.     osg::ref_ptr<osg::Node> node = osgDB::readNodeFile(strDataPath);  
  30.   
  31.     //创建矩阵变换节点mt1  
  32.     osg::ref_ptr<osg::MatrixTransform> mt1 = new osg::MatrixTransform();  
  33.     //创建一个矩阵  
  34.     osg::Matrix m;  
  35.     //X方向平移10个单位  
  36.     m.makeTranslate(osg::Vec3(10.0f, 0.0f, 0.0f));  
  37.     //X轴旋转45  
  38.     m.makeRotate(45.0f, 1.0f, 0.0f, 0.0f);  
  39.     //设置矩阵  
  40.     mt1->setMatrix(m);  
  41.     //添加子节点  
  42.     mt1->addChild(node.get());  
  43.   
  44.     //创建矩阵变换节点mt2  
  45.     osg::ref_ptr<osg::MatrixTransform> mt2 = new osg::MatrixTransform();  
  46.     //创建一个矩阵  
  47.     osg::Matrix t;  
  48.     //X负方向上平移10个单位  
  49.     t.makeTranslate(osg::Vec3(-10.0f, 0.0f, 0.0f));  
  50.     //设置矩阵  
  51.     mt2->setMatrix(t);  
  52.     //添加子节点  
  53.     mt2->addChild(node.get());  
  54.   
  55.     //添加到场景  
  56.     root->addChild(mt1.get());  
  57.     root->addChild(mt2.get());  
  58.   
  59.     //优化场景数据  
  60.     osgUtil::Optimizer optimizer;  
  61.     optimizer.optimize(root.get());  
  62.   
  63.     //设置场景数据  
  64.     viewer->setSceneData(root.get());  
  65.   
  66.     //初始化并创建窗口  
  67.     viewer->realize();  
  68.   
  69.     //开始渲染  
  70.     viewer->run();  
  71. }  

        运行程序,截图如图3-11所示。

图 3-11矩阵变换节点示例截图

3.5 自动对齐节点

        自动对齐节点(osg::AutoTransform)也继承自og::Transform,它的主要作用是使节点自动对齐于摄像机或者屏幕。在实际应用中,通常可以用来显示一些不变化的文字或者其他的标识。

        osg::AutoTransform有如下3种对齐模式。

  1. enum AutoRotateMode  
  2. {  
  3.     NO_ROTATION,      // 无旋转  
  4.     ROTATE_TO_SCREEN, // 自动朝向屏幕  
  5.     ROTATE_TO_CAMERA  // 自动朝向相机  
  6. }; 

        osg::AutoTransform的继承关系图如图3-12所示。

图3-12 osg::AutoTransform 的继承关系图

3.6 自动对齐节点示例

        自动对齐节点(osg::AutoTransform)的示例代码如程序清单 3-4 所示(这用到了文字的显示,后面还有详细的讲解)。

  1. osg::ref_ptr<osg::Node> createAutoTransform(const string &strDataFolder, osg::Vec3& position, float size,  std::string& label, 
  2. osg::AutoTransform::AutoRotateMode autoMode, osgText::Text::AxisAlignment axisAlignment)  
  3. {  
  4.     osg::ref_ptr<osg::Geode> geode = new osg::Geode();  
  5.   
  6.     string strFontPath = strDataFolder + "fonts/cour.ttf";// 字体  
  7.     std::string font(strFontPath);  
  8.   
  9.     // 创建Text对象  
  10.     osg::ref_ptr<osgText::Text> text = new osgText::Text();  
  11.     geode->addDrawable(text.get());    
  12.     text->setFont(font);// 设置字体    
  13.     text->setFontResolution(128.0f, 128.0f);// 设置字体的分辨率,默认为32*32   
  14.     text->setCharacterSize(size);// 设置字体的大小    
  15.     text->setAlignment(osgText::Text::CENTER_CENTER);// 设置对齐方式     
  16.     text->setAxisAlignment(axisAlignment);// 设置方向      
  17.     text->setText(label);// 设置文字  
  18.       
  19.     geode->getOrCreateStateSet()->setMode(GL_LIGHTING, osg::StateAttribute::OFF);// 关闭光照  
  20.   
  21.     // 创建自动变换节点  
  22.     osg::ref_ptr<osg::AutoTransform> at = new osg::AutoTransform();     
  23.     at->addChild(geode.get());      // 添加子节点   
  24.     at->setAutoRotateMode(autoMode);// 设置自动变换方式  
  25.     at->setAutoScaleToScreen(false);// 根据屏幕大小来缩放节点,默认为false,设置为true时,节点无法缩放  
  26.     //at->setAutoScaleToScreen(true) ;     
  27.     at->setMinimumScale(0.0f);// 设置缩放的最大和最小比例  
  28.     at->setMaximumScale(5.0f);  
  29.     at->setPosition(position);   // 设置位置  
  30.   
  31.     return at.get();  
  32. }  
  33.   
  34. void autoTransform_3_4(const string &strDataFolder)  
  35. {  
  36.     osg::ref_ptr<osgViewer::Viewer> viewer = new osgViewer::Viewer();  
  37.     osg::ref_ptr<osg::GraphicsContext::Traits> traits = new osg::GraphicsContext::Traits;  
  38.     traits->x = 40;  
  39.     traits->y = 40;  
  40.     traits->width = 600;  
  41.     traits->height = 480;  
  42.     traits->windowDecoration = true;  
  43.     traits->doubleBuffer = true;  
  44.     traits->sharedContext = 0;  
  45.   
  46.     osg::ref_ptr<osg::GraphicsContext> gc = osg::GraphicsContext::createGraphicsContext(traits.get());  
  47.   
  48.     osg::ref_ptr<osg::Camera> camera = new osg::Camera;  
  49.     camera->setGraphicsContext(gc.get());  
  50.     camera->setViewport(new osg::Viewport(0, 0, traits->width, traits->height));  
  51.     GLenum buffer = traits->doubleBuffer ? GL_BACK : GL_FRONT;  
  52.     camera->setDrawBuffer(buffer);  
  53.     camera->setReadBuffer(buffer);  
  54.     viewer->addSlave(camera.get());  
  55.   
  56.     osg::ref_ptr<osg::Group> root = new osg::Group();  
  57.   
  58.     std::string text("Fly To Sky");  
  59.   
  60.     /* 
  61.     三种变换模式: 
  62.     ROTATE_TO_SCREEN  自动朝向屏幕 
  63.     ROTATE_TO_CAMERA    自动朝向相机 
  64.     NO_ROTATION          
  65.     */  
  66.   
  67.     // 添加ROTATE_TO_SCEREEN模式变换节点  
  68.     root->addChild(createAutoTransform(strDataFolder, osg::Vec3(0.0f, 0.0f, 0.0f), 60.0f, text,  
  69.         osg::AutoTransform::ROTATE_TO_SCREEN, osgText::Text::XY_PLANE));  
  70.   
  71.     //添加NO_ROTATION模式变换节点  
  72.     root->addChild(createAutoTransform(strDataFolder, osg::Vec3(0.0f, 0.0f, 0.0f), 60.0f, text,  
  73.         osg::AutoTransform::NO_ROTATION, osgText::Text::YZ_PLANE));  
  74.   
  75.     // 添加ROTATE_TO_CAMERA模式变换节点  
  76.     //root->addChild(createAutoTransform(osg::Vec3(0.0f,0.0f,0.0f),60.0f,text,  
  77.     //  osg::AutoTransform::ROTATE_TO_CAMERA,osgText::Text::XY_PLANE)) ;  
  78.   
  79.     // 优化场景数据  
  80.     osgUtil::Optimizer optimizer;  
  81.     optimizer.optimize(root.get());  
  82.   
  83.     viewer->setSceneData(root.get());  
  84.   
  85.     viewer->realize();  
  86.   
  87.     viewer->run();  

}  

        运行程序,截图如图3-13 所示。

图3-13自动对齐节点示例截图

3.7 开关节点

        开关节点(osg::Switch)继承自osg::Group节点使用开关节点可以渲染或者跳过指定的子节点。Switch 的优势在于能够根据当前渲染的负荷有选择地渲染子场景以实现渲染性能的均衡,或者在游戏的界面和层级之间有选择地切换。

        如果想在应用程序中实现允许或者禁止各种开关节点的渲染,需要调用节点更新回调或者节点访问器来控制其渲染状态。

        osg::Switch 的继承关系图如图3-14所示。

图3-14 osg::Switch 的继承关系图

        osg::Switch的主要常用成员函数如下

  1. void setNewChildDefaultValue(bool value) // 设置新加节点的初始值  
  2. bool getNewChildDefaultValue()const      // 得到新加节点的初始值  
  3. void setValue(unsigned int pos,bool value)// 设置索引为pos的值  
  4. bool getValue(unsigncdint pos)const //得到索引为 pos 的值  
  5. void setChildValue(const Node *child, bool value/设置 child 的值  
  6. bool getChildValue(const Node *child) const //得到 child 的值  
  7. bool setAllChildrenOff()//设置所有子节点不显示  
  8. bool setAllChildrenOn()//设置所有子节点显示  
  9. bool setSingleChildOn(unsigned int pos)//设置案引pos单个节点显示  

3.8 开关节点示例

        开关节点(osg::Switch)示例的代码如程序清单3-5所示。

  1. // 3_5 开关节点  
  2. void switch_3_5(const string &strDataFolder)  
  3. {  
  4.     //创建Viewer对象,场景浏览器  
  5.     osg::ref_ptr<osgViewer::Viewer> viewer = new osgViewer::Viewer();  
  6.     osg::ref_ptr<osg::GraphicsContext::Traits> traits = new osg::GraphicsContext::Traits;  
  7.     traits->x = 40;  
  8.     traits->y = 40;  
  9.     traits->width = 600;  
  10.     traits->height = 480;  
  11.     traits->windowDecoration = true;  
  12.     traits->doubleBuffer = true;  
  13.     traits->sharedContext = 0;  
  14.   
  15.     osg::ref_ptr<osg::GraphicsContext> gc = osg::GraphicsContext::createGraphicsContext(traits.get());  
  16.   
  17.     osg::ref_ptr<osg::Camera> camera = new osg::Camera;  
  18.     camera->setGraphicsContext(gc.get());  
  19.     camera->setViewport(new osg::Viewport(0, 0, traits->width, traits->height));  
  20.     GLenum buffer = traits->doubleBuffer ? GL_BACK : GL_FRONT;  
  21.     camera->setDrawBuffer(buffer);  
  22.     camera->setReadBuffer(buffer);  
  23.     viewer->addSlave(camera.get());  
  24.   
  25.     osg::ref_ptr<osg::Group> root = new osg::Group();  
  26.   
  27.     // 创建一个节点,读取牛的模型  
  28.     string strDataPath = strDataFolder + "cow.osg";  
  29.     osg::ref_ptr<osg::Node> node1 = new osg::Node();  
  30.     node1 = osgDB::readNodeFile(strDataFolder);  
  31.   
  32.     // 创建一个节点,读取滑翔机模型  
  33.     strDataPath = strDataFolder + "glider.osg";  
  34.     osg::ref_ptr<osg::Node> node2 = osgDB::readNodeFile(strDataPath);  
  35.   
  36.     // 创建一个开关节点,只渲染滑翔机而不渲染牛  
  37.     osg::ref_ptr<osg::Switch> swtich = new osg::Switch();   
  38.     swtich->addChild(node1.get(), false);// 添加牛的模型,但不渲染,默认为true    
  39.     swtich->addChild(node2.get(), true);// 添加滑翔机模型,状态为渲染  
  40.     root->addChild(swtich.get());  
  41.   
  42.     //优化场景数据  
  43.     osgUtil::Optimizer optimizer;  
  44.     optimizer.optimize(root.get());  
  45.     viewer->setSceneData(root.get());  
  46.     viewer->realize();  
  47.     viewer->run();  

        运行程序,截图如图3-15 所示(开关节点的开关渲染)

图3-15开关节点示例截图

3.9 细节层次节点

        细节层次节点(osg::LOD)继承自osg::Group。使用细节层次节点可以实现不同层次下物体的渲染。细节层次(Level of Detail,LOD)的基本思想是使用物体的一种简单形式表达物体,这样可以使绘制的图形尽量简洁。当视点靠近物体时,用详细的细节表示;当视点远离物体时,用简化模型来表示。由于距离原因,简化后的模型与细节详细的模型看上去很接近,这样就可以获得一个比较好的加速效果。在后面的章节中还会讲到粒子系统中的雾效,可以与LOD 一起使用,当一个物体进入不透明的雾化区域时,可以完全不用绘制这个物体。此外,还可以使用雾化机制实现时间临界绘制,通过将远平面移近,可以对物体进行提前裁剪,这样可以取得比较快的绘制速度,从而提高帧率。

        在OSG中,对于一个LOD 模型,它是一次性载入内存的,而且只是有选择地绘制渲染。osg::LOD的继承关系图如图3-16所示

图3-16 osg::LOD的继承关系图

        LOD计算的是视点到物体包围盒中心的距离,在应用程序中也可以改变这种方式,它有两种中心模式。LOD的切换同样是根据距离来确定的,应用程序中同样可以根据屏幕像素大小来切换,它也有两种变换模式。

  1. enum CenterMode  
  2. {  
  3.     USE_BOUNDING_SPHERE_CENTER,//包围盒中心  
  4.     USE_RDEFINED_CENTER//自定义中心,需要自己调用 setCentcr()  
  5. };  
  6.       
  7. enum RangeMode  
  8. {  
  9.     DISTANCE_FROM_EYE_POINT, // 距视点的距离  
  10.     PIXEL_SIZE_ON_SCREEN    // 屏幕像素的大小  
  11. };  

3.10 细节层次节点示例

        细节层次节点(osg::LOD)示例的代码如程序清单3-6所示。

  1. void LOD_3_6(const string &strDataFolder)  
  2. {  
  3.     //创建Viewer对象,场景浏览器  
  4.     osg::ref_ptr<osgViewer::Viewer> viewer = new osgViewer::Viewer();  
  5.     osg::ref_ptr<osg::GraphicsContext::Traits> traits = new osg::GraphicsContext::Traits;  
  6.     traits->x = 40;  
  7.     traits->y = 40;  
  8.     traits->width = 600;  
  9.     traits->height = 480;  
  10.     traits->windowDecoration = true;  
  11.     traits->doubleBuffer = true;  
  12.     traits->sharedContext = 0;  
  13.   
  14.     osg::ref_ptr<osg::GraphicsContext> gc = osg::GraphicsContext::createGraphicsContext(traits.get());  
  15.     osg::ref_ptr<osg::Camera> camera = new osg::Camera;  
  16.     camera->setGraphicsContext(gc.get());  
  17.     camera->setViewport(new osg::Viewport(0, 0, traits->width, traits->height));  
  18.     GLenum buffer = traits->doubleBuffer ? GL_BACK : GL_FRONT;  
  19.     camera->setDrawBuffer(buffer);  
  20.     camera->setReadBuffer(buffer);  
  21.     viewer->addSlave(camera.get());  
  22.   
  23.     osg::ref_ptr<osg::Group> root = new osg::Group();  
  24.   
  25.     // 创建一个节点,读取一个牛的模型  
  26.     string strDataPath = strDataFolder + "cow.osg";  
  27.     osg::ref_ptr<osg::Node> node1 = osgDB::readNodeFile(strDataPath);  
  28.   
  29.     // 创建一个节点,读取滑翔机模型  
  30.     strDataPath = strDataFolder + "glider.osg";  
  31.     osg::ref_ptr<osg::Node> node2 = osgDB::readNodeFile(strDataPath);  
  32.   
  33.     osg::ref_ptr<osg::LOD> lode = new osg::LOD();// 创建一个细节层次LOD节点  
  34.     lode->addChild(node1.get(), 0.0f, 30.0f);   // 添加子节点,在0-30范围内显示牛      
  35.     lode->addChild(node2.get(), 30.0f, 100.0f); //添加子节点,在30-100范围内显示滑翔机  
  36.   
  37.     // 写入lode.osg文件  
  38.     strDataPath = strDataFolder + "lode.osg";  
  39.     osgDB::writeNodeFile(*(lode.get()), strDataPath);  
  40.   
  41.     root->addChild(lode.get());// 添加到场景  
  42.   
  43.     // 优化场景数据  
  44.     osgUtil::Optimizer optimizer;  
  45.     optimizer.optimize(root.get());  
  46.     viewer->setSceneData(root.get());  
  47.     viewer->realize();  
  48.     viewer->run();  
  49. }  

        运行程序,截图如图3-17 所示(可以进行各细节层次间的切换)。

图3-17 细节层次节点示例截图

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/244945.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

GoWin FPGA, GPIO--- startup2

一个Bank只能用一个电压&#xff0c;假如同一个Bank&#xff0c;在引脚里设置不同的电压&#xff0c;编译不过。 解释说明 2. 错误引脚限制 以上编译设置会导致编译错误。

Docker | 发布镜像到镜像仓库

✅作者简介:大家好,我是Leo,热爱Java后端开发者,一个想要与大家共同进步的男人😉😉 🍎个人主页:Leo的博客 💞当前专栏:Docker系列 ✨特色专栏: MySQL学习 🥭本文内容:Docker | 发布镜像到镜像仓库 📚个人知识库: [Leo知识库]https://gaoziman.gitee.io/bl…

std::vector

这里主要介绍下reserce/resize、push_back/emplace_back、shrink_to_fit/clear等接口&#xff1b; 1. reserve and resize C的vector对象可以通过reserve方法来设置vector对象的容量&#xff0c;通过resize方法来改变vector对象的大小。reserve所设置的容量指的是vector容器中可…

0基础学习VR全景平台篇第127篇:什么是VR全景/720全景漫游?

“全景”作为一种表现宽阔视野的手法&#xff0c;在很久之前就得到了普遍的认同。北宋年间&#xff0c;由张择端绘制的《清明上河图》就是一幅著名的全景画。摄影术出现后&#xff0c;全景摄影也随之而生。 到今天&#xff0c;全景拍摄不再被专业摄影师所独享&#xff0c;广大…

云计算与AI融合:Amazon Connect开创客户服务智能时代

授权说明&#xff1a;本篇文章授权活动官方亚马逊云科技文章转发、改写权&#xff0c;包括不限于在 亚马逊云科技开发者社区, 知乎&#xff0c;自媒体平台&#xff0c;第三方开发者媒体等亚马逊云科技官方渠道 在亚马逊云科技 re:Invent 2023 大会上&#xff0c;Amazon Connect…

[AutoSar]状态管理(四)单核BswM(二)流程、配置、 代码

目录 关键词平台说明一、BswM的模式处理流程图二、stand state handling三、配置、代码、状态转移3.1 initial -> wakeup   3.2 WakeUp -> Run3.3 Run -> PostRun &#xff08;first step&#xff09;3.4 Run -> PostRun &#xff08;second step&#xff09;3.5…

Python安装报错: This environment is externally managed

error: externally-managed-environment This environment is externally managed ╰─> To install Python packages system-wide, try apt installpython3-xyz, where xyz is the package you are trying toinstall.这个错误信息表示当前Python环境是由系统外部管理的&…

基于Docker-Compose实现ELK+Kafka搭建分布式日志采集系统

ELKKafka搭建日志采集系统 ELK概述搭建与配置docker-compose.yml配置日志采集规则启动服务 模拟发送日志消息日志发送队列日志切面配置application.yaml发送日志消息 Kibana的使用创建索引模式Discovery搜索数据可视化数据 ELKRabbitMQ发送日志消息配置日志采集规则 ELK概述 E…

Java IO 流详解

Java IO 流详解 1 .Java IO概念 Java IO&#xff1a;即 Java 输入 / 输出系统。 Java 的 IO 模型设计非常优秀&#xff0c;它使用 Decorator (装饰者)模式&#xff0c;按功能划分 Stream &#xff0c;您可以动态装配 这些 Stream &#xff0c;以便获得您需要的功能。 Stream &…

20 Redis进阶 - 运维监控

1、理解Redis监控 Redis运维和监控的意义不言而喻&#xff0c;可以以下三个方面入手 1.首先是Redis自身提供了哪些状态信息&#xff0c;以及有哪些常见的命令可以获取Redis的监控信息; 2.一些常见的UI工具可以可视化的监控Redis; 3.理解Redis的监控体系;2、Redis自身状态及命…

【Java反射详解】

Java反射详解 &#x1f38a;专栏【Java】 &#x1f354;喜欢的诗句&#xff1a;关山难越&#xff0c;谁悲失路之人。 萍水相逢&#xff0c;尽是他乡之客。 &#x1f386;音乐分享【Counting Stars 】 欢迎并且感谢大家指出问题&#x1f970; 1.什么是反射 所谓的反射就是java…

365锦鲤助手 砍价小程序源码 流量主引流裂变

源码介绍 修改版365锦鲤 助手&#xff0c; 砍价小程序源码 流量主引流裂变 拼多多商品快速丰富产品内容满足广大用户需求&#xff1b;流量矩阵让流量都进你的圈子飞起来&#xff1b;长期盈利、项目稳定 1.后台安装微擎 2安装应用 后台打包上传

PPINN Parareal physics-informed neural network for time-dependent PDEs

论文阅读&#xff1a;PPINN Parareal physics-informed neural network for time-dependent PDEs PPINN Parareal physics-informed neural network for time-dependent PDEs简介方法PPINN加速分析 实验确定性常微分方程随机常微分方程Burgers 方程扩散反应方程 总结 PPINN Par…

Npm安装vue3报错(node:25436) MaxListenersExceededWarning:

运行命令安装vue3时 npm create vuelatest 报了错误(node:25436) MaxListenersExceededWarning: (忘记截报错的图了&#xff0c;后面还有一大串英文) 搞了很久发现是网络的原因&#xff0c;我没有修改镜像地址&#xff0c;导致访问很慢&#xff0c;于是去npmmirror 镜像站 …

字符雨canvas

整体思路&#xff1a; 确定好字符雨的具体字符是什么&#xff0c;需要多少行多少列这里是写死的其实也可以用循环加随机的方式生成不一样的字符雨&#xff0c;行列也可以读一下宽度然后做一下出发算一下也行首先得有一张画布搞起&#xff0c;然后循环列数去绘画字符定时器循环…

泰森多边形半平面求交 - 洛谷 - P3297 [SDOI2013] 逃考

欢迎关注更多精彩 关注我&#xff0c;学习常用算法与数据结构&#xff0c;一题多解&#xff0c;降维打击。 往期相关背景半平面求交 点击前往 voronoi 图求解点击前往 题目大意 题目链接 https://www.luogu.com.cn/problem/P3297 小杨家是一个矩阵&#xff0c;所有亲戚都在…

Monkey工具之fastbot-iOS实践

背景 目前移动端App上线后 crash 率比较高&#xff0c; 尤其在iOS端。我们需要一款Monkey工具测试App的稳定性&#xff0c;更早的发现crash问题并修复。 去年移动开发者大会上有参加 fastbot 的分享&#xff0c;所以很自然的就想到Fastbot工具。 Fastbot-iOS安装配置 准备工…

变电站蓄电池在线监测系统(论文+源码)

1. 系统设计 本次课题为变电站蓄电池在线监测系统的设计&#xff0c;其系统架构如图3.1所示&#xff0c;包括了主控制器STC89C52单片机&#xff0c;液晶显示器LCD1602,模数转换器ADC0832&#xff0c;电流传感器ACS712&#xff0c;分压电阻&#xff0c;蜂鸣器以及温度传感器。在…

实用篇 | 3D建模中Blender软件的下载及使用[图文详情]

本文基于数字人系列的3D建模工具Blender软件的安装及使用&#xff0c;还介绍了图片生成3D模型的AI工具~ 目录 1.Blender的下载 2.Blender的使用 3.安装插件(通过压缩包安装) 4.实例 4.1.Blender使用MB-Lab插件快速人体模型建构 4.1.1.点击官网&#xff0c;进行下载 4.1.…

消息可靠性保证

回顾RabbitMQ的消息传递过程 如图所示&#xff0c;发生消息丢失的可能阶段也就是生产者发送消息&#xff0c;时rabbitmq存储消息时&#xff0c;消费者消费消息时。项目源码&#xff1a;gitee 生产者发送消息阶段 生产者发送消息时把交换机名写错生产者发送消息时把routingK…