十三、OSG学习笔记-osgDB文件读写

发布于:2025-03-12 ⋅ 阅读:(12) ⋅ 点赞:(0)

上一章节:

十二、OSG学习笔记-Control-CSDN博客https://blog.csdn.net/weixin_36323170/article/details/146082287?spm=1001.2014.3001.5501

一、文件读取原理

ReadNodeFile,读取流程:

二、实现一个简单的读取器

仿造ReaderWriterOSG.CPP原码,自己实现一个文件读写器的dll, 该dll名为osgdb_fs.dll,并用这个文件读写器,读取后缀为.fs自定义模型文件

项目输出为类型设置为dll:

输出路径改为:

编译生成路径如下:

再将你编译好的这个库放到osg的bin目录下,就可以通过osgviewer 查看之前定义的sphere.fs文件。

代码仓库:OsgStudy/ReadFs · CuiQingCheng/OsgStudy - 码云 - 开源中国https://gitee.com/cuiqingcheng/osg-study/tree/master/OsgStudy/ReadFs

读取器ReadFs.cpp代码如下:

/**
	自定义OSG 文件读写器
**/

#include <windows.h>
#include <iostream>
#include <sstream>

#include <osg/Image>
#include <osg/Group>
#include <osg/Notify>
#include <osg/Version>
#include <osg/Geode>
#include <osg/Shape>
#include <osg/ShapeDrawable>

#include <osgDB/FileNameUtils>
#include <osgDB/FileUtils>
#include <osgDB/fstream>
#include <osgDB/Registry>
#include <osgDB/Input>
#include <osgDB/Output>

using namespace osg;
using namespace osgDB;

class FSReaderWriter : public ReaderWriter
{
public:

	mutable OpenThreads::Mutex _mutex;
	mutable bool _wrappersLoaded;

	FSReaderWriter()
	{
		supportsExtension("fs", "FreeSouth 's format");
	}

	virtual const char* className() const { return "FSReaderWriter"; }

	bool loadWrappers() const
	{
#ifndef OSG_LIBRARY_STATIC
		if (_wrappersLoaded) return true;

		OpenThreads::ScopedLock<OpenThreads::Mutex> lock(_mutex);
		if (_wrappersLoaded) return true;

		std::string filename = osgDB::Registry::instance()->createLibraryNameForExtension("fsreadwrite_osg");
		if (osgDB::Registry::instance()->loadLibrary(filename) == osgDB::Registry::LOADED)
		{
			OSG_INFO << "FSReaderWriter wrappers loaded OK" << std::endl;
			_wrappersLoaded = true;
			return true;
		}
		else
		{
			OSG_NOTICE << "FSReaderWriter wrappers failed to load" << std::endl;
			_wrappersLoaded = true;
			return false;
		}
#else
		return true;
#endif
	}

	virtual ReadResult readNode(const std::string& file, const Options* opt) const
	{
		std::string ext = osgDB::getLowerCaseFileExtension(file);

		if (!acceptsExtension(ext)) return ReadResult::FILE_NOT_HANDLED;

		std::string fileName = osgDB::findDataFile(file, opt);
		if (fileName.empty()) return ReadResult::FILE_NOT_FOUND;

		osgDB::ifstream fin(fileName.c_str());
		if (!fin)
		{
			std::cerr << "Failed to open file: " << fileName << std::endl;
			return ReadResult::FILE_NOT_FOUND;
		}
		return readNode(fin, opt);

	}

	virtual ReadResult readNode(std::istream& fin, const Options* options) const
	{
		Input fr;
		fr.attach(&fin);

		osg::ref_ptr<osg::Geode> gnode = new osg::Geode;

		osg::Vec3 center;
		float radius;

		// load all nodes in file, placing them in a group.
		while (!fr.eof())
		{
			// 匹配文件中中心点,跟半径
			if (fr.matchSequence("%f%f%f%f"))
			{
				fr.readSequence(center);
				fr.readSequence(radius);
				std::cout << "Center is:" << center.x() << " " << center.y() <<" "<< center.z() << std::endl;
				std::cout << "Radius:" << radius << std::endl;
				gnode->addDrawable(new osg::ShapeDrawable(new osg::Sphere(center, radius)));
			}
			else {
				std::cout << "fr is NULL" << std::endl;
				++fr;
			}
		}
		return gnode;
	}

};

// now register with Registry to instantiate the above
// reader/writer.
REGISTER_OSGPLUGIN(fs, FSReaderWriter)

再切换到编写一个exe,程序加载使用这个读写器,读取文件,main.cpp 如下:

#include <windows.h>
#include <osgViewer/Viewer>
#include <osgDB/ReadFile>

int main()
{
	osgDB::Registry::instance()->addFileExtensionAlias("fs", "fs");//将文件扩展名与dll名关联起来

	osg::ref_ptr<osg::Group> group = new osg::Group;
	group->addChild(osgDB::readNodeFile("sphere.fs")); // 自定义的fs文件

	osg::ref_ptr<osgViewer::Viewer> viewer = new osgViewer::Viewer;
	viewer->setUpViewInWindow(100, 100, 1500, 1000);
	viewer->setSceneData(group.get());
	viewer->run();
	return 0;
}

运行结果如下图:

三、实现获取读取OSG文件进度功能

文件读取流程如下:

通过从写文件读取流的方式进行:

代码仓库:

OsgStudy/ReadProcess · CuiQingCheng/OsgStudy - 码云 - 开源中国https://gitee.com/cuiqingcheng/osg-study/tree/master/OsgStudy/ReadProcess

代码如下:

/**
	自定义文件读取,并实时获得读取进度
**/
#include <windows.h>
#include <iostream>
#include <fstream>
#include <streambuf>

#include <osgViewer/Viewer>
#include <osgDB/ReaderWriter>
#include <osgDB/ReadFile>
#include <osgDB/FileUtils>
#include <osgDB/FileNameUtils>
#include <osgDB/Registry>

template<class _Elem, class _Traits = std::char_traits<_Elem>>
class ReadStream :public std::basic_filebuf<_Elem, _Traits>
{
public:
	using int_type = typename _Traits::int_type;
	ReadStream(const std::string& fileName):_itotalSize(0)
	{
		if (this->open(fileName.c_str(), std::ios_base::in | std::ios_base::binary))
		{
			//std::cout << "Read Success" << std::endl;
			// 打开文件时,会获得文件指针,将文件指针移动到文件末尾;从而获取文件大小
			_itotalSize = this->pubseekoff(0, std::ios_base::end, std::ios_base::in);
			std::cout << "file size:" <<_itotalSize << std::endl; // 获取文件大小字节数
			// 再回置指针到文件开头
			this->pubseekoff(0, std::ios_base::beg, std::ios_base::in);
		}
	}

protected:
	int_type  uflow() override // 读取文件时,会不断的执行这个文件
	{
		int_type value =  std::basic_filebuf<_Elem, _Traits>::uflow();
		_iCurSize += (this->egptr() - this->gptr());	// 用结尾指针减去当前读取的指针, 获取当前读取到的字符数;
		std::cout << 100 * ((float)_iCurSize/_itotalSize)<<"%" << std::endl;
		return value;
	}
	int _iCurSize{ 0 };
	int _itotalSize{0};
};

class ReadFileCB :public osgDB::Registry::ReadFileCallback
{
public:
	typedef ReadStream<char> ReadStreamString;
	virtual osgDB::ReaderWriter::ReadResult readNode(const std::string& file, const osgDB::ReaderWriter::Options* opt) override {
		std::cout << "Use our function" << std::endl;

		// 第一步:获取OSG、IVE ReaderWriter
		std::string ext = osgDB::getLowerCaseFileExtension(file);

		// 用扩展名获取 ReaderWriter
		osgDB::ReaderWriter* rw = osgDB::Registry::instance()->getReaderWriterForExtension(ext);
		if (!rw)
		{
			return osgDB::ReaderWriter::ReadResult::FILE_NOT_HANDLED;
		}

		std::string fileName = osgDB::findDataFile(file, opt);
		if (fileName.empty())
		{
			return osgDB::ReaderWriter::ReadResult::FILE_NOT_FOUND;
		}

		//osgDB::ifstream fin(fileName.c_str());
		ReadStreamString *fin = new ReadStreamString(fileName);
		if (fin->is_open())
		{
			std::cout << "Using default format readerwriter" << std::endl;
			//rw->readNode(fin);
			std::istream stream(fin);
			// 调用接受 std::istream 的 readNode 重载版本
			osgDB::ReaderWriter::ReadResult result = rw->readNode(stream, opt);
			if (result.success()) {
				return result;
			}
		}
		else
		{
			return osgDB::ReaderWriter::ReadResult::ERROR_IN_READING_FILE;
		}
		return osgDB::Registry::instance()->readNodeImplementation(file, opt);
	}
};

int main()
{
	osg::ref_ptr<osgViewer::Viewer> viewer = new osgViewer::Viewer;
	viewer->setUpViewInWindow(100, 100, 1500, 1000);
	osgDB::Registry::instance()->setReadFileCallback(new ReadFileCB);
	viewer->setSceneData(osgDB::readNodeFile("glider.osg"));
	viewer->run();
	return 0;
}

四、osgDB写文件

核心函数接口,osgDB::Registry::RwriteNode();

代码仓库:

OsgStudy/outputNode · CuiQingCheng/OsgStudy - 码云 - 开源中国https://gitee.com/cuiqingcheng/osg-study/tree/master/OsgStudy/outputNode

实例代码:

/**
	osg 写文件
**/
#include <windows.h>
#include <iostream>

#include <osgViewer/Viewer>
#include <osgDB/ReaderWriter>
#include <osgDB/ReadFile>
#include <osgDB/Registry>


int main()
{
	osgDB::Registry::instance()->addFileExtensionAlias("fs", "fs");//将文件扩展名与dll名关联起来
	osg::ref_ptr<osgViewer::Viewer> viewer = new osgViewer::Viewer;
	viewer->setUpViewInWindow(100, 100, 1500, 1000);
	osg::ref_ptr<osg::Node> node = osgDB::readNodeFile("sphere.fs"); // 读取自定义文件
	viewer->setSceneData(osgDB::readNodeFile("sphere.fs"));
	osg::Node& writeNode = (*(node)); // 将读到的文件节点,写道指定目录下的文件里
	osgDB::Registry::instance()->writeNode(writeNode, "D:/test.osg", osgDB::Registry::instance()->getOptions());
	return viewer->run();

}

源代码:

/**
	osg 写文件
**/
#include <windows.h>
#include <iostream>

#include <osgViewer/Viewer>
#include <osgDB/ReaderWriter>
#include <osgDB/ReadFile>
#include <osgDB/Registry>
#include <osg/Matrixd>
#include <osg/MatrixTransform>


int main()
{
	osgDB::Registry::instance()->addFileExtensionAlias("fs", "fs");//将文件扩展名与dll名关联起来
	osg::ref_ptr<osgViewer::Viewer> viewer = new osgViewer::Viewer;
	viewer->setUpViewInWindow(100, 100, 1500, 1000);
	osg::ref_ptr<osg::Node> node = osgDB::readNodeFile("sphere.fs"); // 读取自定义文件
	viewer->setSceneData(osgDB::readNodeFile("sphere.fs"));
	osg::Node& writeNode = (*(node)); // 将读到的文件节点,写道指定目录下的文件里
	osgDB::Registry::instance()->writeNode(writeNode, "D:/test.fs", osgDB::Registry::instance()->getOptions());
	
	osg::ref_ptr<osg::Group> gp = new osg::Group;
	osg::ref_ptr<osg::Node> node1 = new osg::Node;
	osg::ref_ptr<osg::MatrixTransform> mx = new osg::MatrixTransform;
	
	node1 = osgDB::readNodeFile("glider.osg");
	mx->addChild(node1.get());
	mx->setMatrix(osg::Matrix::translate(1.0, 0.0, 0.0));

	gp->addChild(mx);
	gp->addChild(node1);
	viewer->setSceneData(gp);
	osg::Node& writeNode1 = (*(gp)); // 将读到的文件节点,写道指定目录下的文件里
	osgDB::Registry::instance()->writeNode(writeNode1, "D:/tt.osg", osgDB::Registry::instance()->getOptions());
	return viewer->run();
}

osgArchive:将很多osg,文件压缩到一个包文件内。

例如:

# 将两个模型文件压缩到一个ive 文件中
osgconv cow.osg glider.osg d:\\g.ive


网站公告

今日签到

点亮在社区的每一天
去签到