osg实现自定义插件读取自定义格式的模型文件到场景

【OSG系列】osgDB库 文件格式支持:osgDB库支持许多常见的3D模型和图像文件格式,包括但不限于:.osg、.obj、.dae、.fbx、.3ds、.stl、.png、.jpg等。使用方法:通过使用osgDB库,您可以轻松地从文件中加载3D模型和图像数据,或将数据保存到文件中。您可以使用预定义的函数来读取和写入不同的文件格式。osgDB是OpenSceneGraph的一个库,用于读取和写入3D模型和图像文件。它提供了一组函数和类,可以加载和保存多种文件格式的数据。功能:osgDB库提供了读取和写入3D模型和图像文件的功能。 阅读详情

目录

1. 前言

2. 预备知识

3. 工具、原料

4. 代码实现


1. 前言

        osg提供了很多插件来读取模型文件到场景中,这些插件支持大约70种格式类型的文件,但现实中的文件是各式各样,osg不可能囊括所有类型文件,当osg不支持某种类型格式文件时,就需要自己根据文件的格式开发插件来对这些文件定制解析、读取。

         本文讲解在osg中,如何实现自定义插件读取自定义格式的模型文件到场景。在读本博文之前,强烈建议先看osgDB::readNodeFile等函数源码剖析博文,该篇博文对osg读取文件的核心函数osgDB::readNodeFile的源码及原理机制进行了深入的剖析,看完并理解后,更加深对本博文的理解。

2. 预备知识

        在osgDB::readNodeFile等函数源码剖析 博文提到,如果想要读取一个自定义格式的文件,则:

  1. 必须开发一个读写器类,该读写器类从ReaderWriter类派生,并重写相应的虚函数。
  2. 利用REGISTER_OSGPLUGIN宏将自定义读写器注册到系统内部,该宏的第1个参数为该类型文件的扩展名,第2个参数是自定义的读写器类名称。
  3. 将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的值,即球位于何处;最后一个表示贴在球上的纹理图片,注意,该纹理图片位于工程的当前目录下。这几个数据之间用空格隔开,空格的个数无所谓。问题的提出:怎么解析这个文件,将其数据在视景器中展现出来?

步骤如下:

  1. 先用Visual Studio 2022建立一个dll工程,并将该dll编译生成的输出目录设置为:osg插件目录下,如:E:\osg\build_osg3.6.2\bin\osgPlugins-3.6.2,请根据你本机实际更改此目录。
  2. 将debug版的dll目标文件名称改为osgdb_csdnd,release版为osgdb_csdn,其中csdn为文件扩展名。
  3. 在Visual Studio 2022中请自行设置该工程的头文件和lib文件,这是osg开发基础,在此不赘述。
  4. 新建一个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函数将文件的扩展名加入,否则这里会返回false
	if (!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.youkuaiyun.com/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_osgDB插件机制 最近研究了一段osg/osgDB插件读写机制,xiechulai 阅读详情

相关推荐

OSG第二代文件序列化存储分析

花了两天时间仔细研究了一下array贡献的第二代文件序列化存储,收益颇多。今后将得益于它的很强的可扩展性。通过自身的体验,感觉应该还有很多初学者可能需要花费几个小时才能看透,所以特将自己分析的流程发上来,以加快想搞明白其流程的初学者的学习速度。这两天身体状况不太好,两眼通红,眼睛

Oman-3D 5257

osg之osgDB读取文件详解

osg、osgEarth所有文件都是通过osgDB库来读取,通过Registry来查找文件拓展名对应的osg库(Registry是一个单例类,这个类特别重要,建议通读代码加深对此的理解),根据一定规则拼接成完成的osg库名并加载,通过ReaderWriter对象来完成节点的读取(ReaderWriter是读写节点的基类,可通过派生此类重写读写方法实现自己的读写格式)。 一、osg读取一个节点的方法 osg::ref_ptr<osg::Node> pNode = osgDB::readNodeFi

的博客 8869

QT+OSG/osgEarth编译之八十二:osgDB+Qt编译(一套代码、一套框架,跨平台编译,版本:OSG-3.6.5核心库osgDB)

通过一套osgDB代码和框架,实现osgDB的跨平台编译。 在Qt环境下,集成osg核心库osgDB头文件、库文件,构建跨平台编译的pro文件。 通过构建的一套配置工程,基于Qt Creator IDE,完成跨平台的编译实践。 在Windows、Linux、MacOS等操作系统上进行测试,成功编译,形成的成果(头文件、库文件等)可在不同系统下调用或使用,从而更好地构建跨平台解决方案。 采用的是osg-3.6.5版本的osgDB。 读者可参考博客中的集成原理和pro文件,构建不同版本的osgDB跨平台包。

LuckyHanMo的博客 1016

osgDB::readNodeFile等函数源码剖析

osg的文件读写接口主要是由osgDB库负责实现。可读写的文件包括:模型、图像、视频、字体、文本文档等。搞清楚这些读写函数内部的实现机制,对于熟悉osg并为自己以后编写读取特定文件的插件是至关重要的。

danshiming的博客 1565

OSG开发笔记(二十九):OSG加载模型文件、加载3DMax三维型文件Demo

Osg深入之后需要打开模型文件,这些模型文件是已有的模型文件,加载入osg之后可以在常见中展示模型文件,该节点可以操作,多个逼真的模型的节点就实现了基本的场景构建。自定义文件插件主要是自定义一个插件读写类,继承osgDB::ReaderWriter类,然后根据需求重写如readNode等函数方法即可。

长沙红胖子 Qt・西安|省级科研团队从业背景,深耕双一流体系高精尖技术配套研发|剥离高精尖机理,沉淀高端特种行业领域 Qt 工程化落地经验|博文仅分享通用技术总结,输出公开普适工程思路。 1万+

OSG 3D模型格式插件

这些 DLL 文件是 OpenSceneGraph 的模型格式插件功能:每种插件负责一种特定的3D模型文件格式的导入和导出自动加载:当调用时,OSG 会根据文件扩展名自动加载对应的插件重要性:这些插件是 OSG 与各种3D建模软件之间的桥梁:通用静态模型交换:兼容老旧3D Studio格式:专业动画和复杂场景:开放标准,学术研究:3D打印和纯几何数据。

深之JohnChen的专栏 638

OSG Day006

OSG学习入门

Junglefor的博客 1693

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

OSG支持的三维文件格式、如何读写、保存文件及对中文字符的支持;附加读取文件的进度示例

欧特GO 2144

【OSG学习笔记】Day 41: ReadFileCallback 与 WriteFileCallback(自定义文件读取)

OSG文件读写回调机制解析:本文深入探讨了OpenSceneGraph中的ReadFileCallback和WriteFileCallback自定义文件读写机制。通过继承osgDB::Registry中的抽象回调类,开发者可以在不修改底层源码的情况下扩展文件读写功能,实现日志记录、耗时统计等定制化需求。文章详细分析了回调类的继承关系、核心原理及实现方法,并提供了完整的可运行代码示例,展示了如何注册全局回调并在文件读写前后执行自定义逻辑。这种钩子设计模式为OSG开发提供了灵活的功能扩展能力,同时保持了原有读写

u012739527的博客 896

OSG原生文件格式

最佳性能:快速加载和解析完整功能:支持所有 OSG 特性版本兼容:向前和向后兼容性管理压缩支持:可选的数据压缩格式扩展名对应的插件格式类型主要特点.osg文本格式人类可读、可调试.osgt文本格式带模板的文本格式.osgb二进制格式高性能、文件小.ive二进制格式分页数据库专用cpp// 设置输出选项// 内嵌图像数据// 浮点数精度.osg:用于开发和调试,人类可读.osgt:用于模板化资源,减少重复.osgb:用于最终发布,最佳性能.ive:用于大规模场景,分页加载。

深之JohnChen的专栏 201

OSG中osgDB库

如果你有自定义的文件格式,可以为osgDB编写自己的读写插件。你需要继承特定的基类(如)并实现readNodewriteNodereadImagewriteImage等虚函数,然后将代码编译成动态库放入 OSG 插件路径即可。自定义插件本质上是一个动态链接库.dll.soon Linux,.dylibon macOS)。这个库需要实现并导出一个继承自的类,该类包含了识别文件扩展名、读取文件和写入文件的逻辑。OSG 在运行时会在其插件路径(由环境变量。

深之JohnChen的专栏 313

OSG学习之路(一)osg各个库的用途

介绍一下osg各个库的用途 组件 Osg核心库 提供了基本的场景图形和渲染功能,以及3d图形程序所需的某些特定功能实现。包括: osg库 包含了用于创建场景图形的场景图形节点类,用作向量和矩阵运算的类,几何体类,以及用于描述和管理渲染状态的类,3d图形程序所需的典型功能类,例如命令行参数解析,动画路径管理,以及错误和警告信息类。 osgUtil库 osg工具库包含的类和函数,可以用于场景图形...

qq_43238450的博客 6369

OSG 3.4.0集成FBX插件实现三维模型读取功能

为了实现条件编译,OSG社区在CMake系统中引入了专用宏,用于控制是否启用FBX插件构建。endif()同时,在源码中通过预处理器判断是否包含相关实现:// ...#endif该宏还可进一步细分为::仅启用动画支持:仅处理几何体此类细粒度控制有助于裁剪功能集,适用于资源受限的嵌入式系统。graph LR上述流程体现了构建系统的决策逻辑,强调了依赖发现与条件编译的重要性。虽然。

weixin_42593701的博客 1171

osgCopc:基于OSG的插件,支持大体量Copc点云读取

本章将介绍一种新的海量点云渲染方案—osgCopc。作为 OSG 的插件,将 COPC(Cloud Optimized Point Cloud,云优化点云)格式集成到场景图中。该插件充分发挥了 COPC 的云原生优势,通过将 COPC 内部的八叉树索引信息动态地转化为 OSG 的PagedLOD节点,实现了海量数据在本地或云端的按需加载、分级渲染与高效流式传输。osgPotree: 针对Potree 2.0转换的结果,在osg中直接显示,通过插件osgPotree实现。目录1 COPC点云介绍。

CPWWHSU的博客 864

深入理解OSG如何读取FBX文件

OpenSceneGraph (OSG) 是一个高性能的、跨平台的开源3D图形工具库,它能够帮助开发者构建各种图形应用程序,如模拟器、虚拟现实和游戏等。OSG最初由Don Burns和Robert Osfield在20世纪90年代后期开发,其目的是提供一个易用、高效且功能强大的3D图形引擎。这个库广泛应用于图形和仿真领域,已成为IT行业中备受推崇的图形解决方案之一。FBX最初由Kaydara公司开发,用于其3D动画软件Fusion Studio。

weixin_28840811的博客 1176

跨平台3D模型格式转换工具:从OSG到OSGB、IVE、OBJ

OSG(OpenSceneGraph)是一个高性能的3D图形工具库,主要用于实时渲染、可视化和模拟领域。它支持多种文件格式,但OSG本身也作为一种常用的场景图描述格式被广泛应用。OSG文件通常包含场景图节点的描述,能够表达复杂的场景结构,包括几何体、光照、纹理映射以及视图和渲染设置等。

weixin_29323977的博客 1430

♆1-OSG 概述

OSG组成模块 OpenSceneGraph及其扩展位于系统的API一级,即系统的底层绘图硬件和相应的软件驱动程序之上封装了OpenGL,并对其余的底层图形显示方式予以支持,利用OpenSceneGraph可以轻松地开发其上层的应用程序。 OSG层次结构图如下图所示: OSG主要包括4个库,下面分别进行介绍。 ...

itzyjr的专栏 6141

使用OSG创建逼真的海景体验:小船、月光与动态环境

OSG(OpenSceneGraph)是一个开源的三维图形工具包,广泛应用于虚拟现实、游戏开发、飞行模拟等领域。OSG的出现源于对更高效率和更广泛可接入性的需求。osgOcean是一个用于OpenSceneGraph的高级海洋渲染插件,它能够模拟海洋表面波浪、海流、以及水下效果等,非常适合于制作真实感海景。为了开始使用osgOcean,首先需要将其安装到已经搭建好的OSG环境中。安装过程通常包括以下步骤:下载osgOcean源代码或预编译包。

weixin_28999139的博客 1113
上一篇: osgDB::readNodeFile等函数源码剖析
下一篇: 浅谈在操控器类中,为何要通过osgGA::CameraManipulator的逆矩阵改变视点位置
荆楚闲人
博客等级 码龄20年 3万+粉丝 473原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

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

抵扣说明:

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

余额充值