开始研究OpenSceneGraph(OSG)

本文介绍了OpenSceneGraph(OSG),一个基于OpenGL技术的三维图形应用程序接口(API)。OSG支持多种平台,采用开源模式,强调适应性和高效性。文章还探讨了OSG的多线程、多显示设计以及其实现原理。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

本文翻译自Don Burns和Robert Osfield(缺席)在Image 2003会议上的演讲幻灯片。
原文下载地址:http://www.openscenegraph.com/osgwiki/pmwiki.php/ProgrammingGuides/ProgrammingGuides

--------------------------------------------------------------------------------------

1、什么是Open Scene Graph?
OpenSceneGraph使用OpenGL技术开发,是一套基于C++平台的应用程序接口(API)。OpenGL技术为图形元素(多边形、线、点……)和状态(光照、材质、阴影……)的编程提供了标准化的接口。而OSG开发的主要意义在于,将3D场景定义为空间中一系列连续的对象,以进行三维世界的管理。

正是由于场景及其参数定义的特点,通过状态转化、绘图管道和自定制等操作,OSG还可以用于优化渲染性能。
可以运行OSG的平台,需要具备OpenGL的支持能力,以及C++的编译环境,支持OSG的系统包括Solaris,IRIX,Windows,Mac OSX,HP-UX,Sony Platystation等等,不过XBox除外。和OpenGL类似,OSG的核心并没有提供窗口系统的功能。因此用户可以自由选择所需的图形开发接口,如GLUT,X11/Motif,Win32,MacOS X,Qt,wxWindows,Fox等。

OSG是一个开源系统。自Robert Osfield主持这个项目以来,OSG就作为一个开放源代码的图形开发工程开始在全球运作了。
OSG包括一系列的标准库。其核心是OSG本身。下图中的树状结构包括了场景管理的各个功能节点(node)。
节点可以用于绘图,或者设置几何体和渲染属性。例如,有的节点可以用于管理细节层次,场景转换,或者一个区域内几何体的拣选。
OSGUtil提供了场景操作的工具。如场景的精简(cull)和绘制,优化渲染,提供快捷方式等。
OSGDB提供了文件管理和插件管理的功能。所有的文件和图片都使用插件进行读取,以下是目前支持的文件格式列表:
3dc、3ds、ac3、dw、flt、Freetype、iv、ive、logo、lwo、md2、obj、osg、osgtgz、tgz、txp、directX、zip等文件格式;bmp、dds、pic、png、pnm、qt、rgb、tga等图像格式。
osg是OSG自身的格式,使用ASCII编码,便于阅读和编辑。
这些格式的文件都可以通过已有的插件读取,这其中也包括久负盛名的OpenFLT,Inventor,TXP(包括多重和异步的页),最近还增加了ive格式(osg格式的二进制版本)。
此外,OSG还提供了提供特殊功能和组件的一系列节点,如文本的字体和风格化显示,OSGSim用于模拟特定对象(天空,光,天候),以及粒子特效的显示。
用户可以自由地使用以上的库,也可以自定义新的库。


2、为什么开源?
之前已经提到过,OSG是一个完全开源的项目。而开源项目经常被认为是低质量的,“所予即所得”的,不适合产品化的。事实上,对于OSG这种还未产品化的开发层软件(middleware)而言,开源是一个极好的战略选择,当然这并不是对所有软件而言。
考虑软件开发的流程:首先是一个概念性的想法或者一个用户需求,软件工程师随后提出设计和实现的方案,最后将方案转化为代码。
不幸的是,大部分商业软件将代码的部分作为“家传之宝”,深藏起来,生怕这些看起来汇集了智慧结晶的资料外泄。。
然而,软件真正的价值是在开发流程的第二步,而且这一步完全可以被重新演绎成别的代码。我们经常见到大型企业之间为了代码之争将对方告上法庭的例子,但是这显得毫无用处。
在软件的“食物链”当中,处于最底层的是系统开发者,他们针对硬件编写接口和驱动程序;其上一层是开发层软件的编写者,他们提供抽象层,并整合硬件接口(声音、图像、网络等),以方便应用软件的开发者使用。应用层软件的开发者比较特殊,他们不仅要理解开发平台的特性,还要十分理解应用程序的工作配置和上级用户的需求。

最上一层是应用软件的用户,和开发者不同,他们将计算机作为一种工具,他们不关心软件的技术细节,只要软件易用而且有用,他们就愿意为之付款。这些人包括办公室的白领,培训学员,老师,飞行员,等等。
在开发者的层级,事实上也有一条分界线存在。在这个层级中,最下面的两层(系统开发者和开发层软件开发者)是由硬件厂商支持的。而开发层软件开发者和应用软件开发者之间,却存在了明显的差别。
以上的场景存在了两条主要问题:一、应用程序开发者要依赖于开发层软件开发者和系统开发者,这决定了产品的质量;二、开发层软件开发者要开发出令人满意的产品,就必须与应用程序开发者分享设计的方案。而软件的真正价值也就在这里。
OSG开源后带来的益处主要有:
(1)自由分享智慧:OSG有OSGPL的授权(派生自LGPL,但有所修改以适应商业软件的需求),这个授权将开发者从源代码保密的桎枯中解放出来,带来了诸多的便利。
(2)没有商业规范的限制:商业软件的编写要时常发布日程表、新特性和新版本,以实现市场战略的需要。开源软件纯粹从技术的角度出发,开发者可以集中精力解决技术上的难题。
(3)带给应用软件开发者的便利:不用购买;可参与开发;彻底进行调试;错误的反馈和解决。
(4)带给开发软件开发者的便利:高效的软件开发;用户参与;直接反馈;思想的共享。
(5)提升软件质量:不会总是忍受重复的错误。


开源的产品并不等价于成功的产品。网络上存在着许多开源软件(可以浏览一下Source Forge),它们之间一直在进行着“适者生存”的战争。
一个优秀的软件,无论它开源与否,都必须物有所值,即,必须为最终用户提供唯一的解决方案;它必须稳定,没有哪个应用程序开发者愿意在有问题的软件基础上进行编程;它必须有良好的设计,必须提供一种适合用户的开发方法,而不是对开发者和用户加以限制。它必须有很好的交流渠道,经常性地为用户的问题提供回答,解决疑难,而且要做到谦恭有礼。


3、设计思想
(1)适应性开发:早期的开发往往做出各种例行的限制,而OSG有意去适应用户。
(2)主要特性:可移植性;可扩展性(Design Patterns,STL……);多显示、多线程环境;宽松的模块关系足以适应OpenGL技术的发展和各个方面(例如CG Shading语言);可以在最少的重绘时间里提供最好的显示性能;提供简单的实时配置和各种特效(蜡板效果,阴影、基于图片的渲染、扭曲校正等)。
大部分的交流都在OSG的邮件组中进行。我们每天都会抽出数个小时的时间回答问题,和OSG的用户进行各种交流。我们在OSG的主页上通过在线的参考指南向用户提供各种信息,其中也包括大量的示例。我们还负责维护一个主机,用于收集邮件组的问答资料,用户提供的的示例代码,以及一些软件的部分程序段。


4、多线程、多显示(Multi-threaded, Multi-display)
单线程低负荷的设计特性允许我们的程序“朴实无华”,即,我们不必关注不必要的损耗。可升级性也是呈线性的,系统负荷不会随着进程单元的增加而增加。
我们不需要在运行时实现数据保护,而是在编译时进行这项工作。我们使用C++常量来保证源代码中的数据只读,编译器会要求我们按照规定的方式写入数据,从而避免覆盖危险的数据。因此,在运行时,我们不需要再建立额外的进程来保护多进程共享的数据。

当然危险依然存在。在任何多进程程序运行时,都需要遵守一定的规则。其中最重要的是,程序只有在更新段(UpdatePhase)的时候才可以传递数据。如下所示:
如上的程序拥有传统的多线程、多显示和多缓冲特性。每个相(Phase)都有自己的CPU时间,使得程序保持高度的并行化。在1990年时,这显然是一个优秀的设计,但是在2003年就不尽然了。处理器的速度比起过去已经快了60倍。
现在,我们如果要描述每个相的处理时间,那么大致如下图所示。更新时间(Update)不到一毫秒,标准数据库的拣选时间(Cull)约2~3毫秒,绘图时间(Draw)则没有变化,除非我们有意在绘图时为程序添加更多的工作。
可以明显看出,CPU资源的使用少得可怜,更多的时间它处于空闲状态。
Producer是OSG的姊妹产品,它为OSG良好地实现了多线程、多显示的环境。其基本概念是运用抽象的“摄相机”(Camera)。Producer中的每一个摄相机都是一个对象,也是一个进程单元,可以自行、与其他摄相机异步地并行工作。
Producer/OSG的多显示运用,其原理如下图所示:

绘图(Draw)事实上是两个并行的进程。在现代的图形设备上,一般至少有两个处理器在进行工作。CPU并不负责图形的渲染,而是执行OpenGL的指令,也就是“分发”(Dispatch)。图形处理器(也就是GPU)负责执行CPU分发的OpenGL指令,并异步进行执行。

这样的硬件结构有几个特点:一、分发进程仅仅由CPU和GPU之间管道(FIFO)的传输速率决定;二、使用大容量的管道,可以使分发的时间远远少于和快于GPU绘图的时间。
基于以上的信息,Producer/OSG使用了称为“移相”(phase shifted)的技术:
在进行移相时,我们使用了两种周期进行计算。其中一种是由图形设备的帧扫描(vertical retrace)得来的,它用于图形硬件设备的绘图工作。
在CPU一端,我们使用的时间周期与图形设备帧同步(vertical sync)的周期相同,但是通过移相使得更新(update)、拣选(cull)和分发(dispatch)过程与绘图(draw)过程交迭。在理想情况下,我们可以在一次分发结束后立即开始下一次的更新。更新/拣选/分发的过程连续地运行,简化了多线程的模型,也提高了资源的使用效率。


--------------------------------------------------------------------------------------
关于作者:
Don Burns,OSG的创始者,1996年,他在Performer的基础上建立了这个PC平台上的视觉模拟工程,自2001年开始全职承担OSG及其相关工程的开发工作。
Robert Osfield,自1999年开始担任项目负责人,并将其作为开源项目发布,自2000年开始全职承担OSG的开发工作。

关于Image:
Image大会(The IMAGE Conference)开始于1977年,是目前世界上首屈一指的视觉仿真技术会议。它是由IMAGE Society发起,旨在探讨视觉仿真技术的发展和应用的会议。每次会议的内容主要由致辞、论文讲演、展览和技术教学组成。
<think>我们正在讨论OpenSceneGraphosg::Image类的setData方法的使用。根据用户要求,我们需要提供一个使用示例,并解释其工作原理。osg::Image类用于存储图像数据(像素数据)。setData方法允许设置图像的数据指针,并指定内存管理策略(是否由Image对象负责删除内存)。方法签名:void setData(unsignedchar*data,AllocationModemode =USE_NEW_DELETE)参数:- data:指向图像数据的指针- mode:内存分配模式,决定当Image对象被销毁时如何处理数据指针。可选值:* NO_DELETE:不删除数据(由用户管理)*USE_NEW_DELETE:使用delete[]删除(默认)* USE_MALLOC_FREE:使用free()删除注意:如果使用USE_NEW_DELETE,则数据必须是用new unsignedchar[]分配的;如果使用USE_MALLOC_FREE,则数据必须是用malloc分配的。 示例步骤: 1.创建osg::Image对象。2.分配图像数据内存(根据所选模式使用new或malloc)。 3.填充图像数据(例如,生成一个简单的渐变图像)。4.设置图像的尺寸、像素格式等属性。 5.使用setData方法设置数据指针和内存管理策略。 6.使用图像(例如,作为纹理)。下面是一个创建2x2像素的RGBA图像的示例代码:</think>### OpenSceneGraph中`osg::Image::setData()`方法详解 `osg::Image`类管理图像数据,`setData()`方法用于直接设置原始像素数据指针,并指定内存管理策略。其核心功能是**接管或引用外部分配的像素内存**。 #### 方法签名 ```cpp void setData( unsigned char* data, AllocationMode allocationMode = USE_NEW_DELETE ) ``` - **`data`**:指向像素数据的指针(需与图像格式匹配) - **`allocationMode`**:内存管理策略(默认`USE_NEW_DELETE`) - `NO_DELETE`:OSG不管理内存,用户需自行释放 - `USE_NEW_DELETE`:OSG用`delete[]`释放内存(默认) - `USE_MALLOC_FREE`:OSG用`free()`释放内存 --- ### 使用示例 #### 场景:动态创建 256x256 的RGBA纹理 ```cpp #include <osg/Image> // 1. 创建Image对象 osg::ref_ptr<osg::Image> image = new osg::Image(); // 2. 分配像素内存 (RGBA格式: 每像素4字节) const int width = 256; const int height = 256; unsigned char* pixelData = new unsigned char[width * height * 4]; // 动态分配 // 3. 填充绿色渐变数据 for (int y = 0; y < height; ++y) { for (int x = 0; x < width; ++x) { int offset = (y * width + x) * 4; pixelData[offset + 0] = 0; // R pixelData[offset + 1] = y; // G (渐变) pixelData[offset + 2] = 0; // B pixelData[offset + 3] = 255; // A } } // 4. 设置图像属性 image->setImage( width, height, 1, // 宽、高、深度(2D图像为1) GL_RGBA, GL_UNSIGNED_BYTE, // 像素格式/类型 pixelData, // 数据指针 osg::Image::USE_NEW_DELETE // 内存策略 ); // 5. 后续使用(如绑定纹理) osg::ref_ptr<osg::Texture2D> texture = new osg::Texture2D; texture->setImage(image); ``` #### 关键说明: 1. **内存所有权** - 使用`USE_NEW_DELETE`时,`osg::Image`在析构时自动调用`delete[] pixelData` - 若需外部管理内存,用`NO_DELETE`(需确保数据生命周期覆盖OSG使用) 2. **格式一致性** 像素数据必须与`setImage()`中指定的格式(`GL_RGBA`)和类型(`GL_UNSIGNED_BYTE`)严格匹配。 3. **高效更新** 动态修改`pixelData`后调用`dirty()`通知OSG刷新: ```cpp pixelData[0] = 255; // 修改数据 image->dirty(); // 标记数据更新 ``` --- ### 典型应用场景 1. **动态生成纹理** 实时生成噪声图、程序化纹理等[^1]。 2. **视频流渲染** 将解码后的视频帧数据通过`setData()`注入OSG[^2]。 3. **科学可视化** 将计算数据(如热力图)映射为像素数据。 4. **内存复用** 用`NO_DELETE`复用外部内存池,避免重复拷贝。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值