天下武功,唯快不破

最近网友问了关于点云、倾斜摄影数据的性能优化问题。本来想刀枪剑戟、斧钺勾叉给弄了,但是后来想性能其实是个系统问题,要在第22节分成数小节扎扎实实的讲一讲。

鸣谢

非常感谢王锐王大神的cookbook,我准备主要参考它里面关于性能的一章。也就是第8章。

本节资源

本文集包括本节所有资源包括模型代码都在此下载,按节的序号有文件或文件夹:

注意: 务必使用浏览器打开:
【击此打开网盘资源链接】

问题描述

我们为什么使用googlEarth或者osgEarth的时候,原则上可以加载无限大的数据呢,其原因就是因为其使用的是树状的组织结构,如下:

我们仍然来拿地球来想象,Level0是最粗的球,我们离的很远的时候是这个球。Level1是我们拉近一点,地球会一分为八,然后我们再对着其中一个角拉近就分裂成Level2的模样,这个角又一分为八。

粗的级别就显示粗的内容,细的级别就加载细的内容,就像高清影像的瓦片一样,第0级可以是整个地球,分辨率是256X256,然后一分为八,每张图片的范围变成了第0级的八分之一,但是分辨率仍然是256x256,就越往下拉越清晰。

本节我们就来构建这样一个八叉树的结构,本节如果你搞明白了,就入门了八叉树的结构,因为在构建树状结构的时候往往会用到递归。理解起来还是有点费劲的。LOD和PagedLOD都大量的用作构建数字地球等,其实原理都和本节差不多。

本节功能

1、随机生成5000个球,坐标范围在[-500, 500]。
2、对这5000个球生成八叉树,其结束条件是这样的:当结点的孩子小于16个时认为是叶结点,就不再往下分了。或者树的深度大于32也不往下分了。3、每一层我们用一个LOD来保存,当离的很远时显示父亲(把包围盒绘制出来),当拉近时父亲就一分为八。直到显示叶结点。

听起来就晕了吧,一定要好好的缕一缕。

具体实现

1、随机生成小球没有什么好说的。我们将生成的所有的小球的包围盒都压在globalElements当中,将所有小球组成的最大包围盒记为globalBound

    typedef std::pair<std::string, osg::BoundingBox> ElementInfo;osg::BoundingBox globalBound;std::vector<OctreeBuilder::ElementInfo> globalElements;for ( unsigned int i=0; i<5000; ++i ){osg::Vec3 pos = randomVector( -500.0f, 500.0f );float radius = randomValue( 0.5f, 2.0f );std::stringstream ss; ss << "Ball-" << i+1;osg::Vec3 min = pos - osg::Vec3(radius, radius, radius);osg::Vec3 max = pos + osg::Vec3(radius, radius, radius);osg::BoundingBox region(min, max);globalBound.expandBy( region );globalElements.push_back( OctreeBuilder::ElementInfo(ss.str(), region) );}

2.2、然后我们直接就开始调用OctreeBuilder的build方法开始构建八叉树:

    OctreeBuilder octree;osg::ref_ptr<osg::Group> root = octree.build( 0, globalBound, globalElements );

2.3、build是个递归方法,有三个参数,第一个是当前级别,第二个是当前包围盒,第三个是当前元素,其中主要干了以下几件事:
a) 先把当前包围盒的最大点、中间点、最小点给记录下来到extentSet中,以便以这三个数为界一分为八:

    //存放当前包围盒的最大、中间、最小点,以为划分八叉树做准备osg::Vec3 extentSet[3] = {total._min,(total._max + total._min) * 0.5f,total._max};

b) 把当前元素每个都判断一下是不是在当前盒子中,有人说了build(0,…)的时候那不废话吗,肯定都在盒子里了。但是build(1,…)的时候就不一定了。这一步是要判断传入的元素(往往是父结点的所有元素)是不是在当前盒子(子结点的盒子里),因此要进行判断:

    std::vector<ElementInfo> childData;//遍历父结点的所有孩子,让包含在当前盒子里的,不完全包含但是中点在盒子里的,都压入到//当前盒子的子结点for ( unsigned int i=0; i<elements.size(); ++i ){const ElementInfo& obj = elements[i];if ( total.contains(obj.second._min) && total.contains(obj.second._max) )childData.push_back( obj );else if ( total.intersects(obj.second) ){osg::Vec3 center = (obj.second._max + obj.second._min) * 0.5f;if ( total.contains(center) ) childData.push_back( obj );}}

c) 判断完成之后,要看看当前盒子里的元素数量和级别,以此来判断当前盒子是不是叶结点

    //如果当前结点的孩子数量已经达标,或者层数已经达标,则认为//是叶结点bool isLeafNode = false;if ( (int)childData.size()<=_maxChildNumber || depth>_maxTreeDepth )isLeafNode = true;

d) 如果不是叶结点,就继续再一分为八,这个时候就把a)里面存的数字extentSet,拿它来将空间分成八个盒子:

        osg::ref_ptr<osg::Group> childNodes[8];//空间一分为八2*2*2for ( s[0]=0; s[0]<2; ++s[0] ) //x{for ( s[1]=0; s[1]<2; ++s[1] ) //y{for ( s[2]=0; s[2]<2; ++s[2] ) //z{// Calculate the child extent//extentSet 0是最小,1是中间,2是最大//下面这个小算法有点磨人,分另求出min和max的x, y, z自己好好推几个试试osg::Vec3 min, max;for ( int a=0; a<3; ++a ){min[a] = (extentSet[s[a] + 0])[a];max[a] = (extentSet[s[a] + 1])[a];}//这么求id是为了确保唯一性int id = s[0] + (2 * s[1]) + (4 * s[2]);childNodes[id] = build( depth+1, osg::BoundingBox(min, max), childData );}}}

e) 如果是叶结点,那就构建一个LOD,离的远时,拿其父的包围盒构建一个盒子,离的近的时候就显示叶结点(小球)。

   else //找到叶结点,递归就结束了{for ( unsigned int i=0; i<childData.size(); ++i ){const ElementInfo& obj = childData[i];osg::Vec3 center = (obj.second._max + obj.second._min) * 0.5;float radius = (obj.second._max - obj.second._min).length() * 0.5f;//创建一个球group->addChild( createElement(obj.first, center, radius) );}}osg::Vec3 center = (total._max + total._min) * 0.5;float radius = (total._max - total._min).length() * 0.5f;//最后创建一个LOD,离的远了显示调试盒子,离的近了显示分的组osg::LOD* level = createNewLevel( depth, center, radius );level->insertChild( 0, createBoxForDebug(total._max, total._min) );  // For debug uselevel->insertChild( 1, group.get() );return level;

最后

理解了这一节,真算是你这个关于八叉树,四叉树方面算是有感觉了。你可能会有疑问,只有最底层才显示东西,这样的结构有什么用,因此你可以将小球进行抽稀,给每一级都放个球,这样就不会只显示一个空盒子了。地球就是这样的,父结点也有纹理高程,子结点也有纹理高程。

第22.7节 性能篇-使用八叉树结构来管理场景相关推荐

  1. 第22.9节 性能篇-使用KdTree来做性能优化

    天下武功,唯快不破 最近网友问了关于点云.倾斜摄影数据的性能优化问题.本来想刀枪剑戟.斧钺勾叉给弄了,但是后来想性能其实是个系统问题,要在第22节分成数小节扎扎实实的讲一讲. 鸣谢 非常感谢王锐王大神 ...

  2. 第22.6节 性能篇-使用遮档查询来拣选物体

    天下武功,唯快不破 最近网友问了关于点云.倾斜摄影数据的性能优化问题.本来想刀枪剑戟.斧钺勾叉给弄了,但是后来想性能其实是个系统问题,要在第22节分成数小节扎扎实实的讲一讲. 鸣谢 非常感谢王锐王大神 ...

  3. 使用八叉树结构来管理场景

    1.问题描述 我们为什么使用googlEarth或者osgEarth的时候,原则上可以加载无限大的数据呢,其原因就是因为其使用的是树状的组织结构,如下: 我们仍然来拿地球来想象,Level0是最粗的球 ...

  4. 阿里云RDS金融数据库(三节点版) - 性能篇

    标签 PostgreSQL , MySQL , 三节点版 , 金融数据库 , Raft , 分布式共享存储版 背景 终于到了性能篇,三节点同时满足了企业对数据库的可用性.可靠性的要求,那么性能如何呢? ...

  5. 【朝花夕拾】Android性能篇之(二)Java内存分配

    前言       原文:[朝花夕拾]Android性能篇之(二)Java内存分配        在内存方面,相比于C/C++程序员,咱们java系程序员算是比较幸运的,因为对于内存的分配和回收,都交给 ...

  6. 第八节: EF的性能篇(一) 之 EF自有方法的性能测试

    一. 开发中常见的性能问题 我们在日常开发过程中,由于一些不好的习惯,经常会导致所写的代码性能低下,却毫无发觉,下面就总结一下常见的一些性能问题. 1. 真假分页 ① 假分页: db.xxx.toLi ...

  7. 【Linux 性能优化系列】Linux 性能优化 -- CPU 性能篇(三) Linux 软中断

    [Linux 性能优化系列]Linux 性能优化 -- CPU 性能篇(三) Linux 软中断 [1]相关概念 [1.1]中断 中断其实是一种异步的事件处理机制,可以提高系统的并发处理能力:为了减少 ...

  8. 【Linux 性能优化系列】Linux 性能优化 -- CPU 性能篇(一) 平均负载、上下文切换、CPU 使用率

    [Linux 性能优化系列]Linux 性能优化 -- CPU 性能篇(一) 平均负载.上下文切换.CPU 使用率 [1]相关概念 [1.1]平均负载 平均负载是指单位时间内,系统处于可运行状态和不可 ...

  9. Synology DS412+ 安装与性能篇

    [安装篇] DS412+入手也有好几天了,开箱的时候并没有拍多少照片,因此安装这篇就没法细写了.好在网络上类似的文章还是有的,比如这篇就写得相当详细: http://t17.techbang.com/ ...

  10. linux查看cpu运行速度,linux 性能篇 -- 查看cpu核数

    linux 性能篇 查看物理CPU的个数 #cat /proc/cpuinfo |grep "physical id"|sort |uniq|wc -l 查询系统CPU的物理核数( ...

最新文章

  1. 关于何种情况下使用DataGrid、DataList或Repeater的一些讨论
  2. 独立云计算服务商的多维实践之道:用户需求驱动变革
  3. VTK:图表之TreeBFSIterator
  4. 13.2.10 Ajax操作
  5. 伪元素::before与::after的用法
  6. 使用控制结构——条件分支语句——简单条件
  7. 9家专利拥有者退出MPEG LA HEVC 华为加入HEVC Advance
  8. 前端学习(1950)vue之电商管理系统电商系统之渲染添加父类的对话框
  9. java如何编译运行?
  10. 原来竟然还有这种局部变量!
  11. 设计模式学习笔记—策略模式
  12. 福布斯发布区块链50强 这5家中国公司上榜
  13. 概率图模型-原理与技术 第二章 基础知识 学习笔记
  14. python抓取网易云音乐评论_如何爬取网易云音乐评论?
  15. 合上电脑盖时,电脑断网-原因及解决方法
  16. linux系统etc什么意思,etc.是什么意思 linux下的etc是什么意思
  17. Request Response
  18. 黑马程序员——OC语言------类的声明实现、面向对象
  19. VS2005编译器选项
  20. 《C++ Primer》第15章 15.2节习题答案

热门文章

  1. java中国象棋编程思想_中国象棋网络对战平台系统.doc
  2. Matlab/Simulink怎么输出低版本仿真文件?
  3. AutoCAD如何将dwf转成dwg格式
  4. 【STM32】基于STM32F407实现串口通信
  5. EA enterprise architect 画用例图
  6. 微信小程序开发的基本流程__BaiMoci
  7. Springboot集成Activiti7
  8. 斐讯 N1 降级、刷机及 Armbian 安装 [2019.7.23]
  9. 拜耳2020年10个新植保制剂商业化,3个生物技术性状项目推进至上市阶段
  10. 区块链核心技术演进之路-共识机制演进