zoukankan      html  css  js  c++  java
  • OSG图形设备接口GraphicsContext

    1、图形设备与相机

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

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

    [html] view plain copy
     
     在CODE上查看代码片派生到我的代码片
    1. osg::ref_ptr<osg::GraphicsContextgc = osg::GraphicsContext::creteGraphicsContext(traits)  

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

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

    [html] view plain copy
     
    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窗口的基本步骤如下。

    [html] view plain copy
     
    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的基本流程如下:

    [html] view plain copy
     
    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种纹理烘焙方式的支持。

  • 相关阅读:
    hdu 5007 水题 (2014西安网赛A题)
    hdu 1698 线段树(成段替换 区间求和)
    poj 3468 线段树 成段增减 区间求和
    hdu 2795 公告板 (单点最值)
    UVaLive 6833 Miscalculation (表达式计算)
    UVaLive 6832 Bit String Reordering (模拟)
    CodeForces 124C Prime Permutation (数论+贪心)
    SPOJ BALNUM (数位DP)
    CodeForces 628D Magic Numbers (数位DP)
    POJ 3252 Round Numbers (数位DP)
  • 原文地址:https://www.cnblogs.com/yanhuiw/p/6588786.html
Copyright © 2011-2022 走看看