|
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, 0, sizeof(int)*2*MAX_ATTRIBS); memset(fAttributes, 0, sizeof(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, 0, sizeof(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, -1, 1); 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.0f, 0.0f); glVertex2i(left, bottom); glTexCoord2f(1.0f, 0.0f); glVertex2i(left + width, bottom); glTexCoord2f(1.0f, 1.0f); glVertex2i(left + width, bottom + height); glTexCoord2f(0.0f, 1.0f); glVertex2i(left, bottom + height); glEnd(); } };
#endif//__OGL_RENDER_TEXTURE_H__
|