1、图形设备与相机

在Camera类的成员函数中,setGraphicContext()函数的工作是设置相机对应的图形设备对象,换句话说,下面要介绍的GraphicsContext类就是图形设备对象的载体。用一句话来描述的话,GraphicsContext是任意图形子系统的抽象层接口,它提供了统一的图形设备操作函数,用来实现渲染结果和底层设备的交互;同时它还具有平台无关性,因而将OSG的渲染过程与操作系统平台剥离开来,使两者相互独立。用户即可以将渲染的内容传递给Windows或者X11的窗口与像素缓存对象,也可以自定义一个支持OpenGL的图形设备,并将结果反映在其上。

图形设备对象的主要工作是提供场景渲染结果的载体,这个载体可以显示缓存,进而绘制到一个图像窗口中,也可以是其他特殊的缓存对象,从而实现复杂的渲染和图像多次曝光等功能,创建一个图像设备不能简单地使用new运算符,因为GraphicContext类是一个不能被实例化的抽象类(这个体现在valid()等一大批纯虚函数上);通常应当使用createContext()静态函数,自动根据当前的用户环境和特性参数traits,构建一个平台相关的图形设备对象。

  1. osg::ref_ptr<osg::GraphicsContext> gc = osg::GraphicsContext::creteGraphicsContext(traits)

2、窗口与像素缓存(Pixel Buffer)

      Windows下的每一个窗口都附带了一个设备环境(Device Context,DC)。当需要在窗口中直接进行二维图像绘制时,可以使用Windows图形设备接口函数(GDI)来完成操作。如果希望在某个Windows的窗口中实现三维场景的渲染,则需要将一个OpenGL渲染环境(Rendering Context, RC)的标识与此窗口的设备环境相关联;如果当前的OpenGL指令都要输出到某一个窗口,还应当指定该窗口的渲染环境为“当前渲染环境”。假设已知窗口句柄为hwnd,那么一个简单的渲染窗口的实现过程如下。

  1. HDC hdc = GetDC(hwnd);
  2. HGLRC hrc = wglCreateContext(hdc);
  3. ----
  4. wglMakeCurrent(hdc, hrc);

对于一个OpenGL而言,参与三维绘制的窗口可以有多个,但是一个渲染环境只能与一个窗口的设备环境相关联;并且任意时刻都只能有一个渲染环境被指定为当前环境。

而对于OSG来说,有关窗口及其渲染环境的操作都是由GraphicsContext的派生类osgViewer::GraphicsWindow来完成的。有关这个类及其“平台相关”子类的具体实现,参见后文“人机交互与图形设备接口”的内容。

像素缓存(Pixel Buffer, PBuffer)是一种较新的OpenGL扩展功能,用于实现离屏渲染(Off-screen Rendering)以及渲染到纹理(又称纹理烘焙,Render to Texture)。简单地说, PBuffer机制将本来渲染到显示缓存的场景数据换向输出到一处用户缓存中,进而可以将渲染数据绑定到纹理图片,甚至直接取出进行处理。将场景渲染的数据绑定到一张纹理图片的动作称为“纹理烘焙”;而使用着色器进行逐顶点或逐像素的数学运算,通过glReadPixels()等函数将渲染到纹理的结果重新取出,并加以储存和重新运用的过程,则属于通用GPU计算(General-purpose Computing on Graphics Process Units, GPGPU)的范畴。

OpenGL的像素缓存可以理解成一个建立在已有窗口上的一个虚拟窗口设备,它同样需要创建一个“窗口”句柄,为这个句柄分配设备环境,并且为设备环境关联渲染环境。由此得到的PBuffer设备可以像普通窗口一样被操作,但是它还允许将这个“窗口”绑定到指定的纹理对象,从而将渲染到该“窗口”的场景内容烘焙到纹理上。假设已知一个实际窗口的设备环境hdc,在其基础上构建一个PBuffer窗口的基本步骤如下。

  1. HWND pbufferHwnd = reinterpret_cast<HWND>(wglCreatePbufferARB(hdc, ---));
  2. HDC pbufferHdc = wglGetPbufferDCARB(reinterpret_cast<HRBUFFERARB>(pbufferHwnd));
  3. HGLRC pbufferHrc = wglCreateContext(pbufferHdc);
  4. ----
  5. wglMakeCurrent(pbufferHdc, pbufferHrc);
  6. ----
  7. glBindTexture(----);
  8. wglBindTexImageARB(reinterpret_cast<HPBUFFERARB>(phbufferHwnd), ---);

OSG中完整地封装了像素缓存的实现机制。正是由于pBuffer设备和窗口的类似之处,各个平台上的pBuffer类的实现同样都是由GraphicContext的派生类来完成的,包括核心库osgViewer下的PixelBufferWin32(Windows平台下的实现)、PixelBufferX11(Linux X11下的实现)和PixelBufferCarbon(Mac OS X下的实现)类。当将前文中提及的Traits::pbuffer参数设置为真时,系统就会根据当前系统平台的类别加载相应的PBuffer设备。当然直接使用createGraphicsContext()函数启动一个PBuffer也许没有太大的意义,更多的是在执行渲染到纹理功能时创建一个与之绑定的PBuffer设备。具体参看下一节的内容。

3、渲染到纹理(Rende to Texture)

上一节已经提到过,渲染到纹理(纹理烘焙)这一功能有两个主要作用——是实现场景离屏渲染之后的“后置处理”(Post-processing);二是实现多种不同场景的融合显示。

一个典型的例子如下所述:在一个房间中放置一台播放着精彩节目的电视,房间是主场景;而电视节目则属于另一个场景,它作为纹理被显示在电视屏幕的模型之上,因而成为了主场景的组成部分。重要的是,节目的播放、节目频道的替换,以及节目信号是否突然中断等,这些复杂的变故与主场景并没有直接关系,对于整个房间而言,那只是一幅不断更新着的纹理图片而已。

上一节介绍了像素缓存(PBuffer)这一常用的OpenGL机制,然而实现纹理烘焙的手段并不只有像素缓存一种而已。常用的渲染到纹理的手段包括直接复制帧缓存(Frame buffer)中的像素、使用像素缓存设备、以及使用使用帧缓存对象(Frame Buffer Object, FBO)3种。

  直接复制帧缓存(Frame buffer)中的像素: OpenGL中提供了多种从当前帧的缓存数据中生成二维纹理的方法。效率较低的例如使用glReadPixels()提取像素再传递给glTexImage2D();而效率较高的则使用glCopyTexImage2D()或者glCopyTexSubImage()函数,直接将显示缓存中的数据保存为纹理图片。但是无论怎样,这都是一种间接地“渲染到纹理”的方案,因而其中总是免不了一个“将数据复制到纹理”的步骤。

使用像素缓存设备 : 由此产生的一个优化方案就是使用像素缓存设备。正如之前介绍的那样,它省却了复制的过程,而是直接将子场景渲染到与之绑定的纹理中。因此PBuffer虽然可能在一些老式和低端的显卡上无法得到全面的支持,但依然足以取代直接复制帧缓存的做法,从而进一步提升了纹理烘焙的效率。

帧缓存对象: 然而PBuffer还是有一些无法令人忽视的问题,例如每一个PBuffer设备都必须建立一个自己的渲染环境(RC);它们各自有自己的像素格式、深度和模板缓存;对多个PBuffer进行切换和管理都十分困难。因此,一个新的解决方案诞生了,那就是帧缓存对象(Frame Buffer Object, FBO)扩展。

帧缓存的意义在于,它是一段2D数据的存储空间,保存了OpenGL渲染管线最终得到的像素数据。帧缓存的数据直接输出到窗口系统,即作为显示缓存使用,这种默认的缓存对象又称为“窗口系统支持”(Window-system-provided)的帧缓存。

如果将帧缓存的信息换向输出到一个虚拟窗口设备,并进而绑定到纹理对象,那么这就是之前所说的PBuffer的概念。如果另外定义一种不参与显示的,由“应用程序创建”(Application-created)的帧缓存,则称为帧缓存对象(FBO)。当FBO与一个纹理对象绑定时,它实现的即是“渲染到纹理”的操作;如果它与一处内存空间绑定,那么所执行的操作称为“离屏渲染”,我们可以随后取出该空间的内容,将其保存到图片或执行其他的后置处理。

FBO支持多达16个绑定通道,可以绑定渲染结果的多个颜色缓存值、深度缓存值以及模板缓存值到纹理或者自定义空间之上。FBO易于管理,多个FBO对象之间的切换也十分迅速,并且它还具有平台无关的特性(要知道PBuffer是平台相关的)。

OpenGL中定义和绑定FBO的基本流程如下:

  1. /* 创建FBO对象那个*/
  2. GLuint fboID;
  3. glGenFramebuffersEXT(1, &fboID);
  4. glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, fboID);
  5. /*绑定FBO与一个二维纹理对象textureID*/
  6. glFramebufferTexture3DEXT(GL_FRAMEBUFFER_EXT,
  7. GL_COLOR_ATTACHMENT0_EXT,
  8. GL_TEXTURE_2D, textureId, 0);
  9. /*渲染子场景到纹理*/
  10. glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, fboId);
  11. drawSubScene();
  12. glBindFrameBufferEXT(GL_FRAMEBUFFER_EXT, 0);

而OSG中则直接使用Camera类实现了对于FBO、PBuffer和读取帧缓存3种纹理烘焙方式的支持。

OSG图形设备接口GraphicsContext的更多相关文章

  1. 图形设备接口(GDI)

    图形设备接口(GDI,Graphics Device Interface)负责在显示器和打印机上显示图形.GDI 是由几百个函数和一些相关的数据类型.宏和结构构成的.Windows 98/NT 中的图 ...

  2. 第四章 Windows的图形设备接口及Windows绘图 P83 4-6

    实验(实习)名称  图形程序设计及其应用  实验(实习)日期 一.实验目的 1.熟悉图形设备接口的概念及其应用. 二.实验内容及步骤  实验任务 1.熟悉基于图形应用的程序设计: 2.掌握刷新技术及其 ...

  3. C++ GDI图形设备接口

    一.概念 1. GDI:(Graphics Device Interfase)图形设备接口,是一个应用程序与输出设备之间的中介. 一方面,GDI向应用程序提供一个与设备无关的编程环境,另一方面,它又以 ...

  4. Windows的图形设备接口与Windows绘图

    本次学习目标 理解DC, 映像模式, 坐标系统, 窗口和视口; 学习获取绘图工具(画笔/画刷)的句柄, 设置颜色, 能定义映像模式; 会使用常用的绘图函数. 编写程序: 在屏幕上出现一个圆心沿正弦曲线 ...

  5. 探索未知种族之osg类生物---渲染遍历之器官协作

    好了,现在我们经过三节的介绍我们已经大体上明确了单线程模型(SingleThreaded)下 OSG 渲染遍历的工作流程.事实上无论是场景的筛选render还是绘制cull工作,最后都要归结到场景视图 ...

  6. [OSG]OSG例子程序简介

    1.example_osganimate一)演示了路径动画的使用(AnimationPath.AnimationPathCallback),路径动画回调可以作用在Camera.CameraView.M ...

  7. OSG中的示例程序简介

    OSG中的示例程序简介 转自:http://www.cnblogs.com/indif/archive/2011/05/13/2045136.html 1.example_osganimate一)演示 ...

  8. OSG中的示例程序简介(转)

    OSG中的示例程序简介 1.example_osganimate一)演示了路径动画的使用 (AnimationPath.AnimationPathCallback),路径动画回调可以作用在Camera ...

  9. [原][OSG]OSG例子程序简介

    1.example_osganimate一)演示了路径动画的使用(AnimationPath.AnimationPathCallback),路径动画回调可以作用在Camera.CameraView.M ...

随机推荐

  1. python稀疏矩阵得到每列最大k项的值,对list内为类对象的排序(scipy.sparse.csr.csr_matrix)

    print(train_set.tdm) print(type(train_set.tdm)) 输出得到: (0, 3200) 0.264940780338 (0, 1682) 0.356545827 ...

  2. linux文件权限,用户和组

    文件权限 默认权限分配 umask umask是通过八进制的数值来定义用户创建文件或目录的默认权限的 安全权限的临界点是,文件默认权限是644,目录默认权限是755 [root@Poppy joker ...

  3. SHUTDOWN: waiting for active calls to complete

    Problem Description: ====================  You are attempting to shut down the database and the data ...

  4. IBM AIX创建lv

    #lsvg 查看当前有哪些vgrootvgvgdb02vgdb01datavg#lslv maindb_index 查看maindb_index这个lv 位于哪个vg上,新的lv也要与之相同.LOGI ...

  5. Linux基础综合练习

    Linux基本操作综合练习 1.建立用户zhangsan,密码使用明文123456: 命令:useradd -p 123456 zhangsan 解释: 参数 -p 添加明文密码 useradd添加用 ...

  6. 深入浅出 Java Concurrency (10): 锁机制 part 5 闭锁 (CountDownLatch)

    此小节介绍几个与锁有关的有用工具. 闭锁(Latch) 闭锁(Latch):一种同步方法,可以延迟线程的进度直到线程到达某个终点状态.通俗的讲就是,一个闭锁相当于一扇大门,在大门打开之前所有线程都被阻 ...

  7. oracle、sqlserver、mysql常用函数对比[to_char、to_number、to_date]

    Oracle                                       -->                             MySQL to_char(sysdat ...

  8. SQL中Like语句的语法

    在SQL结构化查询语言中,LIKE语句有着至关重要的作用. LIKE语句的语法格式是:select * from 表名 where 字段名 like 对应值(子串),它主要是针对字符型字段的,它的作用 ...

  9. LUA使用虚函数与使用回调函数

    ------------------虚函数overload-------------------------- --回调:寻路中格子坐标改变 CHero.OnSearchToCellsChange = ...

  10. ASP .NET core 入门基础内容备份

    model 里边设置主键 : [key]可以自定义主键 默认是名称为ID类型为int的字段 设置显示格式: [DisplayFormat(DataFormatString="{0:显示的格式 ...