OpenGL Pixel Buffer

一般电脑绘图的流程大致是这样:算出投影矩阵、产生模型的几何资料、设定贴图、打上光源、最后由硬体产生一张2D平面的影像。 而这个2D的影像会放在一块记忆体中,称之为Frame buffer。

  Frame Buffer 是一块直接对应萤幕的记忆体,所以通常是放在显示卡里。 为了让连续画面显示流畅,我们都会将Frame Buffer设为前景跟背景两个。 先对背景Frame buffer进行绘图,等确定画完整个场景后,再将前景跟背景进行对调(Swap)。 如此就可把刚才画完的场景显示在萤幕上,而我们可以继续在背景Frame buffer画下一个场景。

  问题来了,我们能不能​​把Frame buffer读出来? 因为我们可能会将还没送出萤幕的影像做一些加工处理。 比如将场景影像当成贴图贴在某个模型,像镜子这样的效果。
  早期OpenGL只有提供glReadPixels()这样的函式可以读出Frame buffer的资料,但是这会将资料读在主记忆体中,而我们又要当成贴图放在显示记忆体中,这样一来一往就浪费了不少时间。 后来改用glCopyTexImage(), glCopyTexSubImage()直接在显示记忆体中存取后,速度上就改善了许多。 但仍然有使用上的不便性,因为就只是对一块背景Frame buffer进行存取,换另一张贴图则整个Frame buffer就必须重画。

  直到2002年OpenGL 提供了一套解决方法,称为PBuffer( Pixel Buffer)。 这是让使用者自行建立一块颣似Frame Buffer的记忆体,差别是PBuffer是不能直接显示在萤幕上的。 我们可以先对PBuffer进行绘图,然后再将PBuffer当成贴图来用。 这个功能一般的显示卡都有支援,它是建立在wgl extension中,所以我们在程式开头要先含入wglext.h档。 要知道您的显示卡是否支援PBuffer,可以用这个方法来确认:

#include <gl/wglext.h>

 

/* 在此之前要先设定好OpenGL的基本环境*/
wglGetExtensionsStringARB = (PFNWGLGETEXTENSIONSSTRINGARBPROC)wglGetProcAddress("wglGetExtensionsStringARB");
char *ext = NULL; 
if( wglGetExtensionsStringARB ){
    ext = (char*)wglGetExtensionsStringARB( wglGetCurrentDC() );
    if( strstr( ext, "WGL_ARB_pbuffer" ) == NULL ){
    // 不支援PBuffer!
    }
}

  接下来要介绍如何使用PBuffer。 整个使用流程大致是这样:设定好OpenGL的基本环境、建立PBuffer、启动PBuffer、对PBuffer绘图、将PBuffer当成贴图、启动原来的Frame Buffer、对Frame Buffer画图、解除贴图的连结、删除PBuffer。

1. 设定OpenGL的基本环境:请参考我之前的文章-- "在VC++ .NET framework 使用OpenGL",这边不多介绍。 这个步骤主要是取得HDC及HGLRC。

2. 建立PBuffer:

    a. 取得WGL extension 的函式位置,我们会需要这些函式:wglMakeContextCurrentARB , wglChoosePixelFormatARB , wglCreatePbufferARB , wglDestroyPbufferARB , wglGetPbufferDCARB , wglReleasePbufferDCARB , wglReleasePbufferDCARB , wglQueryPbufferARB , wglBindTexImageARB , wglReleaseTexImageARB , wglSetPbufferAttribARB .

    b. 设定PBuffer每个Pixel的格式,用wglChoosePixelFormatARB

    c. 建立PBuffer,用wglCreatePbufferARB

    d. 取得PBuffer的环境DC,用wglGetPbufferDCARB及wglCreateContext

3. 启动PBuffer:
    wglMakeContextCurrentARB(hPBufDC, hPBufDC, hPBufRC);

4. 对PBuffer绘图:这个步骤有一点需要特别注意,就是在PBuffer的绘图环境是与Frame Buffer完全独立的。 也就是说投影矩阵、几何资讯、光源、贴图...等,都需要重新设定!

5. 启动原来的Frame Buffer:
    wglMakeContextCurrentARB(hGLDC, hGLDC, hGLRC);

6. 将PBuffer当成贴图:注意! 这个步骤一定要Frame Buffer的绘图环境下执行!

    GLuint nPbufTexID;
    glGenTextures(1, &nPbufTexID);
    glBindTexture (GL_TEXTURE_2D, nPbufTexID);
    glTexImage2D( .... );
    glTexParameterf(....);
    wglBindTexImageARB( hPBuf, WGL_FRONT_LEFT_ARB);

7. 对Frame Buffer画图:即一般的绘图流程,要注意的是所有绘图环境需重新设定。

8. 解除贴图的连结:
    wglReleaseTexImageARB(hPBuf, WGL_FRONT_LEFT_ARB);

9. 删除PBuffer:这个步骤是当PBuffer不再使用的情况下才执行。
    wglReleaseTexImageARB(hPBuf, WGL_FRONT_LEFT_ARB); 
    glDeleteTextures (1, &nPbufTexID);
    wglDeleteContext(hPBufRC);
    wglReleasePbufferDCARB(hPBuf, hPBufDC);
    wglDestroyPbufferARB(hPBuf);

  对直接在Texture上作画,PBuffer是目前比较常用的方法,但不是最佳的方法! 因为它仍有许多限制,如它只能在视窗化的作业系统上运作(如Microsoft Windows、XWindow、Mac OS...),以及两个PBuffer无法直接分享资源等。 于是OpenGL又在2003年提供了一个更好的方法-- Frame Buffer Object(FBO),这也是目前GPGPU(General Purpose GPU, 绘图晶片泛用运算)所必须的基本功能。 我将在下一篇文章为各位介绍。

参考资料:

[1] Christopher Oat, "Rendering to an off-screen buffer with WGL_ARB_pbuffer", ATI Research, Inc.

[2] PBuffer范例程式

  • 0
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值