OSG加载倾斜摄影数据

目录

1. 概述

ContextCapture(Smart3D)天生的倾斜摄影模子数据一样平常都形如如下组织结构:
OSG加载倾斜摄影数据

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

动画图解Git下令

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

2. 实例

2.1. 代码

详细的实现代码如下:

#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();
}

2.2. 剖析

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

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只是个索引文件,以是会设置第二层为极大的可见局限值。

3. 效果

可以像加载通俗OSGB文件一样加载这个索引文件,通过osgviewer加载的效果如下:
OSG加载倾斜摄影数据

原创文章,作者:28x29新闻网,如若转载,请注明出处:https://www.28x29.com/archives/6914.html