ContextCapture(Smart3D)生成的傾斜攝影模型數據通常都形如以下組織結構:
node
在Data目錄下包含了分塊的瓦片數據,每一個瓦片都是一個LOD文件夾。osg可以直接讀取osgb格式,理論上只須要依次加載每一個LOD的金字塔層級最高的osgb,整個傾斜攝影模型數據就加載進來了。不過有點麻煩的是這類數據缺少一個總體加載的入口,若是每次加載都遍歷整個文件夾加載的話,會影響加載的效率。因此通常的數據查看軟件都會爲其增長一個索引。ios
這裏就給傾斜攝影數據添加一個osgb格式的索引文件,生成後就能夠經過OSG直接加載整個傾斜攝影模型數據。數據結構
具體的實現代碼以下:spa
#include <iostream> #include <string> #include <QDir> #include <osgViewer/Viewer> #include <osgDB/ReadFile> #include <osgDB/WriteFile> using namespace std; //查找目錄下全部的文件夾 static void findDir(string dir, vector<string>& subDirs) { // subDirs.clear(); QDir fromDir(QString::fromLocal8Bit(dir.c_str())); QStringList filters; // QFileInfoList fileInfoList = fromDir.entryInfoList(filters, QDir::AllDirs | QDir::Files); foreach(QFileInfo fileInfo, fileInfoList) { if (fileInfo.fileName() == "." || fileInfo.fileName() == "..") { continue; } if (fileInfo.isDir()) { QByteArray dir = fileInfo.filePath().toLocal8Bit(); subDirs.push_back(dir.data()); } } } //獲得文件路徑的文件名 C:\\b\\a(.txt) -> a static std::string DirOrPathGetName(std::string filePath) { size_t m = filePath.find_last_of('/'); if (m == string::npos) { return filePath; } size_t p = filePath.find_last_of('.'); if (p != string::npos && p > m) //沒有點號或者 { filePath.erase(p); } std::string dirPath = filePath; dirPath.erase(0, m + 1); return dirPath; } void createObliqueIndexes(std::string fileDir) { string dataDir = fileDir + "/Data"; osg::ref_ptr<osg::Group> group = new osg::Group(); vector<string> subDirs; findDir(dataDir, subDirs); for (size_t i = 0; i < subDirs.size(); i++) { string name = DirOrPathGetName(subDirs[i]); string path = subDirs[i] + "/" + name + ".osgb"; osg::ref_ptr<osg::Node> node = osgDB::readNodeFile(path); osg::ref_ptr<osg::PagedLOD> lod = new osg::PagedLOD(); auto bs = node->getBound(); auto c = bs.center(); auto r = bs.radius(); lod->setCenter(c); lod->setRadius(r); lod->setRangeMode(osg::LOD::RangeMode::PIXEL_SIZE_ON_SCREEN); osg::ref_ptr<osg::Geode> geode = new osg::Geode; geode->getOrCreateStateSet(); lod->addChild(geode.get()); std::string relativeFilePath = "./Data/" + name + "/" + name + ".osgb"; //相對路徑 lod->setFileName(0, ""); lod->setFileName(1, relativeFilePath); lod->setRange(0, 0, 1.0); //第一層不可見 lod->setRange(1, 1.0, FLT_MAX); lod->setDatabasePath(""); group->addChild(lod); } std::string outputLodFile = fileDir + "/Data.osgb"; osgDB::writeNodeFile(*group, outputLodFile); } int main(int argc, char *argv[]) { string fileDir = "D:/Data/scene/city"; std::string outputLodFile = fileDir + "/Data.osgb"; createObliqueIndexes(fileDir); osgViewer::Viewer viewer; osg::Node * node = new osg::Node; node = osgDB::readNodeFile(outputLodFile); viewer.setSceneData(node); return viewer.run(); }
若是直接讀取每一塊的LOD而後經過osgDB::writeNodeFile寫入到一個osgb文件,這個文件就會保存全部塊的LOD第一層信息。這樣在第二冊加載的時候仍是會比較慢,因此這裏就建立了一個空的節點,造成了索引全部LOD塊的數據結構。對於每一塊數據,新建兩層LOD,第一層爲自身的空白節點,第二層爲分塊LOD的第一層數據:code
osg::ref_ptr<osg::Node> node = osgDB::readNodeFile(path); osg::ref_ptr<osg::PagedLOD> lod = new osg::PagedLOD(); auto bs = node->getBound(); auto c = bs.center(); auto r = bs.radius(); lod->setCenter(c); lod->setRadius(r); lod->setRangeMode(osg::LOD::RangeMode::PIXEL_SIZE_ON_SCREEN); osg::ref_ptr<osg::Geode> geode = new osg::Geode; geode->getOrCreateStateSet(); lod->addChild(geode.get()); std::string relativeFilePath = "./Data/" + name + "/" + name + ".osgb"; //相對路徑 lod->setFileName(0, ""); lod->setFileName(1, relativeFilePath); lod->setRange(0, 0, 1.0); //第一層不可見 lod->setRange(1, 1.0, FLT_MAX); lod->setDatabasePath(""); group->addChild(lod);
LOD的Center和Radius都很是重要,須要預先設置好;setRangeMode設置了細節層級調度的模式,通常都爲PIXEL_SIZE_ON_SCREEN;setFileName設置了每一層的數據路徑,setRange肯定了當前層級的範圍。因爲這個LOD只是個索引文件,因此會設置第二層爲極大的可見範圍值。blog
能夠像加載普通OSGB文件同樣加載這個索引文件,經過osgviewer加載的效果以下:
索引