【OSG : 原理】osg读取文件的原理(插件工作机制)

5 篇文章 0 订阅

一、osg读取文件的原理(插件工作机制)【重要】

二、osg的readnodefile一直返回空指针

三、osgPlugins相关 【重要】

 

四、附件:

我们可以直接使用osgDB::readNodeFile("cow.osg")来读取不同格式的模型,osgDB库允许用户程序加载、使用和写入3D数据库,它采用插件管理的架构,可以支持大量常见的2D图形和3D图形文件格式。osgDB负责维护插件的信息注册表,并负责检查将要被载入的OSG插件接口的合法性。由于大型3D地形数据通常是多段数据块的组合体。因此,应用程序从文件中读取各部分数据库信息时,需要在不干扰当前渲染的前提下以后台线程的方式进行,osgDB::DatabaseParger提供了这样的功能。

插件的不足之处在于,其设计过程中只能遵循固定的格式和工作模式进行编程,它的一切行为都无法超出主系统所提供的公共接口规范。

1、自定义文件插件:

自定义文件插件主要是自定义一个插件读写类,继承osgDB::ReaderWriter类,然后根据需求重写如readNode等函数方法即可,如下,这些函数的返回值均为枚举变量。
 virtual ReadResult readNode(std::istream& /*fin*/,const Options* =NULL) const { return ReadResult(ReadResult::NOT_IMPLEMENTED); }
在建立插件读写类时需要注意:

需要建立一个dll项目工程,输出的dll必须为osgdb_扩展名.dll或osgdb_扩展名d.dll的形式
为了实现插件注册,需要定义全局变量,方法如下REGISTER_OSGPLUGIN(VR, ReaderWriterVR),在该全局变量的初始化过程中,会使用Registery::addReaderWriter函数自动注册插件所对应的扩展名。
    REGISTER_OSGPLUGIN是一个宏,在Registry.h中如下定义
    #define REGISTER_OSGPLUGIN(ext, classname) \
    extern "C" void osgdb_##ext(void) {} \
    static osgDB::RegisterReaderWriterProxy<classname> g_proxy_##classname;
这里说一下"#" "##"的含义:"#"将后面跟的变量由引号包含,如#value会解析成"value"。 "##"将前后两个值连接,去掉空格,如A##B会解析成AB。
在应用程序使用中,需要注册插件,方法如下 osgDB::Registry::instance->addFileExtensionAlias("VR", "VR")
void Registry::addFileExtensionAlias(const std::string mapExt, const std::string toExt)
{
    _extAliasMap[mapExt] = toExt;
}
2、插件的工作机制
osg插件是一组动态链接库,其中实现了osgDB头文件ReaderWriter定义的接口。OSG不可能查找并加载所有的插件以获取它们支持的文件格式,这样,在程序启动时将会是一个很大的开销。因此,OSG使用职责链(Chain of Responsibility)的设计模式,以加载尽量少的插件。当用户程序尝试使用osgDB读取或写入文件时,OSG将按照如下步骤来查找合适的插件。
OSG搜索已注册的插件列表,查找支持文件格式的插件。开始时已注册插件列表仅包含了Registry类构造函数中注册的插件。如果OSG找到了可以支持此文件格式的插件,并成功执行了I/O操作,那么它将返回相应的数据。
如果没有发现可以支持此格式的已注册插件,或者I/0操作失败,那么OSG将根据前面所述的文件命名规则创建插件文件的名称,并尝试读取相应的插件库。如果读取成功,OSG将添加此插件到已注册插件列表中。
OSG将重复步骤(1),如果文件I/O的操作再次失败,OSG将返回失败信息。
总的来说,用户不必了解OSG内部如何实现文件I/O操作,就可以使用插件顺利工作。反之,如果文件I/O操作失败,用户也可以根据给出的错误信息跟踪插件源代码中的相关内容。其在程序中代码的实现顺序如下图所示:


主要的实现的代码是在ReaderWriter::ReadResult Registry::read(const ReadFunctor& readFunctor)函数中

ReaderWriter::ReadResult Registry::read(const ReadFunctor& readFunctor)
{
    // first attempt to load the file from existing ReaderWriter's
    //看是否有可用的ReaderWriter,对当前的数据进行解析,如果解析成功,就返回结果
    AvailableReaderWriterIterator itr(_rwList, _pluginMutex);
    for(;itr.valid();++itr)
    {
        ReaderWriter::ReadResult rr = readFunctor.doRead(*itr);
        if (readFunctor.isValid(rr)) return rr;
        else results.push_back(rr);
    }
 
 
    // now look for a plug-in to load the file.
    //根据文件名称创建新的动态库名称,然后加载动态库,增加_rwList对象个数
    std::string libraryName = createLibraryNameForFile(readFunctor._filename);
    if (loadLibrary(libraryName)!=NOT_LOADED)
    {
        //重新遍历一下,使用新的ReaderWriter进行数据的解析
        for(;itr.valid();++itr)
        {
            ReaderWriter::ReadResult rr = readFunctor.doRead(*itr);
            if (readFunctor.isValid(rr)) return rr;
            else results.push_back(rr);
        }
    }
}
接下去需要研究createLibraryNameForFile()。
===========================================================================================

从官网下载好的osg进行编译完成。写了一个测试的demo。

具体代码如下

int main(int argc, char *argv[])
{
    std::string osgstr = "E:\\cow.osg";
    osgDB::Options  *option = new osgDB::Options(std::string("noTriStripPolygons"));
    osgViewer::Viewer viewer;
    osg::ref_ptr<osg::Node> loadedModel = osgDB::readNodeFile(osgstr);
    
    osgUtil::Optimizer optimizer;
    optimizer.optimize(loadedModel);

    viewer.setUpViewInWindow(100,100,2000,600);
    viewer.setSceneData(loadedModel);
    viewer.realize();
    return viewer.run();
}
调试的时候  osgDB::readNodeFile的返回值loadedModel一直是防会空NULL。

解决办法:将osg编译目录的bin添加到环境变量中。我的测试安装路径

C:\OpenSceneGraph-OpenSceneGraph-3.6.3\OpenSceneGraph-OpenSceneGraph-3.6.3\bin

添加到path到环境变量中即可。
 

 

 

 

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值