osg实现自定义插件读取自定义格式的模型文件到场景
目录
1. 前言
2. 预备知识
3. 工具、原料
4. 代码实现
1. 前言
osg提供了很多插件来读取模型文件到场景中,这些插件支持大约70种格式类型的文件,但现实中的文件是各式各样,osg不可能囊括所有类型文件,当osg不支持某种类型格式文件时,就需要自己根据文件的格式开发插件来对这些文件定制解析、读取。
本文讲解在osg中,如何实现自定义插件读取自定义格式的模型文件到场景。在读本博文之前,强烈建议先看osgDB::readNodeFile等函数源码剖析博文,该篇博文对osg读取文件的核心函数osgDB::readNodeFile的源码及原理机制进行了深入的剖析,看完并理解后,更加深对本博文的理解。
2. 预备知识
在osgDB::readNodeFile等函数源码剖析 博文提到,如果想要读取一个自定义格式的文件,则:
- 必须开发一个读写器类,该读写器类从ReaderWriter类派生,并重写相应的虚函数。
- 利用REGISTER_OSGPLUGIN宏将自定义读写器注册到系统内部,该宏的第1个参数为该类型文件的扩展名,第2个参数是自定义的读写器类名称。
- 将1、2步用dll来封装实现,dll文件名格式为:osgdb_ext.dll或osgdb_extd.dll,其中ext为文件扩展名,d表示debug版,没d的表示release版,并将生成的dll放到osgPlugins-xx.yy.zz目录,其中xx.yy.zz为osg版本号。
3. 工具、原料
本次用到的开发环境如下:
- osg 3.6.2。
- Visual Studio 2022。
- Windows 11 操作系统。
4. 代码实现
现在假设有一个名称为sphere.csdn 格式的文件,文件内容如下:
图1
这个文件包含创建一个地球所需的数据,其中第1个数值表示球半径;接下来三个数值表示球心位置x、y、z的值,即球位于何处;最后一个表示贴在球上的纹理图片,注意,该纹理图片位于工程的当前目录下。这几个数据之间用空格隔开,空格的个数无所谓。问题的提出:怎么解析这个文件,将其数据在视景器中展现出来?
步骤如下:
- 先用Visual Studio 2022建立一个dll工程,并将该dll编译生成的输出目录设置为:osg插件目录下,如:E:\osg\build_osg3.6.2\bin\osgPlugins-3.6.2,请根据你本机实际更改此目录。
- 将debug版的dll目标文件名称改为osgdb_csdnd,release版为osgdb_csdn,其中csdn为文件扩展名。
- 在Visual Studio 2022中请自行设置该工程的头文件和lib文件,这是osg开发基础,在次不赘述。
- 新建一个readMy3DModel类。
如下为该插件在Visual Studio 2022的设置:
图2
readMy3DModel类的.h文件和cpp文件如下:
.h文件:
#ifndef _READMY3DFMODEL_EXPORT_H
#define _READMY3DFMODEL_EXPORT_H
#include<osgDB/ReaderWriter>
#include<osgDB/Registry>
using namespace osgDB;
class readMy3DModel : public ReaderWriter
{
public:readMy3DModel();~readMy3DModel();
public:// 返回类名virtual const char* className() const override;// 读节点virtual ReaderWriter::ReadResult readNode(const std::string& fileName, const osgDB::ReaderWriter::Options* options) const override;private:osg::Node* makeSphere(const std::string& strFileDirPath, std::ifstream& stream) const;void doTexture(const std::string& strTextureImageFilePath, osg::Geode* pShereGeode) const;
};REGISTER_OSGPLUGIN(csdn, readMy3DModel)#endif
.cpp文件:
#include "readMy3DModel.h"
#include<osgDB/FileNameUtils> // 这里有很多文件操作相关的工具类,如:获取文件扩展名、文件目录名等
#include<osgDB/FileUtils> // 这里有很多文件操作相关的工具类,如:文件是否存在,查找文件、文件类型等
#include<osgDB/ReadFile>
#include<osg/ShapeDrawable>
#include<osg/Texture2D>
readMy3DModel::readMy3DModel()
{supportsExtension("csdn", "sphere csdn model");
}readMy3DModel::~readMy3DModel()
{}ReaderWriter::ReadResult readMy3DModel::readNode(const std::string& fileName, const osgDB::ReaderWriter::Options* options) const
{ReaderWriter::ReadResult result;auto strExt = osgDB::getLowerCaseFileExtension(fileName);// 在构造函数里必须先通过supportsExtension函数将文件的扩展名加入,否则这里会返回falseif (!acceptsExtension(strExt)) {OSG_WARN << fileName << "Not Found!";result = ReaderWriter::ReadResult::FILE_NOT_FOUND;return result;}auto strFileFullPath = osgDB::findDataFile(fileName, options); // 获取文件的绝对路径if (!osgDB::fileExists(strFileFullPath)){OSG_WARN << strFileFullPath << "is not exist!";result = ReaderWriter::ReadResult::FILE_NOT_FOUND;return result;}auto strFileDirPath = osgDB::getFilePath(strFileFullPath); // 获取模型文件所在的目录std::ifstream stream(strFileFullPath.c_str(), std::ios::in | std::ios::binary);if (!stream){result = ReaderWriter::ReadResult::ERROR_IN_READING_FILE;return result;}// 构建球体result = makeSphere(strFileDirPath, stream);return result;
}const char* readMy3DModel::className() const
{return "sphere csdn model";
}osg::Node* readMy3DModel::makeSphere(const std::string& strFileDirPath, std::ifstream& stream) const
{osg::Node* pShereNode{nullptr};osgDB::Input fr;fr.attach(&stream);// 以下解析sphere.csdn文件auto radius = 0.0f;auto center = osg::Vec3d(0.0, 0.0, 0.0);auto textureImageFilePath = std::string();/* 读取%f表示读取数值,%s表示读取字符串。注意:%f与%f或%f与%s之间的分隔符即空格个数不需要和sphere.csdn文件完全一致sphere.csdn中要是字符串,必须用英文双引号括起来*/if (!fr.matchSequence("%f %f %f %f %s")){return pShereNode;}fr.readSequence(radius);auto x = 0.0f, y = 0.0f, z = 0.0f;fr.readSequence(x);fr.readSequence(y);fr.readSequence(z);center.set(x, y, z);fr.readSequence(textureImageFilePath);textureImageFilePath = strFileDirPath + R"(\)" + textureImageFilePath;bool bTextureImageFilePathIsExist = osgDB::fileExists(textureImageFilePath);if (!bTextureImageFilePathIsExist){OSG_WARN << textureImageFilePath << "is not exist!";}auto pShereGeode = new osg::Geode();osg::TessellationHints* pHints = new osg::TessellationHints;pHints->setDetailRatio(5.0f); // 球的精细度设置auto pSpere = new osg::ShapeDrawable(new osg::Sphere(center, radius), pHints);pShereGeode->addDrawable(pSpere);pShereNode = pShereGeode;if (bTextureImageFilePathIsExist){doTexture(textureImageFilePath, pShereGeode);}return pShereNode;
}// 为地球贴纹理
void readMy3DModel::doTexture(const std::string& strTextureImageFilePath, osg::Geode* pShereGeode) const
{/*注意:这里需要读取jpg,故请保证jpg插件存在,否则读取jpg会失败。关于怎么编译jpg插件到osg,请参见:https://blog.csdn.net/danshiming/article/details/115412956*/auto pImage = osgDB::readImageFile(strTextureImageFilePath);if (nullptr == pImage){OSG_WARN << "read " << strTextureImageFilePath << "Failed!";return;}// 构造二维纹理对象auto pTexture2D = new osg::Texture2D;pTexture2D->setImage(pImage);// 设置二维纹理过滤器属性pTexture2D->setWrap(osg::Texture::WRAP_S, osg::Texture::CLAMP);pTexture2D->setWrap(osg::Texture::WRAP_T, osg::Texture::CLAMP);pTexture2D->setFilter(osg::Texture::MIN_FILTER, osg::Texture::LINEAR);pTexture2D->setFilter(osg::Texture::MAG_FILTER, osg::Texture::LINEAR);// 将纹理贴到地球上pShereGeode->getOrCreateStateSet()->setTextureAttributeAndModes(0, pTexture2D, osg::StateAttribute::ON);
}
说明:
- 在.h文件中需要通过如下宏,将该插件类即该读写器注册到osg内核:
REGISTER_OSGPLUGIN(csdn, readMy3DModel)
关于这个宏的作用及参数含义,请参见前提提到的那篇博客。
- 本类重写了父类的className和readNode函数。
- osgDB::Input从osgDB:: FieldReaderIterator类派生而来,是一个字段迭代器,通过该对象可以遍历sphere.csdn中每个字段。当然,你也可以自己实现读取一行然后按空格解析出每个数据。
- 因为贴纹理时,用的是jpg图片,所以本机需要有读取jpg的插件并挂接到osg中,关于怎么编译jpg插件到osg,请参见:osg第三方插件的编译方法(以jpeg插件来讲解)博文。
- 其它的内容,请参见注释。
请确保sphere.csdn和land_shallow_topo_2048.jpg文件在当前工程目录下,编写主程序以便调用该dll,如下:
#include<osgViewer/Viewer>
#include<osgDB/readFile>
#include<osgDB/FileUtils>int main(int argc, char *argv[])
{osgViewer::Viewer viewer;osg::ref_ptr<osgDB::Options>spOptions = new osgDB::Options();spOptions->setDatabasePath("."); // 设置文件搜索目录,即在当前目录下看是否存在sphere.csdn文件auto pSphereNode = osgDB::readNodeFile("sphere.csdn", spOptions);auto pRoot = new osg::Group;pRoot->addChild(pSphereNode);viewer.setSceneData(pRoot);return viewer.run();
}
运行结果如下:
图3
也可以在命令行中输入如下命令验证是否加载成功:
osgViewerd sphere.csdn
至此,一个自定义的读写插件开发完成。
相关文章:
osg实现自定义插件读取自定义格式的模型文件到场景
目录 1. 前言 2. 预备知识 3. 工具、原料 4. 代码实现 1. 前言 osg提供了很多插件来读取模型文件到场景中,这些插件支持大约70种格式类型的文件,但现实中的文件是各式各样,osg不可能囊括所有类型文件,当osg不支持某种类型格式…...
redis进阶
redis.conf 启动的时候就通过配置文件来启动的! # 这个不是配置的,就是在这儿说明一下 # 当配置中需要配置内存大小时,可以使用 1k, 5GB, 4M 等类似的格式,其转换方式如下(不区分大小写) # # 1k > 1000 bytes # 1kb > 102…...
(一)正点原子STM32MP135移植——准备
一、简述 使用板卡:正点原子的ATK-DLMP135 V1.2 从i.mx6ull学习完过来,想继续学习一下移植uboot和内核的,但是原子官方没有MP135的移植教程,STM32MP157的移植教程用的又是老版本的代码,ST官方更新后的代码不兼容老版本…...
Kotlin的关键字 lateinit 和 lazy
序、完善一下曾经的草稿。 Kotlin通常要求我们在定义属性后立即对起进行初始化,当我们不知道理想的初始值时,这样做似乎很奇怪,尤其是在生命周期驱动android属性的情况下。 lateinit 简介 lateinit,Kotlin提供的一个可以延迟初…...
阿里云服务器ECS详细介绍_云主机_服务器托管_弹性计算
阿里云服务器ECS英文全程Elastic Compute Service,云服务器ECS是一种安全可靠、弹性可伸缩的云计算服务,阿里云提供多种云服务器ECS实例规格,如经济型e实例、通用算力型u1、ECS计算型c7、通用型g7、GPU实例等,阿里云服务器网分享阿…...
12、建立健全人员培训体系
9、大小屏分离与精细化审核 10、质量审核的设立与合并 11、视频分类建议 内容仓为公司其他部门输送了许多人才,既包括有潜力的主管,也有表现突出或者具备某些特殊能力的员工,从内容仓走出的同事,有些已经成为公司重要业务某个方…...
代码随想录算法训练营第五十九天 | 647. 回文子串 516.最长回文子序列
1. 回文子串 647. 回文子串 - 力扣(LeetCode) 一个子串左右两个元素相等,并且中间对称,才是回文子串 即 ij 时,[i1: j-1]对称 dp[i][j]: [i:j] 是否是回文字串 当 子串长度大于2 由 dp[i1][j-1] 推出…...
React Redux
redux是什么 Redux是一个模式和库,用于管理和更新应用程序状态,使用称为“action”的事件。它是需要在整个应用程序中使用的状态的集中存储,规则确保状态只能以可预测的方式更新。 Redux主要有三个功能: 获取当前状态更新状态监…...
StreamingLLM - 处理无限长度的输入
文章目录 关于 StreamingLLM使用关于 StreamingLLM Efficient Streaming Language Models with Attention Sinks GitHub : https://github.com/mit-han-lab/streaming-llm论文:https://arxiv.org/abs/2309.17453在流媒体应用程序(如多轮对话)中 部署大型语言模型(LLM)是迫…...
[Linux 命令] nm 详解
1. nm 命令: 显示关于指定 File 中符号的信息,文件可以是对象文件、可执行文件或对象文件库。如果文件没有包含符号信息,nm 命令报告该情况,但不把它解释为出错条件。 nm 命令缺省情况下报告十进制符号表示法下的数字值。 2. 命…...
好文学作品的鉴赏标准
好文学作品的鉴赏标准 2023年诺贝尔文学奖颁给了挪威剧作家约恩福瑟。由于之前的博彩公司给中国作家残雪开出了最高的赔率,以及诺贝尔官方推特在揭晓奖项前发布了一张泰戈尔99年前访华的老照片,残雪的获奖氛围在国内各类媒体的渲染下被拉至极高。当奖项…...
智慧公厕:将科技融入日常生活的创新之举
智慧公厕是当今社会中一项备受关注的创新项目。通过将科技融入公厕设计和管理中,这些公厕不仅能够提供更便利、更卫生的使用体验,还能够极大地提升城市形象和居民生活质量。本文将以智慧公厕领先厂家广州中期科技有限公司,大量的精品案例项目…...
ROS(0)命令及学习资源汇总
ROS安装命令 参考:Ubuntu20.04.4安装ROS Noetic详细教程 - 知乎 安装C和Python3 sudo apt-get install g sudo apt-get install python3 ROS运行小海龟仿真器 roscore确定ROS是否运行成功rosrun turtlesim turtlesim_node运行小海龟仿真器rosrun turtlesim turtle_…...
NodeMCU ESP8266开发流程详解(图文并茂)
文章目录 整体架构打开软件setuploop 连接开发板CP2102版本CH340版本 下载结论 整体架构 NodeMCU ESP8266基于Arduino IDE的开发相对来说还是比较容易上手的,我们基本需要以下几个东西; 一台安装好Arduino IDE的PC,并且已经部署环境&#x…...
【最终版】tkinter+matplotlib实现一个强大的绘图系统
文章目录 辅助坐标轴功能实现代码优化源代码 Python绘图系统: 前置源码: Python打造动态绘图系统📈一 三维绘图系统 📈二 多图绘制系统📈三 坐 标 轴 定 制📈四 定制绘图风格 📈五 数据生成导入…...
Postman使用实例
Postman使用实例 实体类Emp package com.example.springboot_postman.pojo;import com.fasterxml.jackson.annotation.JsonIgnoreProperties; import lombok.AllArgsConstructor; import lombok.Data; import lombok.NoArgsConstructor;import javax.persistence.*; import j…...
【ES的优势和原理及分布式开发的好处与坏处】
文章目录 ES的优势及分布式开发的好处1.ES的优势1.1 优势概述1.2 相关问题1)为什么需要 Elasticsearch?MySQL 不行吗?2)SQL检索的问题:3)ES检索快的原理 2.分布式开发的好处与坏处 ES的优势及分布式开发的好…...
Autosar诊断实战系列23-CanTp半/全双工及相关工程问题思考
本文框架 前言1. CanTp半/全双工基本介绍1.1 差异比较1.2 不同模式下可能发生场景分析1.2.1 当CanTp正在发送1.2.2 当CanTp正在接收2. 相关工程问题思考前言 在本系列笔者将结合工作中对诊断实战部分的应用经验进一步介绍常用UDS服务的进一步探讨及开发中注意事项, Dem/Dcm/C…...
【Pandas】数据分组groupby
本文目标: 应用groupby 进行分组对分组数据进行聚合,转换和过滤应用自定义函数处理分组之后的数据 文章目录 1. 数据聚合1.1 单变量分组聚合1.2 Pandas内置聚合方法1.3 聚合方法使用Numpy的聚合方法自定义方法同时计算多种特征向agg/aggregate传入字典 2. 数据转换…...
【图像处理GIU】图像分割(Matlab代码实现)
💥💥💞💞欢迎来到本博客❤️❤️💥💥 🏆博主优势:🌞🌞🌞博客内容尽量做到思维缜密,逻辑清晰,为了方便读者。 ⛳️座右铭&a…...
Java中的锁与锁优化技术
文章目录 自旋锁与自适应自旋锁消除锁粗化轻量级锁偏向锁重量级锁 自旋锁与自适应自旋 自旋锁是一种锁的实现机制,其核心思想是当一个线程尝试获取锁时,如果锁已经被其他线程持有,那么这个线程会在一个循环中不断地检查锁是否被释放…...
布局与打包
属性栏直接输入值,比代码更直观方便。 打包:...
UVa11324 - The Largest Clique
Online Judge 题目大意:有一张n个点m条边的图,现对于每一个点u,建立一条边连接它和所有它能到达的点,问满足所有点之间都有边的分量的大小最大是多少 0<n<1000;0<m<50000 思路:根据建新图的规则可知&am…...
【Linux】TCP的服务端(守护进程) + 客户端
文章目录 📖 前言1. 服务端基本结构1.1 类成员变量:1.2 头文件1.3 初始化:1.3 - 1 全双工与半双工1.3 - 2 inet_aton1.3 - 3 listen 2. 服务端运行接口2.1 accept:2.2 服务接口: 3. 客户端3.1 connect:3.2 …...
1.7. 找出数组的第 K 大和原理及C++实现
题目 给你一个整数数组 nums 和一个 正 整数 k 。你可以选择数组的任一 子序列 并且对其全部元素求和。 数组的 第 k 大和 定义为:可以获得的第 k 个 最大 子序列和(子序列和允许出现重复) 返回数组的 第 k 大和 。 子序列是一个可以由其他数…...
基于微信小程序的付费自习室
博主介绍:✌程序员徐师兄、7年大厂程序员经历。全网粉丝30W、csdn博客专家、掘金/华为云/阿里云/InfoQ等平台优质作者、专注于Java技术领域和毕业项目实战✌ 文章目录 1 简介2 技术栈3 需求分析3.1用户需求分析3.1.1 学生用户3.1.3 管理员用户 4 数据库设计4.4.1 E…...
纪念在CSDN的2048天
时间真快~...
云原生Kubernetes:简化K8S应用部署工具Helm
目录 一、理论 1.HELM 2.部署HELM2 3.部署HELM3 二、实验 1.部署 HELM2 2.部署HELM3 三、问题 1.api版本过期 2.helm初始化报错 3.pod状态为ImagePullBackOff 4.helm 命令显示 no repositories to show 的错误 5.Helm安装报错 6.git命令报错 7.CentOS 7 下git c…...
qml保姆级教程五:视图组件
💂 个人主页:pp不会算法v 🤟 版权: 本文由【pp不会算法v】原创、在CSDN首发、需要转载请联系博主 💬 如果文章对你有帮助、欢迎关注、点赞、收藏(一键三连)和订阅专栏哦 QML系列教程 QML教程一:布局组件 文章目录 列表视图ListVi…...
2310d编译不过
struct A {this(int[] data) safe { a data; }int[] a; }void main() safe {int[3] test [1, 2, 3];A a A(test); }应该给data参数加上return scope.或让构造器为模板参数来推导,否则,构造器可以把栈分配切片赋值给全局变量....
怎么做查询数据输入的网站/上海有名网站建站开发公司
“这里会给你最新、最快的极速体验beat~”时间不知不觉到了10月份的最后一天,明天又是全新的一个月,不知道大家在10月里收获得怎么样,反正我是过的很充实了。每天早起上课,晚上给大家更新文章都已经成为了常态了,加油打…...
最新新闻热点事件短篇/长沙seo外包服务
NUit Test Adapter 安装,两种方式 第一种:从扩展和更新里搜索nunit,进行下载安装 第二种:在项目中右键,管理NuGet程序包,搜索nunit 打开窗口: 编写测试用例: TestFixtureAttribute标…...
西宁网站seo/二十条优化措施原文
今天看JVM的过程中收获颇丰,但一想到这些学习心得将来可能被遗忘,便一阵恐慌,自觉得以后要开始坚持做读书笔记了。 操作系统层面的内存管理 物理内存是一切内存管理的基础,Java中使用的内存和应用程序的内存一样是从物理内存申请下…...
做软件下载网站/百度百度一下一下
LibreOffice 的开发者已着手打造一个新的工具栏布局,以给用户提供更好的使用体验。 在 LibreOffice Wiki 上已经有这个新的 NotebookBar 的介绍,“目标是提供一个替代的(可选的)界面,统一所用不同的工具栏并归类到标签…...
宜兴建设局 审图中心 网站/seo网站排名的软件
让骑行更安全的智能头盔,轻便又好用,力沃BH51M Neo体验 我发现如今使用单车、电动滑板等轻量载具的朋友越来越多了,相比于机动车,这类交通工具不仅方便,而且更加环保,不过在骑车的时候也要佩戴好必要的护具,像是手套、头盔之类的,这样在公路上骑行的时候才能更加安全。…...
wordpress 带数据库吗/长尾关键词挖掘站长工具
我在选择框架的时候非常谨慎,因为一个PHPer在选定这个框架来学习的时候,必定是全身心的投入并熟悉这个框架的逻辑习惯等等。有人告诉我说:“我都学了好几个框架了。”。我想告诉他你对你学习的框架产生了习惯了么?PHPer的第一个框…...