osg LOD节点动态调度

1、LOD节点

LOD(level of detail):是指根据物体模型的结点在显示环境中所处的位置和重要度,决定物体渲染的资源分配,降低非重要物体的面数和细节度,从而获得高效率的渲染运算。在OSG的场景结点组织结构中,专门提供了场景结点osg::LOD来表达不同的细节层次模型。其中,osg::LOD结点作为父节点,每个子节点作为一个细节层次,设置不同的视域,在不同的视域下显示相应的子节点。

2、数据分页


数据分页:也即osg的DatabasePager类。在城市三维场景中可以采用数据分页的方式进行动态调度。这里“分页”的意思是随着视口范围的变化,场景只加载和渲染当前视口范围内数据,并将离开视口范围内的数据清除内存(可以设定不同的数据卸载策略),不再渲染。保证内存中只有有限的数据量,场景的每一帧也只有有限的数据被送到图形渲染管道,从而提高渲染性能。也就是常说的数据库分页技术,简单来说,就是在进行数据库查找时,有可能满足条件的数据很多,为了提高相应速度我们进行数据查找时进行分页查找与显示,当点击下一页时才会进行下一次的查找动作。Osg就是把这个原理应用在了三维大场景中,当我们需要加载一个城市级数据时,因为数据量非常大,而我们感兴趣的范围在某一时刻一般都是很小的一部分,所以我们也可以应用数据分页的技术,对大数据进行”分页”查找并显示。

在osg中DatabasePager执行的动作只有一步,就是在每一帧的更新循环中使用updateSceneGraph函数,把过期的数据卸载掉。并将新加入的数据载入到当前scene中。这些数据都是在用户视野中显示的。所以我们就把用户的视野比作”页面”。我们都知道数据的加载都是非常耗时的操作,更何况是三维模型这种大体量的数据,所以osg把DatabasePager的操作放到了另一个独立于渲染线程之外的线程上进行。

3、动态调度

动态调度:OSG源代码中提供PagedLOD来进行模型的动态调度。在不同的视域下,PagedLOD动态读取不同细节层次的结点模型,实现了分页LOD显示。OSG内部采用osgDB::DatabasePager类来管理场景结点的动态调度,场景循环每一帧的时候,会将一段时间内不在当前视图范围内的场景子树卸载掉,并加载新进入到当前视图范围的新场景子树。OSG采用了多线程的方式来完成上述工作。

4、示例

#include "stdafx.h"
#include 
#include 
#include 
#include 

osg::Geode* createBox(const osg::Vec3& center, float width)
{
	osg::ref_ptr geode = new osg::Geode;
	geode->addDrawable(
		new osg::ShapeDrawable(new osg::Box(center, width)));
	return geode.release();
}

osg::Group* createPagedLOD(int row, int col)
{
	osg::ref_ptr root = new osg::Group;
	char buffer[5] = "";
	for (int i = 0; i < row; i++)
	{
		for (int j = 0; j < col; j++)
		{
			std::string filename = "cow.osg.";
#ifdef _WIN32
			_itoa_s(i * 10, buffer, 5, 10);
			filename += buffer; filename += ",";
			_itoa_s(j * 10, buffer, 5, 10);
			filename += buffer; filename += ",0.trans";
#else
			gcvt(i * 10, 5, buffer);
			filename += buffer; filename += ",";
			gcvt(j * 10, 5, buffer);
			filename += buffer; filename += ",0.trans";
#endif
			osg::ref_ptr lod = new osg::PagedLOD;
			lod->setCenter(osg::Vec3(i * 10, j * 10, 0.0));
			lod->addChild(createBox(osg::Vec3(i * 10, j * 10, 0.0), 1), 200.0, FLT_MAX);
			lod->setFileName(1, filename);
			lod->setRange(1, 0.0, 200.0);
			root->addChild(lod.get());
		}
	}
	return root.release();
}

int main(int argc, char** argv)
{
	osgViewer::Viewer viewer;
	viewer.setSceneData(createPagedLOD(30, 30));
	return viewer.run();
}

截图

osg LOD节点动态调度_第1张图片

你可能感兴趣的:(osg学习记录,c++)