2018-09-13
我们经常需要在渲染程序中继承各种格式的文件导入功能,虽然我们可以自行编译各种文件类型处理的lib,但是,如果渲染引擎能够有一个模块来处理这样的工作是最好的了。OSG插件机制真的是利器。这里主要讲讲用OSG插件进行资源导入。
OSG支持多种3D格式,链接[1]表明,基本囊括了我们能接触到的数据交换格式。对于每一种格式,OSG都有插件来处理。插件用dll来实现,根据文件后缀名来决定插件的名字,动态加载dll并调用统一的接口来加载文件。这里要说明下OSG插件机制也有一些不足之处:它使用了singleton模式,不支持多线程导入多个文件,而且,读取单个文件也是不支持多线程的。
osgDB::readNodeFile(file); ReaderWriter::ReadResult rr = Registry::instance()->readNode(filename,options); readNodeImplementation(fileName,options); ReaderWriter::ReadResult rr = read(readFunctor); std::string libraryName = createLibraryNameForFile(readFunctor._filename); loadLibrary(libraryName)!=NOT_LOADED ReaderWriterOBJ::readNode(_filename, _options) obj::Model model; osg::Node* node = convertModelToSceneGraph(model, localOptions, local_opt.get());
读取形成的OSG对象,保存在ReadResult 类型的对象中。需要使用 rr.takeNode(); 获取。如上面的例子,核心就是ReaderWriterOBJ,类似的还有ReaderWriterGTA、ReaderWriterJPEG、ReaderWriterPNG、ReaderWriterSTL等,都继承于 osgDB::ReaderWriter。基类有readNode(const std::string& file, const osgDB::ReaderWriter::Options* options)接口,子类都需要override该method。ReaderWriterOBJ在构造时会指明本插件支持的文件格式:supportsExtension("obj","Alias Wavefront OBJ format");,还会指明参数:supportsOption("DIFFUSE=<unit>", "Set texture unit for diffuse texture");。在ReaderWriterOBJ::readNode()中实现真正的文件读写与解析。
因为一种格式可能被多个插件所支持,所以,OSG假定,只要找到第一个支持该格式的插件就直接使用它。所以,需要遍历所有支持该格式 的插件列表。
ReadNodeFunctor这个类型看似无用,OSG用这个functor 保存filename和option,用它来翻转依赖关系。如果单纯只有这个功能,那就没有必要了。它还有一个很重要的功能:缓存已经加载的文件。这样的话就不用再次解析文件了(如果该osg::Object对象没有被析构的话)。缓存对象的功能重点依赖于osg的智能指针功能。要是没有智能指针,还真是很难实现。所以,这里并不会有内存浪费的问题。
因为前面提到的不能支持多线程的问题,如果程序有这个方面的需求,就只能采用第三方的lib,把lib的数据结构转化为osg::Node。
OSG似乎把 obj的 y,z 值调换了,不是什么大问题。
如果有任何意见,欢迎留言讨论。
[ 主页 ]