一、图形设备与相机html
在Camera类的成员函数中,setGraphicContext()函数的工做是设置相机对应的图形设备对象,换句话说,下面要介绍的GraphicsContext类就是图形设备对象的载体。用一句话来描述的话,GraphicsContext是任意图形子系统的抽象层接口,它提供了统一的图形设备操做函数,用来实现渲染结果和底层设备的交互;同时它还具备平台无关性,于是将OSG的渲染过程与操做系统平台剥离开来,使二者相互独立。用户便可以将渲染的内容传递给Windows或者X11的窗口与像素缓存对象,也能够自定义一个支持OpenGL的图形设备,并将结果反映在其上。linux
图形设备对象的主要工做是提供场景渲染结果的载体,这个载体能够显示缓存,进而绘制到一个图像窗口中,也能够是其余特殊的缓存对象,从而实现复杂的渲染和图像屡次曝光等功能,建立一个图像设备不能简单地使用new运算符,由于GraphicContext类是一个不能被实例化的抽象类(这个体如今valid()等一大批纯虚函数上);一般应当使用createContext()静态函数,自动根据当前的用户环境和特性参数traits,构建一个平台相关的图形设备对象。 缓存
二、窗口与像素缓存(Pixel Buffer)ide
Windows下的每个窗口都附带了一个设备环境(Device Context,DC)。当须要在窗口中直接进行二维图像绘制时,可使用Windows图形设备接口函数(GDI)来完成操做。若是但愿在某个Windows的窗口中实现三维场景的渲染,则须要将一个OpenGL渲染环境(Rendering Context, RC)的标识与此窗口的设备环境相关联;若是当前的OpenGL指令都要输出到某一个窗口,还应当指定该窗口的渲染环境为“当前渲染环境”。假设已知窗口句柄为hwnd,那么一个简单的渲染窗口的实现过程以下。函数
对于一个OpenGL而言,参与三维绘制的窗口能够有多个,可是一个渲染环境只能与一个窗口的设备环境相关联;而且任意时刻都只能有一个渲染环境被指定为当前环境。优化
而对于OSG来讲,有关窗口及其渲染环境的操做都是由GraphicsContext的派生类osgViewer::GraphicsWindow来完成的。有关这个类及其“平台相关”子类的具体实现,参见后文“人机交互与图形设备接口”的内容。ui
像素缓存(Pixel Buffer, PBuffer)是一种较新的OpenGL扩展功能,用于实现离屏渲染(Off-screen Rendering)以及渲染到纹理(又称纹理烘焙,Render to Texture)。简单地说, PBuffer机制将原本渲染到显示缓存的场景数据换向输出到一处用户缓存中,进而能够将渲染数据绑定到纹理图片,甚至直接取出进行处理。将场景渲染的数据绑定到一张纹理图片的动做称为“纹理烘焙”;而使用着色器进行逐顶点或逐像素的数学运算,经过glReadPixels()等函数将渲染到纹理的结果从新取出,并加以储存和从新运用的过程,则属于通用GPU计算(General-purpose Computing on Graphics Process Units, GPGPU)的范畴。spa
OpenGL的像素缓存能够理解成一个创建在已有窗口上的一个虚拟窗口设备,它一样须要建立一个“窗口”句柄,为这个句柄分配设备环境,而且为设备环境关联渲染环境。由此获得的PBuffer设备能够像普通窗口同样被操做,可是它还容许将这个“窗口”绑定到指定的纹理对象,从而将渲染到该“窗口”的场景内容烘焙到纹理上。假设已知一个实际窗口的设备环境hdc,在其基础上构建一个PBuffer窗口的基本步骤以下。操作系统
OSG中完整地封装了像素缓存的实现机制。正是因为pBuffer设备和窗口的相似之处,各个平台上的pBuffer类的实现一样都是由GraphicContext的派生类来完成的,包括核心库osgViewer下的PixelBufferWin32(Windows平台下的实现)、PixelBufferX11(Linux X11下的实现)和PixelBufferCarbon(Mac OS X下的实现)类。当将前文中说起的Traits::pbuffer参数设置为真时,系统就会根据当前系统平台的类别加载相应的PBuffer设备。固然直接使用createGraphicsContext()函数启动一个PBuffer也许没有太大的意义,更多的是在执行渲染到纹理功能时建立一个与之绑定的PBuffer设备。具体参看下一节的内容。.net
三、渲染到纹理(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的基本流程以下:
而OSG中则直接使用Camera类实现了对于FBO、PBuffer和读取帧缓存3种纹理烘焙方式的支持。