在OSG中,利用osgUtil::Simplifier进行OBJ/OSGB文件简化压缩代码
对于倾斜摄影模型(OBJ/OSGB)来说,存在节点多、数据量大、渲染处理速度慢等问题,因此对其进行简化压缩是一个不可为避免的问题。本文以OBJ数据为例,在C++中配置好OSG引擎的前提下,利用osgUtil::Simplifier类对单一OBJ文件进行压缩,并输出压缩后的OBJ文件。
osgUtil::Simplifier simplifier(sampleRatio, maxError);
osgUtil::Simplifier 类继承自osg::NodeVisitor类,以访问器的方式遍历几何体并对其进行简化处理。osgUtil::Simplifier类采用QEM(Quadric Error Metrics),即基于二次误差度量的边塌陷算法(参考文献可私我要),通过合并顶点的方式进行三角面片的简化,实现原始OBJ文件大小的压缩,同时保持每个顶点伴随的纹理属性不变。
具体代码如下:
//#include "stdafx.h"
#include <string>
#include <iostream>
#include <osgViewer/Viewer>
#include <osgDB/ReadFile>
#include <osgDB/WriteFile>
#include <osg/Node> //节点类
#include <osg/Geode> //是个几何节点,可以说是一个几何Group节点,一般的可绘制几何体都是通过它来传向root进行渲染,是OSG几何绘制的最高管理节点
#include <osg/Group> //对节点起到组织作用,一般作为父节点或者根节点出现
#include <osg/PositionAttitudeTransform> //位置变换节点类,提供模型的位置变换、大小缩放、原点位置的设置、坐标系的变换
#include <osg/Material>
#include <osgViewer/ViewerEventHandlers> //事件监听
#include <osgGA/StateSetManipulator> //事件响应类,对渲染状态进行控制
#include <osgUtil/Optimizer> //优化器
#include <osgUtil/Simplifier> //简化几何体
#include <osgDB/ReaderWriter>
using namespace std;
//读取模型
osg::Node* readModel()
{
string rpath = "D:/测区OBJ/Tile_+651_+443/Tile_+651_+443.obj"; //输入OBJ文件
//设置文件读取不旋转
osg::ref_ptr<osgDB::Options> options = new osgDB::Options("noRotation");
osg::ref_ptr<osg::Node> node = osgDB::readNodeFile(rpath, options);
cout << "reading done!" << endl;
return node.release();
}
//深拷贝并简化新模型
osg::Node* deepCopy(osg::Node* node)
{
/*
创建简化对象
simplifier(sampleRatio, maxError)
参数:样本比率、点的误差或边的长度 样本简化比率
样本比率<1 设置点的误差
样本比率>1 设置边的长度限制
比率越大,简化越少
使用的是边塌陷算法
*/
float sampleRatio = 0.1f;//0.3f
float maxError = 4.0f;
osgUtil::Simplifier simplifier(sampleRatio, maxError);
//深拷贝
osg::ref_ptr<osg::Node> deepnode = (osg::Node*)(node->clone(osg::CopyOp::DEEP_COPY_ALL));
//创建一个位置变换节点,将之设置为新位置,将深拷贝的模型移到新位置
osg::ref_ptr<osg::PositionAttitudeTransform> pat = new osg::PositionAttitudeTransform();
pat->setPosition(osg::Vec3(120.0f, 0.0f, 0.0f)); //(10.0f, 0.0f, 0.0f)) (右方,后方,上方) 视点沿Y轴向后 对比简化前后效果
pat->addChild(deepnode);
pat->accept(simplifier);
return pat.release();
}
int main()
{
//创建一个叶节点对象并添加节点
osg::ref_ptr<osg::Group> root = new osg::Group();
osg::ref_ptr<osg::Node> node1 = readModel();
osg::ref_ptr<osg::Node> node2 = deepCopy(node1);
root->addChild(node1);
root->addChild(node2);
//优化场景数据
osgUtil::Optimizer optimizer;
optimizer.optimize(root.get());
//显示模型
osg::ref_ptr<osgViewer::Viewer> viewer = new osgViewer::Viewer();
//切换网格模式,方便比较
viewer->addEventHandler(new osgGA::StateSetManipulator(viewer->getCamera()->getOrCreateStateSet()));
viewer->setSceneData(root.get());
viewer->realize();
osg::ref_ptr<osgDB::ReaderWriter::Options> options = new osgDB::ReaderWriter::Options;
//options->setOptionString("Compressor=zlib"); //设置压缩格式为zlib WriteImageHint = IncludeFile
string wpath = "D:/测区OBJ/Tile_+651_+443/Tile_+651_+443_01f.obj"; //输出OBJ文件位置
osgDB::writeNodeFile(*(node2.get()), wpath); //使用zlib压缩写入新osgb文件
cout << "done" << endl;
return viewer->run(); //return代表程序结束,后面的语句不执行了
}
上述代码亲测可用,数据处理前后对比结果展示如下:
实验结果可以看出,能够在不影响三维场景显示效果的前提下,减少模型和三角面片的数量,从而实现OBJ文件的压缩,同时纹理得以完好保存;
此外,设置三角面简化比例在R=0.1条件下,大概可达到41%左右的简化率,文件所占内存得以大大减小。因此,可以认为,本方法具有不错的效果。如果有用的话,帮忙点个赞吧,非常感谢哈哈!