我的github

《OpenSceneGraph三维渲染引擎设计与实践》的编写目的是:详细剖析OpenSceneGraph引擎的实现流程,包括其场景图形结构,几何体绘制和渲染状态的封装机制,场景漫游、交互和动画的实现方式,以及最为重要的对于三维渲染引擎的内部裁减、数据动态调度和多线程渲染机制的深入分析。《OpenSceneGraph三维渲染引擎设计与实践》对虚拟现实行业的爱好者和从业者、对愿意了解最新图形学相关技术发展,以及有志于开发自主知识产权的三维引擎系统的读者,均会大有助益。

:OpenSceneGraph (OSG)是一个高性能的3D计算机图形学编程接口,应用于模拟、动画和可视化应用中。它是基于OpenGL开发的,所以保证了既跨平台又能有高性能。 但它超越了OpenGL,提供了许多3D应用程序通用的功能,如2D和3D文件加载程序、纹理映射字体支持、LOD、线程数据库分页等。由于其丰富的功能集和自由的开源许可证,OSG已经被学术界和工业界广泛接受。它被全球数千名开发人员用于数百个应用程序。

OSG起源于20世纪90年代,是一个基于Linux的场景图支持库。你今天在OSG内核中看到的大部分内容都是Robert Osfield (英国苏格兰)在2000年左右写的。随着时间的推移,一个庞大的开发社区为OSG贡献了许多功能。如果你是OSG的新手,你可能会被OSG的规模和能力所吓到,但你也会发现许多资源来帮助你学习。

这本书就是这样一种资源。2006年,我撰写并出版了《OpenSceneGraph快速入门指南》,这是OSG的一个简短介绍,后来由王锐翻译成中文,并由钱学雷博士校对和编辑。2009年8月,我有幸在美国举行的SIGGRAPH年度会议上见到了王锐,他在会上介绍了OSG在中国的发展和接受情况,并讨论了他在OSG其他文件方面的进展。作为本书的读者,您将受益于他们多年来在中国使用OSG的研究和经验。[Paul Martz]

前言:本书专为准备开始学习OSG的三维图形学爱好者、计划或已经使用OSG进行程序开发的开发者或者有志于开发自主知识产权的三维谊染引擎的朋友而编写。

开始学习本书前,读者需要具备相当的图形学基础理论和OpenGL程序开发的知识储备,对于 OpenGL开发的基础概念,例如顶点和顶点数组、渲染状态、纹理映射、显示列表、VBO等,均应十分了解并可编写相应的OpenGL程序;同时,本书的读者还应当是名熟练的C++程序开发人员,对 于C++的各种特性,包括公有和私有成员、类的继承与重载、构造与析构、标准模板库STL等,都需要有相当的运用水平。 本书还将介绍多种现代图形学理论的概念和实现方法,包括多线程渲染技术、动态数据调度技术、 纹理烘焙技术、场景裁剪技术、动画技术、模块化的插件设计技术等,对这些方面感兴趣的读者可能会因此受益。

本书的读者还应当具备一定的线性代数基础,对于空间坐标系的概念较为熟悉,了解向量、矩阵、 四元数的基本概念,并可运用数学方法从本质上解决各种坐标空间变换的问题,例如在OpenGL中使用空间矩阵变换向量的方法等。

此外,如果读者对设计模式(Design Patterm)能有较深入的理解的话,对于本书内容以及OSG源 代码的阅读将会大有好处。

第一章 初识OpenSceneGraph(OSG)

1.1 场景图形初步

1.1.1 场景图形的概念

场景图形(Scene Graph)是一种经常用于计算机游戏和图形学相关软件的数据结构设计方法。比较典型的应用了场景图形概念的软件系统包括AutoCAD、Java3D、CorelDRAW以及本书将要详细讲解的OpenSceneGraph等。

但是场景图形的实现并没有一定的规定,它可以用于二维或三维图形场景的逻辑关系和空间表达。最简单的场景图形实现是使用数组或者链表的结构,并按照固定的顺序依次绘制或操作这些节点。当然,有些操作可能会因此变得十分低效,例如判断鼠标是否选中了某个节点,此时应用程序同样不得不按照数组或链表的访问顺序依次对各个节点进行检查。

因此,适用于大规模场景管理的场景图形往往使用图结构(Graph Structure)或树结构(Tree Structure)来组织成一组节点集。目前多数渲染引擎均采用一种自顶向下的、分层的树状数据结构来组织空间数据集,以提升渲染的效率。

在场景树结构中,多个场景图形中的子节点往往只有一个父节点,并且可以继承父节点的多重特性;同样场景图形还提供了遍历所有子节点的访问方式。

1.1.2 具体实现:三维渲染引擎

所谓三维渲染引擎,简单地说,就是为了实现三维场景图形的结构管理和绘制而提供的一系列API的集合。它应当包含至少两个层次——构建层(Construction Layer)和交互层(Interaction Layer),前者提供了在三维空间中设计和完成所需模型的工具集,或者从外部加载复杂模型的数据接口;后者则提供对三维空间及所含模型的装配、渲染、优化和控制功能。

三维渲染引擎可以分为低阶引擎和高阶引擎两种。

(1)低阶引擎

OpenGL。

(2)高阶引擎

以场景图形为基础实现几何图形和动态行为的描述。

1.1.3 主流渲染引擎介绍

经过多年的研究和发展,基于OpenGL或DirectX实现的各种渲染引擎已经逐渐趋于成熟。

(1)PHIGS

(2)Open Inventor

(3)OpenGL Performer

(4)Crystal Space

(5)Java3D

(6)Unreal

(7)OpenSG

(8)OGRE

(9)Irrlicht

(10)Vega Prime

(11)OpenSceneGraph:它以OpenGL为底层平台,使用C++编写而成。它诞生于1998年,系统架构思想起源于OpenGL Performer;发展至今,其功能特性涵盖了大规模场景的分页支持,多线程、多显示的渲染,粒子系统与阴影,各种文件格式的支持,以及对于Java、Perl、Python等语言的封装等。

1.2 OpenSceneGraph概述

1.2.1 诞生与发展

1997年,一个名叫Don Burns的软件工程师受雇于当时的Silicon Graphics(SGI)公司,负责针对滑翔机飞行的虚拟仿真工作进行研究。他使用当时的OpenGL Performer系统,设计了一套广受好评的滑翔仿真软件,并开始尝试在Linux中使用Mesa3D和3dfx Voodoo显示卡设备继续完善自己的仿真软件。

随着开发的深入,这一软件逐步壮大并开始支持OpenGL。与此同时,Don编写了一套简单的、类似于Performer的场景图形系统,命名为SG。SG强调朴素易用,并力求满足人们对场景图形设计的需求。

1998年,Don在一个滑翔爱好者的邮件组中遇到了Robert Osfield。Robert提议将SG作为独立的开源场景图形项目继续开发,并由自己担任项目主导。项目改名为OpenSceneGraph,简称OSG。

2000年,Robert离开了原来的工作单位,转而成为OpenSceneGraph的专业服务商,全职负责开发工作。那段时期,他设计并实现了OSG的许多核心功能,并且是在完全没有客户和薪酬的情况下完成。而Don来到了Keyhole数字地图公司(就是后来的Google Earth部门),并于2001年重新回到OSG的开发工作。

第一届OpenSceneGraph爱好者会议(bird-of-a-feature)于SIGGRAPH 2001世界图形学大会期间举行,当时只有12人参加。与会者中包括了来自Magic Earth的代表,他们与Don和Robert讨论了开发的事宜,并成为OSG的第一个收费用户。

之后,OSG开始以令人瞠目的速度飞快地发展,异常活跃的贡献者们为OSG提交了各种功能代码和插件,使得这个原本简单的渲染引擎逐步变得更加完善和无所不包,而其原有的精悍和结构清晰的特色依然得以保留。

如今,相当一部分高性能的软件已经使用了OSG来完成复杂场景的渲染工作。大部分基于OSG的软件开发更适用于可视化设计和工业仿真,这其中包括了地理信息系统(GIS)、计算机辅助设计(CAD)、建模和数字媒体创作(DCC),以及数据库开发、虚拟现实、动画、游戏和娱乐业等。

1.2.2 优势与不足

OSG引擎由一系列图形学相关的功能模块组成,主要为图形图像应用程序的开发提供场景管理和图形渲染优化的功能。它使用可移植的ANSI C++编写,并使用已成为工业标准的OpenGL底层渲染API。OSG具备跨平台的特性,可以运行在大多数类型的操作系统上,并使用抽象层的概念,使OSG的函数接口可以独立于用户的本地操作系统使用;但是OSG也包含了针对某些平台相关的支持代码。

OSG遵循开源协议发布,OSGPL。

OSG主要具备以下一些优势:

- 快速开发。OSG场景图形内核封装了几乎全部的OpenGL底层接口,并随时支持最新的扩展特性。应用程序的开发者可以将重心放在三维程序开发的实质性内容以及与各种场景对象交互的方法上,而不再过多关注底层的代码。

- 高品质。OSG经历了许多开发人员的反复检查、测试和改善,直接参与OSG核心代码开发并有所贡献的开发人员目前已经接近400人。

- 高性能。OSG的核心代码支持多种场景裁剪技术(Culling)、细节层次节点(LOD)、渲染状态排序(State Sort)、顶点数组、显示列表、VBO、PBO、FBO、OpenGL着色语言等;以及文字显示,阴影系统,雨雪、火焰、烟雾等特效模拟,场景的动态调度,多线程渲染等各种机制。它们共同使得OSG逐渐成为一个高性能的三维图形引擎。

- 高质量代码。要编写高质量的程序,开发者必须了解自己所用的引擎结构。如果引擎不开放源代码,那么与它相关的开发信息就被封闭起来,用户只能借助开发商的文档和客户支持来获得开发信息。开放源代码使得程序员可以检查和调试所用开发包的源代码,充分了解内部信息。

- 可扩展性。基于场景图形的扩展思想,OSG提供了强大的可扩展能力,包括各种类型的扩展节点(NodeKits,节点工具箱)、扩展渲染属性、扩展回调、扩展交互事件处理器等,为用户的程序开发提供了灵活的支持能力。

- 可移植性。跨平台。

- 低费用。开源意味着免费。基于OSG开发也不需要开放自身的源代码。

- 没有知识产权问题。

当然,OSG也存在不足,例如参考文档较少、代码风格不统一、部分功能的实现过于臃肿、无法应用于实践等,这些都有待更多的开发者和贡献者去发现和完善。

1.3 OpenSceneGraph的组成结构

1.3.1 核心结构

- OSG核心库:提供了基本的场景图形和渲染功能,以及3D图形程序所需的某些特定功能实现。OSG的核心库包括:

  >osg库:其中包括构建场景图形的场景图形节点类、用作向量和矩阵运算的类;可绘制体和几何体类;用于描述和管理渲染状态的类;以及图形程序所需的典型功能类,例如命令行参数解析、简单动画路径以及错误和警告输出等。

  >osgDB库:其中包括用于2D和3D文件读写的插件类注册器,以及用于访问和读写这些插件的特定功能类;此外还提供了数据的动态分页调度机制,可以支持大规模数据的动态读入和卸载。

  >osgUtil库:实用工具库,其中包括场景图形数据统计和优化工具、渲染后台工具、场景裁剪工具;以及大量几何操作相关的类,例如德洛内三角化(Delaunay Triangulation)、三角条带化(Triangle Stripification)、法线坐标自动生成、场景树优化等工具。

  >osgGA库:提供了各种视景窗口交互事件的管理工具,用于构建一个与平台无关的人机设备抽象层。

  >osgViewer库:视景器工具库,即单个或多个场景观察和管理的整合工具,以及与平台相关的底层图形设备代码;同时还提供了多线程、多CPU、多显示的场景渲染机制。

- 节点扩展工具箱(NodeKits):扩展了核心OSG场景图形节点类的功能,以提供高级节点类型和渲染特效。节点扩展库包括:

  >osgAnimation:场景动画处理库,包括各种关键帧的定义、插值方式、动画管理和融合、路径动画、角色动画、变形动画、渐进动画等。详见第9章。

  >osgFX:场景特效库,包括多种场景特效的实现,例如各向异性光照、卡通着色、凹凸贴图等。随着OpenGL着色语言的逐步应用,这个库的作用已经被逐渐弱化了。

  >osgManipulator:场景对象操控库,用于实现场景对象的用户交互控制,包括移动、旋转和缩放等,详见第8章。

  >osgParticle:粒子特效库,用于实现简单或复杂的场景粒子效果。

  >osgShadow:阴影特效库。

  >osgSim:仿真工具库。

  >osgTerrain:地形处理库。

  >osgText:文字处理库。

  >osgVolume:体渲染实现库。

  >osgWidget:三维控件库。

  >osgIntrospection:内省功能的实现者。

- OSG文件读写插件:其中包括2D图像、3D模型文件和其它类型文件的读写功能插件,可以任意扩展或删减。详见第10章。

- 内省库:提供了OSG与其它开发环境集成的功能,例如脚本语言Python等。

- 工具程序和示例集:提供了实用的工具和超过100个有关OSG使用和功能实验的例子。

第二章 OSG的安装与调试 

作为一款庞大的开源三维渲染引擎,OSG的安装方法和其他大型开源工程类似,往往需要通过源代码进行编译和生成,其中涉及CMake、编译器的设置、环境变量设置等诸多概念,复杂的步骤往往使初学者望而却步。本章力求帮助读者从原理上理解OSG源代码编译的方法,掌握CMake工具的使用、源代码的更新和Out-of-source编译,建立工程环境并生成一个最简单的案例,以及了解最常用的命令行输入和输出的调试方法。

第三章 开发预备知识 

本章的主要内容将是一些枯燥的空间数学方面的知识,以及它们在三维渲染引擎OSG中的实现;同时本章还将介绍OSG中一个重要的数据结构——数组(Array),以及重要的内存管理机制——智能指针(ref ptr)。虽然这些并不涉及三维场景的管理和渲染工作,但它们却是OSG系统的基础所在,亦即开发者们千里之行的伊始。

感觉这章知识跟之前的那本《3D绘图程序设计》重叠。

3.1 基本数学组件

3.1.1 二维与多维向量

在数学上,将只有大小的量称为标量,将既有方向又有大小的量称为向量。一个n维向量V可以使用n个实数a1,a2,...,an等来表达,即:

V=[a1,a2,...,an]

这种表达方式称做行向量。

向量的主要运算方式包括:

- 向量之间的加减运算。

- 向量与一个系数之间的数乘。

- 向量之间的点积,结果为一个标量。

- 向量之间的叉积,结果为一个垂直于原向量的新向量。

- 向量的规范化,将向量转换为单位向量。

OSG中设计了多种维度的向量实现,包括二维向量、三维向量以及四维向量,分别使用Vec2、Vec3和Vec4来表示;同时OSG还为每一类多维向量规定了多种数据类型,并采用名称之后直接添加类型后缀的方式,定义了一系列可供用户使用的向量类,如表3-1所示。

数据类型                    |  二维向量               |  三维向量                  | 四维向量

Byte(-128~127)          |osg::Vec2b              |osg::Vec3b                |osg::Vec4b

UnsignedByte(0~256)|                                |                                  |osg::Vec4ub

Short(-32768~32767)|osg:Vec2s                |osg::Vec3s                |osg::Vec4s

Float(3.4E±38)          |osg::Vec2f/osg::Vec2|osg::Vec3f/osg::Vec3|osg::Vec4f/osg::Vec4

Double(1.7E±308)     |osg::Vec2d               |osg::Vec3d                 |osg::Vec4d

osg::Vec3f类方法:默认构造函数、设置向量的3个分量的构造函数等。

因此,我们可以使用一系列的方法来实现各种类型的向量运算。例如:

osg::Vec3 v1;
v1.set(1.0,1.0,0.0); //设置向量的值
v1.normalize();//对向量进行归一化处理
float x1 = v1[0]; //获取分量的值
osg::Vec3 v2(2.0,5.0,8.0);//通过构造函数赋值
v2*=0.5;//向量的数乘操作
v2 = osg::Vec3(1.0,0.0,-2.0)-v2;//向量的四则运算
float distance = (v1-v2).length();//求取两向量的距离(和向量的模)
float dotProduct=v1*v2;//向量点乘
osg::Vec3 crossProduct=v1^v2;//向量叉乘

二维和四维向量的设置/获取函数与三维向量类同,它们均具备set()、ptr()、length()、normalize()等成员以及对于各种操作符的重载。二维向量Vec2不具备第三分量;而四维向量Vec4则多了W分量的设置和获取处理,即:

osg::Vec4 vec(1.0,0.0,0.0,1.0);
float w=vec[3];

或者

float w = vec.w();

注意:OSG中的Vec2和Vec4类都没有提供叉乘(operator^()操作符)的方法,因为对于三维空间的线性计算而言,二维/四维向量的叉乘通常并不是必需的。

3.1.2 四元数

在数学中,四元数(Quaternion)的概念最早是由W.R.Hamilton于1843年提出的,它事实上是一种由3个复数和1个实数组成的复杂数字系统。

posted on 2023-03-26 23:22  XiaoNiuFeiTian  阅读(729)  评论(0编辑  收藏  举报