1. 概述

ContextCapture(Smart3D)生成的倾斜摄影模型数据一般都形如如下组织结构:

在Data目录下包含了分块的瓦片数据,每个瓦片都是一个LOD文件夹。osg能够直接读取osgb格式,理论上只需要依次加载每个LOD的金字塔层级最高的osgb,整个倾斜摄影模型数据就加载进来了。不过有点麻烦的是这类数据缺乏一个整体加载的入口,如果每次加载都遍历整个文件夹加载的话,会影响加载的效率。所以一般的数据查看软件都会为其增加一个索引。

这里就给倾斜摄影数据添加一个osgb格式的索引文件,生成后就可以通过OSG直接加载整个倾斜摄影模型数据。

2. 实例

2.1. 代码

具体的实现代码如下:

  1. #include <iostream>
  2. #include <string>
  3. #include <QDir>
  4. #include <osgViewer/Viewer>
  5. #include <osgDB/ReadFile>
  6. #include <osgDB/WriteFile>
  7. using namespace std;
  8. //查找目录下所有的文件夹
  9. static void findDir(string dir, vector<string>& subDirs)
  10. {
  11. //
  12. subDirs.clear();
  13. QDir fromDir(QString::fromLocal8Bit(dir.c_str()));
  14. QStringList filters;
  15. //
  16. QFileInfoList fileInfoList = fromDir.entryInfoList(filters, QDir::AllDirs | QDir::Files);
  17. foreach(QFileInfo fileInfo, fileInfoList)
  18. {
  19. if (fileInfo.fileName() == "." || fileInfo.fileName() == "..")
  20. {
  21. continue;
  22. }
  23. if (fileInfo.isDir())
  24. {
  25. QByteArray dir = fileInfo.filePath().toLocal8Bit();
  26. subDirs.push_back(dir.data());
  27. }
  28. }
  29. }
  30. //得到文件路径的文件名 C:\\b\\a(.txt) -> a
  31. static std::string DirOrPathGetName(std::string filePath)
  32. {
  33. size_t m = filePath.find_last_of('/');
  34. if (m == string::npos)
  35. {
  36. return filePath;
  37. }
  38. size_t p = filePath.find_last_of('.');
  39. if (p != string::npos && p > m) //没有点号或者
  40. {
  41. filePath.erase(p);
  42. }
  43. std::string dirPath = filePath;
  44. dirPath.erase(0, m + 1);
  45. return dirPath;
  46. }
  47. void createObliqueIndexes(std::string fileDir)
  48. {
  49. string dataDir = fileDir + "/Data";
  50. osg::ref_ptr<osg::Group> group = new osg::Group();
  51. vector<string> subDirs;
  52. findDir(dataDir, subDirs);
  53. for (size_t i = 0; i < subDirs.size(); i++)
  54. {
  55. string name = DirOrPathGetName(subDirs[i]);
  56. string path = subDirs[i] + "/" + name + ".osgb";
  57. osg::ref_ptr<osg::Node> node = osgDB::readNodeFile(path);
  58. osg::ref_ptr<osg::PagedLOD> lod = new osg::PagedLOD();
  59. auto bs = node->getBound();
  60. auto c = bs.center();
  61. auto r = bs.radius();
  62. lod->setCenter(c);
  63. lod->setRadius(r);
  64. lod->setRangeMode(osg::LOD::RangeMode::PIXEL_SIZE_ON_SCREEN);
  65. osg::ref_ptr<osg::Geode> geode = new osg::Geode;
  66. geode->getOrCreateStateSet();
  67. lod->addChild(geode.get());
  68. std::string relativeFilePath = "./Data/" + name + "/" + name + ".osgb"; //相对路径
  69. lod->setFileName(0, "");
  70. lod->setFileName(1, relativeFilePath);
  71. lod->setRange(0, 0, 1.0); //第一层不可见
  72. lod->setRange(1, 1.0, FLT_MAX);
  73. lod->setDatabasePath("");
  74. group->addChild(lod);
  75. }
  76. std::string outputLodFile = fileDir + "/Data.osgb";
  77. osgDB::writeNodeFile(*group, outputLodFile);
  78. }
  79. int main(int argc, char *argv[])
  80. {
  81. string fileDir = "D:/Data/scene/city";
  82. std::string outputLodFile = fileDir + "/Data.osgb";
  83. createObliqueIndexes(fileDir);
  84. osgViewer::Viewer viewer;
  85. osg::Node * node = new osg::Node;
  86. node = osgDB::readNodeFile(outputLodFile);
  87. viewer.setSceneData(node);
  88. return viewer.run();
  89. }

2.2. 解析

如果直接读取每一块的LOD然后通过osgDB::writeNodeFile写入到一个osgb文件,这个文件就会保存所有块的LOD第一层信息。这样在第二册加载的时候还是会比较慢,所以这里就创建了一个空的节点,形成了索引所有LOD块的数据结构。对于每一块数据,新建两层LOD,第一层为自身的空白节点,第二层为分块LOD的第一层数据:

  1. osg::ref_ptr<osg::Node> node = osgDB::readNodeFile(path);
  2. osg::ref_ptr<osg::PagedLOD> lod = new osg::PagedLOD();
  3. auto bs = node->getBound();
  4. auto c = bs.center();
  5. auto r = bs.radius();
  6. lod->setCenter(c);
  7. lod->setRadius(r);
  8. lod->setRangeMode(osg::LOD::RangeMode::PIXEL_SIZE_ON_SCREEN);
  9. osg::ref_ptr<osg::Geode> geode = new osg::Geode;
  10. geode->getOrCreateStateSet();
  11. lod->addChild(geode.get());
  12. std::string relativeFilePath = "./Data/" + name + "/" + name + ".osgb"; //相对路径
  13. lod->setFileName(0, "");
  14. lod->setFileName(1, relativeFilePath);
  15. lod->setRange(0, 0, 1.0); //第一层不可见
  16. lod->setRange(1, 1.0, FLT_MAX);
  17. lod->setDatabasePath("");
  18. group->addChild(lod);

LOD的Center和Radius都非常重要,需要预先设置好;setRangeMode设置了细节层级调度的模式,一般都为PIXEL_SIZE_ON_SCREEN;setFileName设置了每一层的数据路径,setRange确定了当前层级的范围。由于这个LOD只是个索引文件,所以会设置第二层为极大的可见范围值。

3. 结果

可以像加载普通OSGB文件一样加载这个索引文件,通过osgviewer加载的效果如下:

OSG加载倾斜摄影数据的更多相关文章

  1. Cesium加载倾斜摄影数据

    (1)倾斜摄影数据仅支持 smart3d 格式的 osgb 组织方式, 数据目录必须有一个 “Data” 目录的总入口, “Data” 目录同级放置一个 metadata.xml 文件用来记录模型的位 ...

  2. osg gdal加载tif数据文件

    osg加载.tif地形数据文件 #ifdef _WIN32 #include <Windows.h> #endif // _WIN32 #include <iostream> ...

  3. geotrellis使用(二十三)动态加载时间序列数据

    目录 前言 实现方法 总结 一.前言        今天要介绍的绝对是华丽的干货.比如我们从互联网上下载到了一系列(每天或者月平均等)的MODIS数据,我们怎么能够对比同一区域不同时间的数据情况,采用 ...

  4. WPF DataGrid 性能加载大数据

    WPF(Windows Presentation Foundation)应用程序在没有图形加速设备的机器上运行速度很慢是个公开的秘密,给用户的感觉是它太吃资源了,WPF程序的性能和硬件确实有很大的关系 ...

  5. 基于zepto的H5/移动端tab切换触摸拖动加载更多数据

    以前实现移动端的滑动加载更多实现的方法是当滚动条快到页面底部时就自动加载更多的数据,在这方面很多人都用的是"西门的后花园"写的一个叫dropload的插件,这个插件用起来也很好,很 ...

  6. iOS --- UIWebView的加载本地数据的三种方式

    UIWebView是IOS内置的浏览器,可以浏览网页,打开文档  html/htm  pdf   docx  txt等格式的文件.  safari浏览器就是通过UIWebView做的. 服务器将MIM ...

  7. jQuery.ajax( options ) : 通过 HTTP 请求加载远程数据

    jQuery.ajax( options ) : 通过 HTTP 请求加载远程数据 这个是jQuery 的底层 AJAX 实现.简单易用的高层实现见 $.get, $.post 等. $.ajax() ...

  8. Tree:加载列表数据

    Tree控件,需要提供一个树形的JSON数据,才能正常显示. 通常,开发者在后台可以这样做: 1)从数据库查询出一个列表数据 2)在后台,将列表数据转换为树形数据 3)通过JSON方式返回 在前台页面 ...

  9. 实现winform DataGridView控件判断滚动条是否滚动到当前已加载的数据行底部

    判断 DataGridView控件滚动条是否滚动到当前已加载的数据行底部,其实方法很简单,就是为DataGridView控件添加Scroll事件,然后写入以下代码就可以了,应用范围:可实现分部加载数据 ...

随机推荐

  1. Python数据库MySQL之数据备份、pymysql模块

    一 IDE工具介绍 生产环境还是推荐使用mysql命令行,但为了方便我们测试,可以使用IDE工具 下载链接:https://pan.baidu.com/s/1bpo5mqj 掌握: #1. 测试+链接 ...

  2. supervisor 的使用 (fastcgi管理)

    本文主要介绍 supervisor 对 fastcgi 进程的管理 fastcgi 进程的管理 在php 中,php-fpm 有主进程来管理和维护子进程的数量.但是并不是所有的服务都有类似的主进程来做 ...

  3. 各种版本docker下载的中国开源地址

    最近在群里听说Docker很火,于是自己抱着试试的态度,想玩玩,可是遇到了一些问题,记录下来,方便备忘,也方便防止大家被坑. 我的虚拟机装的是centos 6.5,百度了好多教程,丫的,都不解释,就一 ...

  4. 少儿编程Scratch第一讲:Scratch完美的初体验

    素材及视频下载 链接:https://pan.baidu.com/s/1qX0T2B_zczcLaCCpiRrsnA提取码:xfp8 都说未来是人工智能.计算机程式控制的时代,如何让青少年接触计算机编 ...

  5. Java第三十四天,IO操作(续集),非基本对象的读写——序列化流

    一.序列化与反序列化 以前在对文件的操作过程当中,读写的对象都是最基本的数据类型,即非引用数据类型.那么如果我们对饮用数据类型(即对象类型)数据进行读写时,应该如何做呢?这就用到了序列化与反序列化. ...

  6. PyJWT 详解

    1.首先,我们需要先了解 JWT 的概念,所以我们先看pyjwt的官网 https://jwt.io/ 2.对于官方 JWT 有两篇博文写的不错分别如下: https://blog.csdn.net/ ...

  7. Oacle学习-01Oracle的安装

    @ 目录 下载Oracle 安装Oracle 安装plsqldeveloper客户端 下载Oracle 官方下载地址:Oracle下载 网盘地址:链接:https://pan.baidu.com/s/ ...

  8. Python Requests-学习笔记(8)-重定向与请求历史

    重定向与请求历史 默认情况下,除了 HEAD, Requests会自动处理所有重定向. 可以使用响应对象的 history 方法来追踪重定向. Response.history 是一个:class:R ...

  9. AJ学IOS(04)UI之半小时搞定Tom猫

    AJ分享 必须精品  效果图 曾经风靡一时的tom猫其实制作起来那是叫一个相当的easy啊 功能全部实现,(关键是素材,没有素材的可以加我微信) 新手也可以很快的完成tom这个很拉轰的ios应用哦 然 ...

  10. [模板]SPFA判负环

    目录 一.BFS法判负环 二.DFS法判负环 三.SPFA判正环 一.BFS法判负环 Code: #include<bits/stdc++.h> #define re register # ...