如何使透明背景的OpenGL渲染上下文?

渲染上下文通常在背景上有一个纯色(黑色或其他,见下图):

替代文字

我想知道是否可以设置一个窗口,没有装饰和透明背景,同时允许我呈现OpenGL的东西。

这会让人错觉三angular形在屏幕上浮动。 透明的背景应该允许你看到桌面或者其他可能的应用程序。

你能举例说明源代码吗?

平台:Windows(仅限win32)

为了在这个问题上得到一些帮助而花费了一些不成功的奖励的声誉之后,我终于意识到我感兴趣的问题有多复杂。

完成这个任务的less数人不会有太多的共同点 。 在我的研究中,我发现了不同的方法来实现我所期待的。 其中最有趣的一个是AeroGL ,它使用了迄今为止没有提到的一种技术来显示代码片段,该技术将graphics渲染为与设备无关的位图 (DIB)。

要永久closures此线程, 下面源代码将实现该技术。 代码本身是对这里提出的应用程序的一个小小的修改(非常感谢Andrei Sapronov Y. )。

最终结果可以在下图中看到:

在这里输入图像描述

该代码已经在Windows XP(32位)和Windows 8.1(32位)上进行了testing。 请享用!

#define _WIN32_WINNT 0x0500 #include <windows.h> #include <windowsx.h> #include <GL/gl.h> #include <GL/glu.h> #pragma comment (lib, "opengl32.lib") #pragma comment (lib, "glu32.lib") #include <assert.h> #include <tchar.h> #ifdef assert #define verify(expr) if(!expr) assert(0) #else verify(expr) expr #endif const TCHAR szAppName[]=_T("TransparentGL"); const TCHAR wcWndName[]=_T("WS_EX_LAYERED OpenGL"); HDC hDC; HGLRC m_hrc; int w(240); int h(240); HDC pdcDIB; HBITMAP hbmpDIB; void *bmp_cnt(NULL); int cxDIB(0); int cyDIB(0); BITMAPINFOHEADER BIH; BOOL initSC() { glEnable(GL_ALPHA_TEST); glEnable(GL_DEPTH_TEST); glEnable(GL_COLOR_MATERIAL); glEnable(GL_LIGHTING); glEnable(GL_LIGHT0); glEnable(GL_BLEND); glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); glClearColor(0, 0, 0, 0); return 0; } void resizeSC(int width,int height) { glViewport(0,0,width,height); glMatrixMode(GL_PROJECTION); glLoadIdentity(); glMatrixMode(GL_MODELVIEW ); glLoadIdentity(); } BOOL renderSC() { glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT ); glPushMatrix(); glColor3f(0, 1, 1); glBegin(GL_TRIANGLES); // Drawing Using Triangles glColor3f(1.0f,0.0f,0.0f); // Set The Color To Red glVertex3f( 0.0f, 1.0f, 0.0f); // Top glColor3f(0.0f,1.0f,0.0f); // Set The Color To Green glVertex3f(-1.0f,-1.0f, 0.0f); // Bottom Left glColor3f(0.0f,0.0f,1.0f); // Set The Color To Blue glVertex3f( 1.0f,-1.0f, 0.0f); // Bottom Right glEnd(); glPopMatrix(); glFlush(); return 0; } // DIB -> hDC void draw(HDC pdcDest) { assert(pdcDIB); verify(BitBlt(pdcDest, 0, 0, w, h, pdcDIB, 0, 0, SRCCOPY)); } void CreateDIB(int cx, int cy) { assert(cx > 0); assert(cy > 0); cxDIB = cx ; cyDIB = cy ; int iSize = sizeof(BITMAPINFOHEADER); memset(&BIH, 0, iSize); BIH.biSize = iSize; BIH.biWidth = cx; BIH.biHeight = cy; BIH.biPlanes = 1; BIH.biBitCount = 24; BIH.biCompression = BI_RGB; if(pdcDIB) verify(DeleteDC(pdcDIB)); pdcDIB = CreateCompatibleDC(NULL); assert(pdcDIB); if(hbmpDIB) verify(DeleteObject(hbmpDIB)); hbmpDIB = CreateDIBSection( pdcDIB, (BITMAPINFO*)&BIH, DIB_RGB_COLORS, &bmp_cnt, NULL, 0); assert(hbmpDIB); assert(bmp_cnt); if(hbmpDIB) SelectObject(pdcDIB, hbmpDIB); } BOOL CreateHGLRC() { DWORD dwFlags = PFD_SUPPORT_OPENGL | PFD_DRAW_TO_BITMAP; PIXELFORMATDESCRIPTOR pfd ; memset(&pfd,0, sizeof(PIXELFORMATDESCRIPTOR)) ; pfd.nSize = sizeof(PIXELFORMATDESCRIPTOR); pfd.nVersion = 1; pfd.dwFlags = dwFlags ; pfd.iPixelType = PFD_TYPE_RGBA ; pfd.cColorBits = 24 ; pfd.cDepthBits = 32 ; pfd.iLayerType = PFD_MAIN_PLANE ; int PixelFormat = ChoosePixelFormat(pdcDIB, &pfd); if (PixelFormat == 0){ assert(0); return FALSE ; } BOOL bResult = SetPixelFormat(pdcDIB, PixelFormat, &pfd); if (bResult==FALSE){ assert(0); return FALSE ; } m_hrc = wglCreateContext(pdcDIB); if (!m_hrc){ assert(0); return FALSE; } return TRUE; } LRESULT CALLBACK WindowFunc(HWND hWnd,UINT msg, WPARAM wParam, LPARAM lParam) { PAINTSTRUCT ps; switch(msg) { case WM_ERASEBKGND: return 0; break; case WM_CREATE: break; case WM_DESTROY: if(m_hrc) { wglMakeCurrent(NULL, NULL); wglDeleteContext(m_hrc) ; } PostQuitMessage(0) ; break; case WM_PAINT: hDC = BeginPaint(hWnd, &ps); renderSC(); // OpenGL -> DIB draw(hDC); // DIB -> hDC EndPaint(hWnd, &ps); break; case WM_SIZE: w = LOWORD(lParam); h = HIWORD(lParam); wglMakeCurrent(NULL, NULL); wglDeleteContext(m_hrc); CreateDIB(w, h); CreateHGLRC(); verify(wglMakeCurrent(pdcDIB, m_hrc)); initSC(); resizeSC(w, h); renderSC(); break; default: return DefWindowProc(hWnd,msg,wParam,lParam); } return 0; } int WINAPI _tWinMain(HINSTANCE hThisInst, HINSTANCE hPrevInst, LPSTR str,int nWinMode) { WNDCLASSEX wc; memset(&wc, 0, sizeof(wc)); wc.cbSize = sizeof(WNDCLASSEX); wc.hIconSm = LoadIcon(NULL, IDI_APPLICATION); wc.style = CS_HREDRAW | CS_VREDRAW; wc.lpfnWndProc = (WNDPROC)WindowFunc; wc.cbClsExtra = 0; wc.cbWndExtra = 0; wc.hInstance = hThisInst; wc.hIcon = LoadIcon(NULL, IDI_APPLICATION); wc.hCursor = LoadCursor(NULL, IDC_ARROW); wc.hbrBackground = (HBRUSH) (COLOR_WINDOW); wc.lpszClassName = szAppName; if(!RegisterClassEx(&wc)) { MessageBox(NULL, _T("RegisterClassEx - failed"), _T("Error"), MB_OK | MB_ICONERROR); return FALSE; } HWND hWnd = CreateWindowEx(WS_EX_LAYERED, szAppName, wcWndName, WS_VISIBLE | WS_POPUP, 200, 150, w, h, NULL, NULL, hThisInst, NULL); if(!hWnd){ MessageBox(NULL, _T("CreateWindowEx - failed"), _T("Error"), MB_OK | MB_ICONERROR); return FALSE; } verify(SetLayeredWindowAttributes(hWnd, 0x0, 0, LWA_COLORKEY)); MSG msg; while(1) { while (PeekMessage(&msg,NULL,0,0,PM_NOREMOVE)){ if (GetMessage(&msg, NULL, 0, 0)) { TranslateMessage(&msg); DispatchMessage(&msg); } else return 0; } } return (FALSE); } 

我知道这是可能的Windows 7,不知道早期版本。

要摆脱窗口边框,您需要从窗口中删除WS_OVERLAPPEDWINDOW样式并添加WS_POPUP样式:

 DWORD style = ::GetWindowLong(hWnd, GWL_STYLE); style &= ~WS_OVERLAPPEDWINDOW; style |= WS_POPUP; ::SetWindowLong(hWnd, GWL_STYLE, style); 

要使OpenGL窗口的背景透明,您需要使用DwmEnableBlurBehindWindow函数:

 DWM_BLURBEHIND bb = {0}; bb.dwFlags = DWM_BB_ENABLE; bb.fEnable = true; bb.hRgnBlur = NULL; DwmEnableBlurBehindWindow(hWnd, &bb); 

调用glClearColor时,还需要为alpha值指定0。

 glClearColor(0.0f,0.0f,0.0f,0.0f); 

另外,在创buildOpenGL上下文时,请确保分配一个Alpha通道。

现在你的背景应该是完全透明的。 如果您保留窗口装饰,那么背景将使用Aero模糊外观,您可以使用glClearColor的Alpha值调整透明度级别。

由于迄今为止给出的所有答案都只针对Windows,但在X11上也有合成窗口pipe理器的需求,以供参考,我在此处发布我的示例代码(也可以在https://github.com/datenwolf /codesamples/blob/master/samples/OpenGL/x11argb_opengl/x11argb_opengl.c

 /*------------------------------------------------------------------------ * A demonstration of OpenGL in a ARGB window * => support for composited window transparency * * (c) 2011 by Wolfgang 'datenwolf' Draxinger * See me at comp.graphics.api.opengl and StackOverflow.com * License agreement: This source code is provided "as is". You * can use this source code however you want for your own personal * use. If you give this source code to anybody else then you must * leave this message in it. * * This program is based on the simplest possible * Linux OpenGL program by FTB (see info below) The simplest possible Linux OpenGL program? Maybe... (c) 2002 by FTB. See me in comp.graphics.api.opengl -- <\___/> / OO \ \_____/ FTB. ------------------------------------------------------------------------*/ #include <stdlib.h> #include <stdio.h> #include <string.h> #include <math.h> #include <GL/gl.h> #include <GL/glx.h> #include <GL/glxext.h> #include <X11/Xatom.h> #include <X11/extensions/Xrender.h> #include <X11/Xutil.h> #define USE_CHOOSE_FBCONFIG static void fatalError(const char *why) { fprintf(stderr, "%s", why); exit(0x666); } static int Xscreen; static Atom del_atom; static Colormap cmap; static Display *Xdisplay; static XVisualInfo *visual; static XRenderPictFormat *pict_format; static GLXFBConfig *fbconfigs, fbconfig; static int numfbconfigs; static GLXContext render_context; static Window Xroot, window_handle; static GLXWindow glX_window_handle; static int width, height; static int VisData[] = { GLX_RENDER_TYPE, GLX_RGBA_BIT, GLX_DRAWABLE_TYPE, GLX_WINDOW_BIT, GLX_DOUBLEBUFFER, True, GLX_RED_SIZE, 8, GLX_GREEN_SIZE, 8, GLX_BLUE_SIZE, 8, GLX_ALPHA_SIZE, 8, GLX_DEPTH_SIZE, 16, None }; static int isExtensionSupported(const char *extList, const char *extension) { const char *start; const char *where, *terminator; /* Extension names should not have spaces. */ where = strchr(extension, ' '); if ( where || *extension == '\0' ) return 0; /* It takes a bit of care to be fool-proof about parsing the OpenGL extensions string. Don't be fooled by sub-strings, etc. */ for ( start = extList; ; ) { where = strstr( start, extension ); if ( !where ) break; terminator = where + strlen( extension ); if ( where == start || *(where - 1) == ' ' ) if ( *terminator == ' ' || *terminator == '\0' ) return 1; start = terminator; } return 0; } static Bool WaitForMapNotify(Display *d, XEvent *e, char *arg) { return d && e && arg && (e->type == MapNotify) && (e->xmap.window == *(Window*)arg); } static void describe_fbconfig(GLXFBConfig fbconfig) { int doublebuffer; int red_bits, green_bits, blue_bits, alpha_bits, depth_bits; glXGetFBConfigAttrib(Xdisplay, fbconfig, GLX_DOUBLEBUFFER, &doublebuffer); glXGetFBConfigAttrib(Xdisplay, fbconfig, GLX_RED_SIZE, &red_bits); glXGetFBConfigAttrib(Xdisplay, fbconfig, GLX_GREEN_SIZE, &green_bits); glXGetFBConfigAttrib(Xdisplay, fbconfig, GLX_BLUE_SIZE, &blue_bits); glXGetFBConfigAttrib(Xdisplay, fbconfig, GLX_ALPHA_SIZE, &alpha_bits); glXGetFBConfigAttrib(Xdisplay, fbconfig, GLX_DEPTH_SIZE, &depth_bits); fprintf(stderr, "FBConfig selected:\n" "Doublebuffer: %s\n" "Red Bits: %d, Green Bits: %d, Blue Bits: %d, Alpha Bits: %d, Depth Bits: %d\n", doublebuffer == True ? "Yes" : "No", red_bits, green_bits, blue_bits, alpha_bits, depth_bits); } static void createTheWindow() { XEvent event; int x,y, attr_mask; XSizeHints hints; XWMHints *startup_state; XTextProperty textprop; XSetWindowAttributes attr = {0,}; static char *title = "FTB's little OpenGL example - ARGB extension by WXD"; Xdisplay = XOpenDisplay(NULL); if (!Xdisplay) { fatalError("Couldn't connect to X server\n"); } Xscreen = DefaultScreen(Xdisplay); Xroot = RootWindow(Xdisplay, Xscreen); fbconfigs = glXChooseFBConfig(Xdisplay, Xscreen, VisData, &numfbconfigs); fbconfig = 0; for(int i = 0; i<numfbconfigs; i++) { visual = (XVisualInfo*) glXGetVisualFromFBConfig(Xdisplay, fbconfigs[i]); if(!visual) continue; pict_format = XRenderFindVisualFormat(Xdisplay, visual->visual); if(!pict_format) continue; fbconfig = fbconfigs[i]; if(pict_format->direct.alphaMask > 0) { break; } } if(!fbconfig) { fatalError("No matching FB config found"); } describe_fbconfig(fbconfig); /* Create a colormap - only needed on some X clients, eg. IRIX */ cmap = XCreateColormap(Xdisplay, Xroot, visual->visual, AllocNone); attr.colormap = cmap; attr.background_pixmap = None; attr.border_pixmap = None; attr.border_pixel = 0; attr.event_mask = StructureNotifyMask | EnterWindowMask | LeaveWindowMask | ExposureMask | ButtonPressMask | ButtonReleaseMask | OwnerGrabButtonMask | KeyPressMask | KeyReleaseMask; attr_mask = CWBackPixmap| CWColormap| CWBorderPixel| CWEventMask; width = DisplayWidth(Xdisplay, DefaultScreen(Xdisplay))/2; height = DisplayHeight(Xdisplay, DefaultScreen(Xdisplay))/2; x=width/2, y=height/2; window_handle = XCreateWindow( Xdisplay, Xroot, x, y, width, height, 0, visual->depth, InputOutput, visual->visual, attr_mask, &attr); if( !window_handle ) { fatalError("Couldn't create the window\n"); } #if USE_GLX_CREATE_WINDOW int glXattr[] = { None }; glX_window_handle = glXCreateWindow(Xdisplay, fbconfig, window_handle, glXattr); if( !glX_window_handle ) { fatalError("Couldn't create the GLX window\n"); } #else glX_window_handle = window_handle; #endif textprop.value = (unsigned char*)title; textprop.encoding = XA_STRING; textprop.format = 8; textprop.nitems = strlen(title); hints.x = x; hints.y = y; hints.width = width; hints.height = height; hints.flags = USPosition|USSize; startup_state = XAllocWMHints(); startup_state->initial_state = NormalState; startup_state->flags = StateHint; XSetWMProperties(Xdisplay, window_handle,&textprop, &textprop, NULL, 0, &hints, startup_state, NULL); XFree(startup_state); XMapWindow(Xdisplay, window_handle); XIfEvent(Xdisplay, &event, WaitForMapNotify, (char*)&window_handle); if ((del_atom = XInternAtom(Xdisplay, "WM_DELETE_WINDOW", 0)) != None) { XSetWMProtocols(Xdisplay, window_handle, &del_atom, 1); } } static int ctxErrorHandler( Display *dpy, XErrorEvent *ev ) { fputs("Error at context creation", stderr); return 0; } static void createTheRenderContext() { int dummy; if (!glXQueryExtension(Xdisplay, &dummy, &dummy)) { fatalError("OpenGL not supported by X server\n"); } #if USE_GLX_CREATE_CONTEXT_ATTRIB #define GLX_CONTEXT_MAJOR_VERSION_ARB 0x2091 #define GLX_CONTEXT_MINOR_VERSION_ARB 0x2092 render_context = NULL; if( isExtensionSupported( glXQueryExtensionsString(Xdisplay, DefaultScreen(Xdisplay)), "GLX_ARB_create_context" ) ) { typedef GLXContext (*glXCreateContextAttribsARBProc)(Display*, GLXFBConfig, GLXContext, Bool, const int*); glXCreateContextAttribsARBProc glXCreateContextAttribsARB = (glXCreateContextAttribsARBProc)glXGetProcAddressARB( (const GLubyte *) "glXCreateContextAttribsARB" ); if( glXCreateContextAttribsARB ) { int context_attribs[] = { GLX_CONTEXT_MAJOR_VERSION_ARB, 3, GLX_CONTEXT_MINOR_VERSION_ARB, 0, //GLX_CONTEXT_FLAGS_ARB , GLX_CONTEXT_FORWARD_COMPATIBLE_BIT_ARB, None }; int (*oldHandler)(Display*, XErrorEvent*) = XSetErrorHandler(&ctxErrorHandler); render_context = glXCreateContextAttribsARB( Xdisplay, fbconfig, 0, True, context_attribs ); XSync( Xdisplay, False ); XSetErrorHandler( oldHandler ); fputs("glXCreateContextAttribsARB failed", stderr); } else { fputs("glXCreateContextAttribsARB could not be retrieved", stderr); } } else { fputs("glXCreateContextAttribsARB not supported", stderr); } if(!render_context) { #else { #endif render_context = glXCreateNewContext(Xdisplay, fbconfig, GLX_RGBA_TYPE, 0, True); if (!render_context) { fatalError("Failed to create a GL context\n"); } } if (!glXMakeContextCurrent(Xdisplay, glX_window_handle, glX_window_handle, render_context)) { fatalError("glXMakeCurrent failed for window\n"); } } static int updateTheMessageQueue() { XEvent event; XConfigureEvent *xc; while (XPending(Xdisplay)) { XNextEvent(Xdisplay, &event); switch (event.type) { case ClientMessage: if (event.xclient.data.l[0] == del_atom) { return 0; } break; case ConfigureNotify: xc = &(event.xconfigure); width = xc->width; height = xc->height; break; } } return 1; } /* 6----7 /| /| 3----2 | | 5--|-4 |/ |/ 0----1 */ GLfloat cube_vertices[][8] = { /* XYZ Nx Ny Nz ST */ {-1.0, -1.0, 1.0, 0.0, 0.0, 1.0, 0.0, 0.0}, // 0 { 1.0, -1.0, 1.0, 0.0, 0.0, 1.0, 1.0, 0.0}, // 1 { 1.0, 1.0, 1.0, 0.0, 0.0, 1.0, 1.0, 1.0}, // 2 {-1.0, 1.0, 1.0, 0.0, 0.0, 1.0, 0.0, 1.0}, // 3 { 1.0, -1.0, -1.0, 0.0, 0.0, -1.0, 0.0, 0.0}, // 4 {-1.0, -1.0, -1.0, 0.0, 0.0, -1.0, 1.0, 0.0}, // 5 {-1.0, 1.0, -1.0, 0.0, 0.0, -1.0, 1.0, 1.0}, // 6 { 1.0, 1.0, -1.0, 0.0, 0.0, -1.0, 0.0, 1.0}, // 7 {-1.0, -1.0, -1.0, -1.0, 0.0, 0.0, 0.0, 0.0}, // 5 {-1.0, -1.0, 1.0, -1.0, 0.0, 0.0, 1.0, 0.0}, // 0 {-1.0, 1.0, 1.0, -1.0, 0.0, 0.0, 1.0, 1.0}, // 3 {-1.0, 1.0, -1.0, -1.0, 0.0, 0.0, 0.0, 1.0}, // 6 { 1.0, -1.0, 1.0, 1.0, 0.0, 0.0, 0.0, 0.0}, // 1 { 1.0, -1.0, -1.0, 1.0, 0.0, 0.0, 1.0, 0.0}, // 4 { 1.0, 1.0, -1.0, 1.0, 0.0, 0.0, 1.0, 1.0}, // 7 { 1.0, 1.0, 1.0, 1.0, 0.0, 0.0, 0.0, 1.0}, // 2 {-1.0, -1.0, -1.0, 0.0, -1.0, 0.0, 0.0, 0.0}, // 5 { 1.0, -1.0, -1.0, 0.0, -1.0, 0.0, 1.0, 0.0}, // 4 { 1.0, -1.0, 1.0, 0.0, -1.0, 0.0, 1.0, 1.0}, // 1 {-1.0, -1.0, 1.0, 0.0, -1.0, 0.0, 0.0, 1.0}, // 0 {-1.0, 1.0, 1.0, 0.0, 1.0, 0.0, 0.0, 0.0}, // 3 { 1.0, 1.0, 1.0, 0.0, 1.0, 0.0, 1.0, 0.0}, // 2 { 1.0, 1.0, -1.0, 0.0, 1.0, 0.0, 1.0, 1.0}, // 7 {-1.0, 1.0, -1.0, 0.0, 1.0, 0.0, 0.0, 1.0}, // 6 }; static void draw_cube(void) { glEnableClientState(GL_VERTEX_ARRAY); glEnableClientState(GL_NORMAL_ARRAY); glEnableClientState(GL_TEXTURE_COORD_ARRAY); glVertexPointer(3, GL_FLOAT, sizeof(GLfloat) * 8, &cube_vertices[0][0]); glNormalPointer(GL_FLOAT, sizeof(GLfloat) * 8, &cube_vertices[0][3]); glTexCoordPointer(2, GL_FLOAT, sizeof(GLfloat) * 8, &cube_vertices[0][6]); glDrawArrays(GL_QUADS, 0, 24); } float const light0_dir[]={0,1,0,0}; float const light0_color[]={78./255., 80./255., 184./255.,1}; float const light1_dir[]={-1,1,1,0}; float const light1_color[]={255./255., 220./255., 97./255.,1}; float const light2_dir[]={0,-1,0,0}; float const light2_color[]={31./255., 75./255., 16./255.,1}; static void redrawTheWindow() { float const aspect = (float)width / (float)height; static float a=0; static float b=0; static float c=0; glDrawBuffer(GL_BACK); glViewport(0, 0, width, height); // Clear with alpha = 0.0, ie full transparency glClearColor(0.0, 0.0, 0.0, 0.0); glClear(GL_COLOR_BUFFER_BIT|GL_DEPTH_BUFFER_BIT); glMatrixMode(GL_PROJECTION); glLoadIdentity(); glFrustum(-aspect, aspect, -1, 1, 2.5, 10); glMatrixMode(GL_MODELVIEW); glLoadIdentity(); glEnable(GL_DEPTH_TEST); glEnable(GL_CULL_FACE); glEnable(GL_BLEND); glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); glLightfv(GL_LIGHT0, GL_POSITION, light0_dir); glLightfv(GL_LIGHT0, GL_DIFFUSE, light0_color); glLightfv(GL_LIGHT1, GL_POSITION, light1_dir); glLightfv(GL_LIGHT1, GL_DIFFUSE, light1_color); glLightfv(GL_LIGHT2, GL_POSITION, light2_dir); glLightfv(GL_LIGHT2, GL_DIFFUSE, light2_color); glTranslatef(0., 0., -5.); glRotatef(a, 1, 0, 0); glRotatef(b, 0, 1, 0); glRotatef(c, 0, 0, 1); glEnable(GL_LIGHT0); glEnable(GL_LIGHT1); glEnable(GL_LIGHTING); glEnable(GL_COLOR_MATERIAL); glColorMaterial(GL_FRONT_AND_BACK, GL_AMBIENT_AND_DIFFUSE); glColor4f(1., 1., 1., 0.5); glCullFace(GL_FRONT); draw_cube(); glCullFace(GL_BACK); draw_cube(); a = fmod(a+0.1, 360.); b = fmod(b+0.5, 360.); c = fmod(c+0.25, 360.); glXSwapBuffers(Xdisplay, glX_window_handle); } int main(int argc, char *argv[]) { createTheWindow(); createTheRenderContext(); while (updateTheMessageQueue()) { redrawTheWindow(); } return 0; } 

主要的技巧是获得正确的FBConfig。 你需要问一个alpha通道, testing相关的XRenderPictFormat是否存在一个alpha掩码。

这是一个老问题,但是由于Windows的新版本具有合成和支持,就像datenwolf提示的那样,对于opengl,我们可以使用一些特殊的function来实现这一点。 虽然在DirectX上也是微不足道的(参考图)微软的确在opengl上下文中添加了合成提示。 耶反托拉斯的恐惧!

所以,我们可以不用低效率的复制到物理内存的操作,而是让合成引擎明白如何使用opengl上下文。

所以,你必须创build一个opengl上下文的像素格式,指定一个alpha通道,它应该使用组合(第82行)。 然后,使用DwmApi.h例程来启用一个模糊的窗口(第179行),并指定一个完全无效的区域,这将不模糊任何内容,并使窗口保持透明。 (你需要在窗口类中指定一个黑色的+透明的画笔!奇怪!)然后,你实际上只是使用opengl,因为你习惯使用它。 在事件循环中,每获得一次机会,您都可以绘制和交换缓冲区(第201行),并记住启用GL_BLEND! 🙂

请检查/分叉https://gist.github.com/3644466或者只是基于OP自己的回答,而不是使用这种技术来查看下面的代码片段(你可以把它放在一个空的项目中):;

 #define _WIN32_WINNT 0x0500 #include <windows.h> #include <windowsx.h> #include <GL/gl.h> #include <GL/glu.h> #include <dwmapi.h> #pragma comment (lib, "opengl32.lib") #pragma comment (lib, "glu32.lib") #pragma comment (lib, "dwmapi.lib") #include <assert.h> #include <tchar.h> #ifdef assert #define verify(expr) if(!expr) assert(0) #else verify(expr) expr #endif const TCHAR szAppName[]=_T("TransparentGL"); const TCHAR wcWndName[]=_T("TransparentGL"); HDC hDC; HGLRC m_hrc; int w = 240; int h = 240; BOOL initSC() { glEnable(GL_ALPHA_TEST); glEnable(GL_DEPTH_TEST); glEnable(GL_COLOR_MATERIAL); glEnable(GL_LIGHTING); glEnable(GL_LIGHT0); glEnable(GL_BLEND); glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); glClearColor(0, 0, 0, 0); return 0; } void resizeSC(int width,int height) { glViewport(0,0,width,height); glMatrixMode(GL_PROJECTION); glLoadIdentity(); glMatrixMode(GL_MODELVIEW ); glLoadIdentity(); } BOOL renderSC() { glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT ); glPushMatrix(); glColor3f(0, 1, 1); glBegin(GL_TRIANGLES); // Drawing Using Triangles glColor3f(1.0f,0.0f,0.0f); // Set The Color To Red glVertex3f( 0.0f, 1.0f, 0.0f); // Top glColor3f(0.0f,1.0f,0.0f); // Set The Color To Green glVertex3f(-1.0f,-1.0f, 0.0f); // Bottom Left glColor3f(0.0f,0.0f,1.0f); // Set The Color To Blue glVertex3f( 1.0f,-1.0f, 0.0f); // Bottom Right glEnd(); glPopMatrix(); glFlush(); return 0; } BOOL CreateHGLRC(HWND hWnd) { PIXELFORMATDESCRIPTOR pfd = { sizeof(PIXELFORMATDESCRIPTOR), 1, // Version Number PFD_DRAW_TO_WINDOW | // Format Must Support Window PFD_SUPPORT_OPENGL | // Format Must Support OpenGL PFD_SUPPORT_COMPOSITION | // Format Must Support Composition PFD_DOUBLEBUFFER, // Must Support Double Buffering PFD_TYPE_RGBA, // Request An RGBA Format 32, // Select Our Color Depth 0, 0, 0, 0, 0, 0, // Color Bits Ignored 8, // An Alpha Buffer 0, // Shift Bit Ignored 0, // No Accumulation Buffer 0, 0, 0, 0, // Accumulation Bits Ignored 24, // 16Bit Z-Buffer (Depth Buffer) 8, // Some Stencil Buffer 0, // No Auxiliary Buffer PFD_MAIN_PLANE, // Main Drawing Layer 0, // Reserved 0, 0, 0 // Layer Masks Ignored }; HDC hdc = GetDC(hWnd); int PixelFormat = ChoosePixelFormat(hdc, &pfd); if (PixelFormat == 0) { assert(0); return FALSE ; } BOOL bResult = SetPixelFormat(hdc, PixelFormat, &pfd); if (bResult==FALSE) { assert(0); return FALSE ; } m_hrc = wglCreateContext(hdc); if (!m_hrc){ assert(0); return FALSE; } ReleaseDC(hWnd, hdc); return TRUE; } LRESULT CALLBACK WindowFunc(HWND hWnd,UINT msg, WPARAM wParam, LPARAM lParam) { PAINTSTRUCT ps; switch(msg) { case WM_CREATE: break; case WM_DESTROY: if(m_hrc) { wglMakeCurrent(NULL, NULL); wglDeleteContext(m_hrc) ; } PostQuitMessage(0) ; break; default: return DefWindowProc(hWnd,msg,wParam,lParam); } return 0; } int WINAPI _tWinMain(HINSTANCE hThisInst, HINSTANCE hPrevInst, LPSTR str,int nWinMode) { WNDCLASSEX wc; memset(&wc, 0, sizeof(wc)); wc.cbSize = sizeof(WNDCLASSEX); wc.hIconSm = LoadIcon(NULL, IDI_APPLICATION); wc.style = CS_HREDRAW | CS_VREDRAW; wc.lpfnWndProc = (WNDPROC)WindowFunc; wc.cbClsExtra = 0; wc.cbWndExtra = 0; wc.hInstance = hThisInst; wc.hIcon = LoadIcon(NULL, IDI_APPLICATION); wc.hCursor = LoadCursor(NULL, IDC_ARROW); wc.hbrBackground = (HBRUSH)CreateSolidBrush(0x00000000); wc.lpszClassName = szAppName; if(!RegisterClassEx(&wc)) { MessageBox(NULL, _T("RegisterClassEx - failed"), _T("Error"), MB_OK | MB_ICONERROR); return FALSE; } HWND hWnd = CreateWindowEx(WS_EX_APPWINDOW, szAppName, wcWndName, WS_VISIBLE | WS_POPUP, 200, 150, w, h, NULL, NULL, hThisInst, NULL); if(!hWnd) { MessageBox(NULL, _T("CreateWindowEx - failed"), _T("Error"), MB_OK | MB_ICONERROR); return FALSE; } DWM_BLURBEHIND bb = {0}; HRGN hRgn = CreateRectRgn(0, 0, -1, -1); bb.dwFlags = DWM_BB_ENABLE | DWM_BB_BLURREGION; bb.hRgnBlur = hRgn; bb.fEnable = TRUE; DwmEnableBlurBehindWindow(hWnd, &bb); CreateHGLRC(hWnd); HDC hdc = GetDC(hWnd); wglMakeCurrent(hdc, m_hrc); initSC(); resizeSC(w, h); ReleaseDC(hWnd, hdc); MSG msg; while(1) { if (PeekMessage(&msg, NULL, 0, 0, PM_REMOVE)) { TranslateMessage(&msg); DispatchMessage(&msg); } else { HDC hdc = GetDC(hWnd); wglMakeCurrent(hdc, m_hrc); renderSC(); SwapBuffers(hdc); ReleaseDC(hWnd, hdc); } } return (FALSE); } 

如果允许将OpenGL窗口分层,这将非常容易。 但他们不是,所以你必须去做别的。

你可以做的是创build一个分层的窗口(WS_EX_LAYERED + SetLayeredWindowAttributes() – 谷歌,如果你不知道他们),以处理透明度和一个隐藏的OpenGL窗口的渲染。 将OpenGL场景渲染到屏幕外的缓冲区,将其读回并与分层窗口共享,然后将bitblt(GDI函数)分享给分层窗口。

对于非常复杂的东西,这可能太慢了,但会给你所要求的效果,并且在Windows 2000及更高版本上工作。

编辑:当涉及到创build实际的屏幕外缓冲区,framebuffer对象(FBO)可能是您最好的select。 你可以在隐藏的OpenGL窗口上绘制,不过我想我记得有人发布过这个问题,因为像素所有权 – build议使用FBO。 你也可以使用像素缓冲区(pbuffers),但是这些都是过时的(标记为“遗留”),并且FBO被认为是现代化的方式。 FBO应该给你硬件加速(如果支持的话),而且本身不会限制你使用特定的OpenGL版本。 你需要一个OpenGL上下文来使用它,所以你必须创build隐藏的OpenGL窗口并从那里设置FBO。

这里有一些关于FBO的资源:
维基百科
FBO
Gamedev文章
指南 (对于Mac,但可能会有所帮助)

伟大的演示与源代码带你一步一步:

http://www.dhpoware.com/demos/index.html

您可以将3d场景渲染为pbuffer,并使用颜色键将其投射到屏幕上。

ClanLib游戏SDK执行此操作。

如果您只需要一个静态透明边框,请使用以下技术:

创build5个窗口

AAAAA

公元前

公元前

DDDDD

A,B,C,D是分层窗口

“#”是主窗口。

请参阅 – http://clanlib.org/wiki/ClanLib_2.2.9_Release_Notes底部的图片;