OSG编程指南<十八>:OSG读写保存文件及对中文字符的支持

  基本几何体的绘制只适用于简单的编程,当场景中需要加载一个很复杂的模型时,还是需要从外部导入。osgDB 库
提供了读取二维图像和三维模型的接口,同时,也管理着第三方插件系统,以实现对不同格式文件的读取。

1、OSG 支持的文件格式

  由于 OSG 包含庞大的第三方插件库,所以 OSG 支持的文件格式也非常多,如各种三维模型、图
片和视频等文件,这也是 OSG 的一大优势,它可以满足各行各业的需求。

1.1 三维模型文件格式

  OSG支持的三维模型文件格式类型如下表所示。
在这里插入图片描述

1.2 打包及网络传输格式

  OSG支持的打包及网络传输文件格式类型如下表所示。
在这里插入图片描述

1.3 字体文件格式

  OSG支持的字体文件格式类型如下表所示。
在这里插入图片描述

1.4 伪插件文件格式

  OSG支持的伪插件文件格式类型如下表所示。
在这里插入图片描述

2、.osg 文件和.ive 文件

  OpenSceneGraph 支持如下两种本地文件格式:

.osg OpenSceneGraph native ascii format
.ive OpenSceneGraph native binary format。

2.1 .osg 文件

  .osg 文件格式是标准的 ASCII 文本,它并不是一种可以实现高效存储和读取的数据结构,但它是一种极好的调试工具。由于它是一种文本文件,所以清晰可读。在应用程序开发时,如果遇到了意料不到的渲染结果,可以将渲染结果保存为.osg 文件,然后对其进行手动的修改从而纠正错误,这对实际调试程序来说是非常方便的。

2.2 .ive 文件

  为了加快模型导入和显示的速度,每个视景驱动软件都有自己的二进制格式,如 Vega 的 FST、Vega Prime 的 VSB 和 Performer 的 PFB 等。OSG 里面的就是 IVE,IVE 就是为了性能而生的,它把场景树存成二进制文件。所以在分发应用程序时,可以把模型转为 IVE,并把纹理打包进去(osgconvmyfile.flt——compressed myfile.ive),这样既可以达到保护自己劳动成果的目的,还能提高应用程序的性能。

3、文件读写的流程

  osgDB 库允许用户程序加载、使用和写入 3D 数据库,它采用插件管理的架构,可以支持大量常见的 2D 图形和 3D 模型文件格式。osgDB 负责维护插件的信息注册表,并负责检查将要被载入的 OSG插件接口的合法性。OSG 可以支持自己的文件格式。.osg 文件是对场景图形的一种无格式 ASCII 码文本描述,而.osga文件是一组.osg 文件的有序集合。osgDB 库包含了以上文件格式的支持代码。另外,OSG 还支持一种二进制的.ive 格式。

  由于大型的 3D 地形数据库通常是多段数据块的组合体。因此,应用程序从文件中读取各部分数据库信息时,需要在不干扰当前渲染的前提下以后台线程的方式进行,osgDB::DatabasePager 提供了这样的功能。

3.1 文件的读取与保存

3.1.1 文件的读取

  文件读取的简单代码如下:

#include<osgDB/ReadFile>
osg::ref_ptr<osg::Node> node = osgDB::readNodeFile("cow.osg");
osg::ref_ptr<osg::Image> image = osgDB::readImageFile("lz.rgb");

  上面代码中,函数类的参数可以包含绝对路径或相对路径。如果是绝对路径,OSG 会去指定的位置搜索该文件;如果是相对路径,就要复杂一点了,它会从数据路径列表中来搜索文件。在本章会提到环境变量 OSG_FILE_PATH,这个是在 OSG 中预先定义的。在用户的应用程序中,除了设置环境变量以外,还可以手动添加数据文件路径列表。有如下两种方式:

(1)第一种方式的程序代码如下:

osgDB::FilePathList pathList = osgDB::getDataFilePathList();
pathList.push_back("…");
pathList.push_back("…");
osgDB::setDataFilePathList(pathList);

(2)第二种方式的程序代码如下:

osgDB::Registry::instance()->getDataFilePathList().push_back(newpath );

  osgDB::Registry 是一个单态类(singleton),因此,要调用函数 getDataFilePathList(),就需要使用单态类的实例。osgDB::FilePathList 就是一个简单的 std::deque< std::string >。

  文件读取失败的原因可能很多,读者可以通过设置调试信息 NOTIFY 来确定,当再次读取时,就会提示相关错误或者警告信息。很多时候可能是因为找不到插件或者文件不存在造成的,这也要根据输出信息来具体确定到底是什么错误。

3.1.2.文件的保存

文件保存的简单代码如下:

#include <osgDB/WriteFile>
osgDB::writeNodeFile(*node, "saved.osg");

  文件保存失败的原因也很多。读者可以通过设置调试信息 NOTIFY 来确定,当再次保存时,就会提示相关错误或者警告信息。很多时候可能是因为找不到插件或者该扩展名不支持造成的,这也要根据输出信息具体来确定到底是什么错误。需要注意的是,当 OSG 保存文件时,如果本地有同名文件,会覆盖并不会给出任何警告的信息,所以在保存时需要自行检查本地文件是否存在同名的。

3.2 文件读写进度

  面对海量数据时,读取可能需要耗费很长的时间,这时有必要显示正在读取的数据量和读取进度等信息。下面先介绍 C++流缓冲的一些知识。众所周知,C++标准库的 iostream 提供了如下 3 种形式的缓冲:

不带缓冲区,这样与 fwrite 等操作一致。
空间自动管理的缓冲区,下一个可写位置总是为末边界+1。
外置的缓冲区,如定义局部字符串数组,并将此区域传递给 iostream。

  在带缓冲区的情况下,iostream 本身不具体负责其相关功能,而把此任务交给了 basic_streambuf及其派生类,常见的如 basic_filebuf(用于文件操作的缓冲)和 basic_stringbuf(用于字符串操作的缓冲区)。basic_iostream 的两大分支 basic_istream 和 basic_ostream 都是 basic_streambuf 的友元类,而basic_iostream 包含了一个 basic_streambuf 的派生类的实例,该实例可以通过 basic_iostream 的成员函数 rdbuf()来获取,并通过构造函数传入。我们经常使用的流操作符“<<”实际上是通过调用 basic_streambuf 的相关操作实现的。

  要控制标准输入/输出流的缓冲区行为,必须生成自己的 basic_streambuf 派生类,并生成一个该类的对象,传递给标准输入/输出流。由于基类 basic_streambuf 的很多功能没有具体实现,为了方便操作,我们需要从 basic_filebuf 或basic_stringbuf 派生。在第 6.2.5 节的示例中,显示了读取一个.osg 文件的读取进度。前面已经讲到,.osg 文件是一种 ASCII 文件,因此,.osg 支持数据流操作。在 OSG 支持的文件中,只有.osg、.ive 及一些图像文件支持流操作,都可以用数据流操作来显示读取进度。

  所有的 osgDB 插件都可以使用 osgDB::readNodeFile()、osgDB::writeNodeFile()和 osgDB::readImageFile()之类的函数来执行文件的读取和写入操作,其中一些插件还允许使用标准数据流来执行一些低层级的操作,如从用户自定义的数据流中读写数据。由于 C++标准模板库(STL)的便利性,用户可以编写自定义的数据流缓存类来跟踪 uflow()方法,从而获取当前读入的字节数。用户定义了正确的数据流缓存类(如例子程序所示)后,就可以按照如下的步骤来读取文件:

(1)给出文件名,并搜索用于读取该文件的插件,也就是调用 osgDB::Registry::instance()->getReaderWriterForExtension(),传递文件扩展名作为该函数的输入参数,并保存返回的 osgDB::ReaderWriter对象。
(2)创建自定义数据流缓存类的实例,将文件名传递给类的构造函数。此时函数将按照类似于standard std::basic_filebuf<>的方法打开文件。
(3)通过自定义类的实例创建 std::istream 对象。
(4)调用步骤(1)中获取的 ReaderWriter 对象的 readNode()方法,并将步骤(3)创建的 istream对象作为其输入参数。此时,OSG 将读入文件,同时调用自定义类的 uflow()方法,该方法将负责显示读入字节的进度信息。

3.1.2.读取进度示例
在这里插入图片描述

#include <windows.h>
#include <iostream>
#include <fstream>
#include <osgViewer/Viewer>
#include <osgDB/ReaderWriter>
#include <osgDB/ReadFile>
#include <osgDB/FileNameUtils>
#include <osgDB/FileUtils>
#include <osgDB/Registry>
#include <osgUtil/Optimizer>#pragma comment(lib, "OpenThreadsd.lib")
#pragma comment(lib, "osgd.lib")
#pragma comment(lib, "osgDBd.lib")
#pragma comment(lib, "osgUtild.lib")
#pragma comment(lib, "osgGAd.lib")
#pragma comment(lib, "osgViewerd.lib")
#pragma comment(lib, "osgTextd.lib")class CRenderingThread : public OpenThreads::Thread
{
public:CRenderingThread(osgDB::ifstream* fin) :_fin(fin){fin->seekg(0, std::ifstream::end);_length = fin->tellg();fin->seekg(0, std::ifstream::beg);};virtual ~CRenderingThread() {};virtual void run(){int pos = _fin->tellg();int nProgres = 0;std::cout << nProgres << "%%" << std::endl;while (pos < _length){pos = _fin->tellg();int nTemp = (int)(100.0 * pos / _length);if (nTemp > nProgres && nTemp%5 == 0){std::cout << nTemp << "%%" << std::endl;nProgres = nTemp;}}std::cout << "读取完成!" << std::endl;};protected:osgDB::ifstream* _fin;int _length;
};class ReadFileCB : public osgDB::Registry::ReadFileCallback
{
public:virtual osgDB::ReaderWriter::ReadResult readNode(const std::string& file, const osgDB::ReaderWriter::Options* opt){//第一步是获取OSG、IVE ReaderWriterstd::string ext = osgDB::getLowerCaseFileExtension(file);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 istream(fileName.c_str(), std::ios::in | std::ios::binary);CRenderingThread crt(&istream);crt.startThread();if (istream){std::cout << "正在读取模型文件,进度如下:" << std::endl;osgDB::ReaderWriter::ReadResult rr = rw->readNode(istream);while (crt.isRunning()) {}return rr;}return osgDB::ReaderWriter::ReadResult::ERROR_IN_READING_FILE;}
};int main()
{osg::ref_ptr<osgViewer::Viewer> viewer = new osgViewer::Viewer;osgDB::Registry::instance()->setReadFileCallback(new ReadFileCB);viewer->setSceneData(osgDB::readNodeFile("ceep.ive"));viewer->setUpViewInWindow(600, 600, 1000, 800);return viewer->run();
}

3.3 OSG中文文件名及中文路径问题

  在读写文件时,经常会遇到这样的情况,如果文件名包含中文路径就会导致无法读取或读取失败。因为我们使用的是 unicode 编码位模式,而 OSG 的库函数只支持 ANSI 编码或多字节编码。其实这是符合 C 语言规范的,因为 C 标准并不支持 unicode,只是很多 C 的实现将宽字符用 unicode 的位模式表示。这时我们需要通过 setlocale 函数将 unicode 编码的宽字符转换成一种可以支持的编码。Setlocale 函数的语法格式如下:

char * setlocale ( int category, const char * locale );

  该函数的返回值是字符串,函数种类是操作系统与环境。该函数用来配置地域的信息,设置当前程序使用的本地化信息。参数 category 可以设置为如下数值。

LC_ALL:包括所有选项的功能。
LC_COLLATE:配置字符串比较,PHP 目前尚未实作出来本项。
LC_CTYPE:配置字符类别及转换,如全变大写 strtoupper()。
LC_MONETARY:配置金融货币,PHP 目前尚未实作。
LC_NUMERIC:配置小数点后的位数。
LC_TIME:配置时间日期格式,与 strftime()合用。

  而参数 locale 若是空字符串,则会使用系统环境变量 locale。若 locale 为 0(NULL),则不会改变地域化配置,返回当前的地域值,若系统尚未实作则返回 false。

只需要做如下设置就可以实现编码格式的转换:

setlocale( LC_ALL, "Chinese-simplified" );
setlocale( LC_ALL, "chs" );
setlocale( LC_ALL, "ZHI" );
setlocale( LC_ALL, ".936" );

  关于字符编码转换,其实有很多好用的开源工具包可用,如著名的 iconv。平时积累编码方面的知识对学习 OSG 是非常有帮助的,而且在程序开发时计算机编码也是一个非常重要的方面。

//创建一个节点,读取牛的模型
osg::ref_ptr<osg::Node> node1 = new osg::Node();
/*很关键的一个函数,用于识别 unicode 中文字符 */
setlocale( LC_ALL, "chs" );
node1 = osgDB::readNodeFile("牛.ive");

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/201235.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

在耳机心率血氧健康检测中应用的穿戴心率血氧接收芯片

时代快速发展的今天&#xff0c;随着生活节奏的加快&#xff0c;工作压力的加大&#xff0c;越来越多的消费者开始关注到自身身体健康&#xff0c;加班熬夜生活不规律&#xff0c;很容易让我们的身体处于亚健康的状态&#xff0c;而心率和体温的变化&#xff0c;就能反应我们身…

报表多源关联

报表多源关联 需求背景 在项目中会遇到多种数据展现在一起的报表。例如部分指标在关系型数据库中&#xff0c;部分指标通过restful接口获得到json&#xff0c;然后根据共同的维度关联一起&#xff0c;形成新的数据集。 解决方案 在硕迪报表中有两种方式实现该多源报表&…

生产环境_从数据到层级结构JSON:使用Spark构建多层次树形数据_父子关系生成

代码补充了&#xff01;兄弟萌 造的样例数据 val data Seq(("USA", "Male", "Asian", "Chinese"),("USA", "Female", "Asian", "Chinese"),("USA", "Male", "Bl…

SSL证书续签指南

SSL证书的有效期通常为一年&#xff0c;过期后将无法提供有效的加密保护&#xff0c;使网站容易受到黑客攻击和数据泄露的风险。所以SSL证书定期要进行续签&#xff0c;好确保网站的持久安全性。 首先我们要检查当前证书的有效期&#xff0c;打开网站&#xff0c;点击浏览器地址…

网络安全等级保护V2.0测评指标

网络安全等级保护&#xff08;等保V2.0&#xff09;测评指标&#xff1a; 1、物理和环境安全 2、网络和通信安全 3、设备和计算安全 4、应用和数据安全 5、安全策略和管理制度 6、安全管理机构和人员 7、安全建设管理 8、安全运维管理 软件全文档获取&#xff1a;点我获取 1、物…

TinyMPC - CMU (卡耐基梅隆大学)开源的机器人 MPC 控制器

系列文章目录 CasADi - 最优控制开源 Python/MATLAB 库 文章目录 系列文章目录前言一、机器人硬件对比1.1 Teensy 上的微控制器基准测试1.2 机器人硬件1.3 BibTeX 二、求解器三、功能&#xff08;预期&#xff09;3.1 高效3.2 鲁棒3.3 可嵌入式3.4 最小依赖性3.5 高效热启动3.…

手机怎么录屏?实用技巧,轻松录制!

手机录屏功能在现代通信和创作中扮演着重要的角色。无论是分享游戏过程、演示手机操作&#xff0c;还是创作教程视频&#xff0c;手机录屏成为了用户不可或缺的工具。本文将深入研究手机怎么录屏的三种方法&#xff0c;通过详细的步骤介绍&#xff0c;帮助用户轻松掌握手机录屏…

【无标题】从0到1 搭建一个vue3+Django项目

目录 一、后端项目python django二、前端项目vitevue3三、后端配置3.1 将路由指向app3.2 app下创建urls.py&#xff0c; 写入路由3.3 views写入test函数3.4 启动服务&#xff0c;访问路由 四、前端配置4.1 安装一些工具库及创建文件4.1.1 安装需要用的三方库4.1.2 创建文件 4.2…

Nacos 服务注册与发现

一、Spring Cloud Commons 二、使用方法 &#xff08;1&#xff09;在cloud-demo父工程中添加spring-cloud-alilbaba的管理依赖 &#xff08;2&#xff09;注释掉order-service和user-service中原有的eureka依赖 &#xff08;3&#xff09;添加nacos的客户端依赖 &#xff08;4…

Mysql学习查缺补漏----02 mysql之DCL 数据控制语言

查看数据库里都有哪些用户。 使用root任何一个用户都可以登录。 本机登录。 也可以这样登录其他的机器。 、 修改user表。 刷新权限&#xff1a; 现在我们看到了只有本机才能登陆。 我们这样就可以限制这个mysql指定某台服务器登录。 详解忘记密码以及如何修改用户密码 我们…

华为全面对标iOS,“纯血鸿蒙”时代来了

原创 | 文 BFT机器人 就在今年的10月份&#xff0c;华为官方宣布&#xff0c;鸿蒙OS 4升级设备数量已经突破1亿&#xff0c;成为史上升级最快的鸿蒙OS版本。 伴随着“Harmony OS NEXT”的启动&#xff0c;鸿蒙系统开发者社区迎来了喜讯——新增注册开发者数量已过万&#xff0…

C++ 命名空间详解

目录 引入例子 命名空间的定义 命名空间的使用 命名空间使用注意事项 引入例子 #include <stdio.h> #include <stdlib.h>int rand 10;int main() {printf("%d\n", rand);return 0; } 当我们用C语言写下这样的代码&#xff0c;看着并没有什么语法问…

AI助力智慧农业,基于YOLOv5全系列模型【n/s/m/l/x】开发构建不同参数量级农田场景下庄稼作物、杂草智能检测识别系统

紧接前文&#xff0c;本文是农田场景下庄稼作物、杂草检测识别的第二篇文章&#xff0c;前文是基于YOLOv3这一网络模型实现的目标检测&#xff0c;v3相对来说比较早期的网络模型了&#xff0c;本文是基于最为经典的YOLOv5来开发不同参数量级的检测端模型。 首先看下实例效果&a…

介绍一款在线文件格式转换工具

原因: 今天要将一个pdf格式的文件转为docx格式,结果我用破解版的WPS无法再不登录的情况下转换,所以就搜索了一款在线工具实现功能。 网站地址: Convertio — 文件转换器 使用流程: 1)选择要转换的文件 2)选择要转换的格式 3)点击转换 4)等待上传 5)等待转换 6)下载到本地

Linux简单部署Yearning并结合内网穿透工具发布至公网可访问

目录 前言 1. Linux 部署Yearning 2. 本地访问Yearning 3. Linux 安装cpolar 4. 配置Yearning公网访问地址 5. 公网远程访问Yearning管理界面 6. 固定Yearning公网地址 前言 Yearning 简单, 高效的MYSQL 审计平台 一款MYSQL SQL语句/查询审计工具&#xff0c;为DBA与开发…

Vue混淆与还原

Vue混淆与还原 引言 Vue是一种流行的JavaScript框架&#xff0c;用于构建用户界面。它简单易用且功能强大&#xff0c;备受开发者喜爱。然而&#xff0c;在传输和存储过程中&#xff0c;我们需要保护Vue代码的安全性。混淆是一种有效的保护措施&#xff0c;可以加密和压缩代码…

Course2-Week1-神经网络

Course2-Week1-神经网络 文章目录 Course2-Week1-神经网络1. 神经网络概述1.1 欢迎来到Course21.2 神经元和大脑1.3 引入神经网络-需求预测1.4 神经网络的其他示例-图像感知 2. 神经网络的数学表达式2.1 单层的神经网络-需求预测2.3 前向传播的神经网络-手写数字识别 3. Tensor…

学生护眼台灯怎么样选择?适合考研的护眼台灯推荐

很多家长都是为了孩子的视力健康而置换的护眼台灯&#xff0c;但是有一部分孩子用了之后反而会和家长说出现眼睛不太舒服&#xff0c;甚至近视加深的情况。而引发这种情况的大多数为产品不达标或非专业台灯&#xff0c;因为专业护眼台灯是真实能够保护眼睛的。 所以很多人都对护…

文件上传漏洞(带实例)

漏洞介绍&#xff1a; 现代互联网的Web应用程序中&#xff0c;上传文件是一种常见的功能&#xff0c;因为它有助于提高业务效率&#xff0c;如企业的OA系统&#xff0c;允许用户上传图片&#xff0c;视频&#xff0c;头像和许多其他类型的文件。然而向用户提供的功能越多&#…

【Polar靶场WEB签到】

题目&#xff1a; <?phperror_reporting(0);$file $_GET[file];if(!isset($file))$file 1;$file str_replace(../, , $file);include_once($file.".php");highlight_file(__FILE__); ?>解答&#xff1a;1、进入index页面&#xff0c;说让你加弟弟&#x…