基于OSG讲解一下LOD

LOD也称为层次细节模型,是一种实时三维计算机图形技术,最先由Clark于1976年提出,其工作原理是:
视点离物体近时,能观察到的模型细节丰富;视点远离模型时,观察到的细节逐渐模糊。系统绘图程序根据一定的判断条件,选择相应的细节进行显示,从而避免了因绘制那些意义相对不大的细节而造成的时间浪费,同时有效地协调了画面连续性与模型分辨率的关系。

地形里面的LOD算法可以分为:非连续LOD模型、连续LOD模型以及节点LOD模型。
非连续LOD模型:它实质上保存了原始模型的多个副本,每个副本对应某一特定的分辨率,所有副本构成一个金字塔模型。该模型的优点是不必在线生成模型,可视速度快;缺点是数据冗余大,容易引起几何数据的不一致性,而且由于不同分辨率之间没有任何关联,不同分辨率间的转换易引起视觉上的间跳现象。
连续LOD模型:它是在某一时间只保留某一分辨率的模型,在实际应用中根据需要,采用一定的算法实时生成另一分辨率的模型。该模型优缺点正好与不连续LOD模型相反,即优点是没有数据冗余,能够保证几何数据的一致性和视觉连续性;缺点是需要在线生成不同分辨率的模型,算法设计复杂,可视速度慢。
节点LOD模型:本身是一个分辨率结构。不同分辨率模型之间用节点相连,通过对节点的激活来操作相应的部件。所有节点均被激活时,实质就是一个全分辨率结构,优点是结构简单、操作方便,适合表达复杂的不连续的体模型对象。
先弄一个osg出来最简单的:

void LOD() {
       osg::ref_ptr<osg::LOD> lod = new osg::LOD();
       lod->addChild(osgDB::readNodeFile("cow.osg"), 0.0f, 20);
       //lod->addChild(osgDB::readNodeFile("cessna.osg"), 20, 100);
       //lod->addChild(osgDB::readNodeFile("clock.osgt"), 100, FLT_MAX);
       osg::ref_ptr<osgViewer::Viewer> viewer = new osgViewer::Viewer;
       osg::ref_ptr<osg::Group> sceneRoot = new osg::Group;
       sceneRoot->addChild(lod.get());
       viewer->setSceneData(sceneRoot);    
       viewer->setUpViewInWindow(POSX, POSY, WIDTH, HEIGHT);
       viewer->run();
       return;
              
}

osg实现lod:

osg::ref_ptr<osg::Node> CreateNode()
{
       osg::ref_ptr<osg::Group> _root = new osg::Group;
       //好吧,我们继续拿牛来做实验
       osg::ref_ptr<osg::Node> node1 = osgDB::readNodeFile("cow.osg");
       //然后再弄个滑翔机的模型出来
       osg::ref_ptr<osg::Node> node2 = osgDB::readNodeFile("glider.osg");
       //创建一个细节层次节点LOD
       osg::ref_ptr<osg::LOD> lode = new osg::LOD;
       //添加子节点,在0到30的范围内显示牛
       lode->addChild(node1.get(), 0.0f, 30.0f);
       //添加子节点,在30到100的时候显示滑翔机
       lode->addChild(node2.get(), 30.0f, 100.0f);
       //创建一个细节层次节点LOD
       osg::ref_ptr<osg::LOD> lode1 = new osg::LOD;
       //设置按照像素大小来判断
       lode1->setRangeMode(osg::LOD::PIXEL_SIZE_ON_SCREEN);
       //添加子节点,在0到30的范围内显示牛
       lode1->addChild(node1.get(), 0.0f, 1000.0f);
       //添加子节点,在30到100的时候显示滑翔机
       lode1->addChild(node2.get(), 1000.0f, 2000.0f);
       //创建一个位置变换节点
       osg::ref_ptr<osg::PositionAttitudeTransform> pat1 = new  osg::PositionAttitudeTransform();
       pat1->setPosition(osg::Vec3(-20.0f, 0.0f, 0.0f));
       pat1->addChild(lode1.get());
       _root->addChild(lode.get());
       _root->addChild(pat1.get());
       return _root.get();
}

osg::LOD会一次性载入所有模型进入内存,只是进行有选择的绘制而已。为了避免这种一次性加入内存的浪费行为,OpenSceneGraph提供了另外一种细节层次节点:分页细节层次节点osg::PagedLOD,PagedLOD继承自osg::LOD,可实现动态分页加载,可根据需要来加载模型文件,加载过程中有单独的线程负责实时调度和加载。

osg::ref_ptr<osg::Node> CreateNode()
{
       osg::ref_ptr<osg::Group> _root = new osg::Group;
       //好吧,我们继续拿牛来做实验
       osg::ref_ptr<osg::Node> node1 = osgDB::readNodeFile("cow.osg");
       //然后再弄个滑翔机的模型出来
       osg::ref_ptr<osg::Node> node2 = osgDB::readNodeFile("glider.osg");
       //创建一个细节层次节点LOD
       osg::ref_ptr<osg::LOD> lode = new osg::LOD;
       //添加子节点,在0到30的范围内显示牛
       lode->addChild(node1.get(), 0.0f, 30.0f);
       //添加子节点,在30到100的时候显示滑翔机
       lode->addChild(node2.get(), 30.0f, 100.0f);
       //创建一个细节层次节点LOD
       osg::ref_ptr<osg::LOD> lode1 = new osg::LOD;
       //设置按照像素大小来判断
       lode1->setRangeMode(osg::LOD::PIXEL_SIZE_ON_SCREEN);
       //添加子节点,在0到30的范围内显示牛
       lode1->addChild(node1.get(), 0.0f, 1000.0f);
       //添加子节点,在30到100的时候显示滑翔机
       lode1->addChild(node2.get(), 1000.0f, 2000.0f);
       //创建一个位置变换节点
       osg::ref_ptr<osg::PositionAttitudeTransform> pat1 = new  osg::PositionAttitudeTransform();
       pat1->setPosition(osg::Vec3(-20.0f, 0.0f, 0.0f));
       pat1->addChild(lode1.get());
       _root->addChild(lode.get());
       _root->addChild(pat1.get());
       return _root.get();
}

参考资料:
LOD详解

你可能感兴趣的:(cg&图形学)