平民程序 - linghuye's blog

天下风云出我辈,一入江湖岁月催。皇图霸业谈笑中,不胜人生一场醉。提剑跨骑挥鬼雨,白骨如山鸟惊飞。尘事如潮人如水,只笑江湖几人回。

随笔 - 221, 文章 - 0, 评论 - 680, 引用 - 0
数据加载中……

Opengl PBuffer及RenderToTexture理解和使用

1.在一个Opengl Context(HGLRC)里创建的Texture不能在另一个Opengl Context中使用.

2.HPBUFFERARB PBuffer对象提供了一种Offsceen Render Target机制,类似于GDI的内存位图,DX的RenderSurface.属Opengl 1.3规范,wgl扩展形式.

2.创建PBuffer:
  a.使用wglChoosePixelFormatARB获得指定属性特点的象素格式列表,随便选择1个,使用wglCreatePbufferARB创建一个OBuffer对象,取得该PBuffer的关联DC,创建一个Opengl Context,即PBuffer所关联的环境.
  b.进入该PBuffer的Opengl context,作图.
 
3.使用wglBindTexImageARB将1个PBuffer关联到当前的纹理对象上,此后若渲染该纹理时将渲染PBuffer表面的数据,此时纹理对象仅是个傀儡,其关联的PBuffer才是真正的数据源.wglBindTexImageARB应该在PBuffer Context之外的Opengl context中调用.

4.使用wglReleaseTexImageARB把PBuffer从其之前关联的Texture对象上释放.在PBuffer被绑定到某Texture后,未释放之前,不得进入PBuffer的Context进行渲染.显然wglReleaseTexImageARB也应该在PBuffer Context之外的Opengl context中调用

5.Render to texture 仅是PBuffer的一种使用方式. 技巧:
   a.使用glReadPixels读出PBuffer数据,然后在外部Context进行glDrawPixels,或glTexImageData,或直接图像输出,不会有Window Overlayclip 的限制. 

6.使用glTexParameteri(GL_TEXTURE_2D, GL_GENERATE_MIPMAP_SGIS, GL_TRUE),使得渲染出的纹理数据自动构造为Mipmap.

7.Designed for offscreen rendering - similar to windows, but non-visible!  It is a Windows system specific extentsion!

8.Problems:(From GDC Nvida)
• Each pbuffer usually has its own OpenGL context context
– (Assuming they have different pixel formats)
– Can share texture objects, display lists between pbuffers using wglShareLists ()
– Painful to manage, causes lots of bugs
• Switching between pbuffers is expensive
– wglMakeCurrent causes context switch
• Each  pbuffer has its own depth, stencil, aux buffers
– Cannot share depth buffers between pbuffers

9.Nvidia Sample http://download.developer.nvidia.com/developer/SDK/Individual_Samples/samples.html

#ifndef __OGL_RENDER_TEXTURE_H__
#define __OGL_RENDER_TEXTURE_H__

struct OglRenderTexture
{    
public:
    
enum { MAX_ATTRIBS = 256, MAX_PFORMATS = 256 }

public:
    HDC m_hWinDC;
    HDC m_hBufDC;
    HGLRC m_hWinGLRC;
    HGLRC m_hBufGLRC;
    HPBUFFERARB m_hpBuffer;
        
public:
    OglRenderTexture()
    
{
        m_hWinDC 
= NULL;
        m_hBufDC 
= NULL;
        m_hWinGLRC 
= NULL;
        m_hBufGLRC 
= NULL;
        m_hpBuffer 
= NULL;
    }

    
    
bool Create(int nWidth, int nHeight)
    
{    
        
// Record current context
        m_hWinDC = wglGetCurrentDC();
        m_hWinGLRC 
= wglGetCurrentContext();
        
if(!m_hWinGLRC) return false;
        
        
// Query for a suitable pixel format based on the specified mode.
        int     iAttributes[2*MAX_ATTRIBS];
        
float   fAttributes[2*MAX_ATTRIBS];
        memset(iAttributes, 
0sizeof(int)*2*MAX_ATTRIBS);
        memset(fAttributes, 
0sizeof(float)*2*MAX_ATTRIBS);
        
        
int nIndex = 0;
        iAttributes[nIndex
++= WGL_DRAW_TO_PBUFFER_ARB;
        iAttributes[nIndex
++= GL_TRUE;
        iAttributes[nIndex
++= WGL_BIND_TO_TEXTURE_RGBA_ARB;
        iAttributes[nIndex
++= GL_TRUE;
            
        unsigned 
int nFormats;  
        
int pFormats[MAX_PFORMATS];
        glext::wglChoosePixelFormatARB(m_hWinDC, iAttributes, fAttributes, MAX_PFORMATS, pFormats, 
&nFormats);
        CHECKF(nFormats);
        
        
// Choose the first one format
        int format = pFormats[0];
        
        
// Set up the pbuffer attributes
        nIndex = 0;
        memset(iAttributes, 
0sizeof(int)*2*MAX_ATTRIBS);
        iAttributes[nIndex
++= WGL_TEXTURE_FORMAT_ARB;
        iAttributes[nIndex
++= WGL_TEXTURE_RGBA_ARB;
        iAttributes[nIndex
++= WGL_TEXTURE_TARGET_ARB;
        iAttributes[nIndex
++= WGL_TEXTURE_2D_ARB;
        iAttributes[nIndex
++= WGL_MIPMAP_TEXTURE_ARB;
        iAttributes[nIndex
++= TRUE;
        iAttributes[nIndex
++= WGL_PBUFFER_LARGEST_ARB;
        iAttributes[nIndex
++= FALSE;
                    
        
// Create the p-buffer.
        m_hpBuffer = glext::wglCreatePbufferARB(m_hWinDC, format, nWidth, nHeight, iAttributes);
        
        
if(m_hpBuffer)
        
{    
            
// Create pbuffer context
            m_hBufDC = glext::wglGetPbufferDCARB(m_hpBuffer);
            m_hBufGLRC 
= wglCreateContext(m_hBufDC);

            glext::wglQueryPbufferARB(m_hpBuffer, WGL_PBUFFER_WIDTH_ARB, 
&nWidth);
            glext::wglQueryPbufferARB(m_hpBuffer, WGL_PBUFFER_HEIGHT_ARB, 
&nHeight);
            
            
// 仅使用 2D 模式
            wglMakeCurrent(m_hBufDC, m_hBufGLRC);
            glMatrixMode(GL_PROJECTION);
            glLoadIdentity();
            glOrtho(
0, nWidth, 0, nHeight, -11);
            glMatrixMode(GL_MODELVIEW);
            glEnable(GL_TEXTURE_2D);
            wglMakeCurrent(m_hWinDC, m_hWinGLRC);

            
return true;
        }

        
else return false;
    }

    
    
void Destroy()
    
{    
        
if(m_hpBuffer)
        
{    
            
// Clean up all resource
            wglDeleteContext(m_hBufGLRC);
            glext::wglReleasePbufferDCARB(m_hpBuffer, m_hBufDC);
            glext::wglDestroyPbufferARB(m_hpBuffer);
            m_hBufDC 
= NULL;
            m_hBufGLRC 
= NULL;
            m_hpBuffer 
= NULL;
        }

        
        m_hWinDC 
= NULL;
        m_hWinGLRC 
= NULL;
    }

    
    
bool BeginRender(GLuint texture)
    
{    
        
if(m_hpBuffer  &&  m_hBufDC  &&  m_hBufGLRC)
        
{    
            
// Record current context
            m_hWinDC = wglGetCurrentDC();
            m_hWinGLRC 
= wglGetCurrentContext();
                
            
// Ensure this texture will be bound in EndRender!
            glBindTexture(GL_TEXTURE_2D, texture);
            glTexParameteri(GL_TEXTURE_2D, GL_GENERATE_MIPMAP_SGIS, GL_TRUE);
            
            
// Release the pbuffer from the texture before render to it again!
            glext::wglReleaseTexImageARB(m_hpBuffer, WGL_FRONT_LEFT_ARB); 
            
            
// Switch to pbuffer context
            wglMakeCurrent(m_hBufDC, m_hBufGLRC);
            glClear(GL_COLOR_BUFFER_BIT 
| GL_DEPTH_BUFFER_BIT);
            glLoadIdentity();
            
return true;
        }

        
else return false;
    }

    
    
void EndRender()
    
{    
        
// Switch to original main window render context
        wglMakeCurrent(m_hWinDC, m_hWinGLRC);
        
        
// Bind to texture
        glext::wglBindTexImageARB(m_hpBuffer, WGL_FRONT_LEFT_ARB);
    }


    
void RectangleTexture(GLuint texture, int left, int bottom, int width, int height)
    
{    
        glBindTexture(GL_TEXTURE_2D, texture);
        glBegin(GL_TRIANGLE_FAN);    
        glTexCoord2f(
0.0f0.0f);    glVertex2i(left, bottom);
        glTexCoord2f(
1.0f0.0f);    glVertex2i(left + width, bottom);
        glTexCoord2f(
1.0f1.0f);    glVertex2i(left + width, bottom + height);
        glTexCoord2f(
0.0f1.0f);    glVertex2i(left, bottom + height);
        glEnd();
    }

}
;

#endif//__OGL_RENDER_TEXTURE_H__

posted on 2005-09-08 01:33 linghuye 阅读(4006) 评论(1)  编辑 收藏 引用 所属分类: 3D图形学研究

评论

# re: Opengl PBuffer及RenderToTexture理解和使用  回复  更多评论   

学习,所以留下脚印,谢谢
2008-01-21 16:38 | 李宁
只有注册用户登录后才能发表评论。