渲染上下文通常在背景上具有纯色(黑色或其他颜色,请参见下图):
的数据我想知道是否有可能设置一个窗口,没有装饰和透明的背景,同时允许我渲染OpenGL的东西。这会给予人一种错觉,即三角形漂浮在屏幕上。透明的背景应该可以让你看到桌面或其他可能在它后面的应用程序。你能用源代码举例说明吗?平台:Windows(仅限win32)
iyfamqjs1#
在这个问题上花了一些不成功的赏金来获得一些帮助之后,我终于意识到我感兴趣的问题有多复杂。完成这项任务的少数人don't share much。在我的研究过程中,我发现了不同的方法来实现我所寻找的。其中最有趣的一个是AeroGL,它使用一种迄今为止没有提到的技术来显示snippets of code,即将图形渲染到device-independent bitmap(DIB)。要永久关闭此线程,下面的源代码实现了该技术。代码本身是对here应用程序的轻微修改(非常感谢 Andrei Sapronov Y.)。最终结果如下图所示:
的数据该代码已在Windows XP(32位)和Windows 8.1(32位)上测试。享受吧
#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); }
字符串
uqdfh47h2#
由于到目前为止给出的所有答案都只针对Windows,但肯定也有在X11上使用复合窗口管理器进行此操作的需求,为了参考,我将示例代码发布在这里(也可以在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 -- <\___/> / O O \ \_____/ 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; } XFree(visual); visual = NULL; } if( !visual || !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] = { /* X Y Z Nx Ny Nz S T */ {-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, i.e. 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通道并测试关联的XRenderPictFormat是否存在alpha遮罩。
XRenderPictFormat
llycmphe3#
我知道这是可能的Windows 7,不确定早期版本。要删除窗口边框,您需要从窗口中删除WS_OVERLAPPEDWINDOW样式并添加WS_POPUP样式:
WS_OVERLAPPEDWINDOW
WS_POPUP
DWORD style = ::GetWindowLong(hWnd, GWL_STYLE); style &= ~WS_OVERLAPPEDWINDOW; style |= WS_POPUP; ::SetWindowLong(hWnd, GWL_STYLE, style);
字符串要使OpenGL窗口的背景透明,您需要使用DwmEnableBlurBehindWindow函数:
DwmEnableBlurBehindWindow
DWM_BLURBEHIND bb = {0}; bb.dwFlags = DWM_BB_ENABLE; bb.fEnable = true; bb.hRgnBlur = NULL; DwmEnableBlurBehindWindow(hWnd, &bb);
型在调用glClearColor时,还需要为alpha值指定0。
glClearColor
glClearColor(0.0f,0.0f,0.0f,0.0f);
型此外,在创建OpenGL上下文时,请确保分配Alpha通道。现在你的背景应该是完全透明的。如果保留窗口装饰,则背景将使用Aero模糊外观,您可以使用glClearColor中的alpha值调整透明度级别。
mbjcgjjk4#
这是一个老问题了,但是由于新版本的Windows有合成和支持,正如datenwolf所暗示的那样,对于opengl,我们可以使用一些特殊的酱料来完成这一点。虽然这在DirectX中也很简单(去图...),但微软确实在opengl上下文中添加了合成提示。Yay反垄断恐惧!因此,我们可以让合成引擎理解如何利用opengl上下文,而不是低效的复制到物理内存的操作。所以,你必须创建一个opengl上下文,用pixelformat指定alpha通道,并且它应该使用合成(第82行)。然后,使用DwmApi. h例程启用一个指定了完全无效区域的模糊窗口(第179行),这将不模糊任何内容并使窗口透明。(你需要在窗口类上指定一个黑色+透明的笔刷!奇怪!)然后,你实际上只是使用opengl,因为你习惯使用它。在事件循环中,只要有机会,就可以绘制和交换缓冲区(第201行),并记住启用GL_BLEND!:)请查看/fork 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); }
omhiaaxx5#
如果允许OpenGL窗口分层,这将非常容易。但他们不是,所以你必须去别的东西。你可以做的是创建一个分层的窗口(WS_EX_LAYERED + SetLayeredWindowAttributes()-如果你不知道的话可以谷歌一下)来处理透明度,以及一个隐藏的OpenGL窗口来渲染。将OpenGL场景渲染到屏幕外缓冲区,读回并与分层窗口共享,然后将其bitblt(GDI函数)到分层窗口。对于非常复杂的东西来说,这可能太慢了,但会给予你所要求的效果,并在Windows 2000及以上版本上工作。编辑:在创建实际的屏幕外缓冲区时,帧缓冲区对象(FBO)可能是您的最佳选择。你可以在隐藏的OpenGL窗口上绘制,尽管我想我记得有人发帖说在这方面遇到了麻烦,因为像素所有权-建议使用FBO。你也可以使用像素缓冲区(pbuffers),但这些都有点过时了(打上“遗留”的印记),FBO被认为是实现这一点的现代方式。FBO应该为您提供硬件加速(如果支持),并且本身不会限制您使用特定的OpenGL版本。您需要一个OpenGL上下文来使用它,因此您必须创建隐藏的OpenGL窗口并从那里设置FBO。以下是一些关于FBO的资源:WikipediaFBO的Gamedev article的指南(适用于Mac,但可能会有帮助)
i34xakig6#
我知道这是旧的,但我试图将Xlib解决方案移植到Gtk+。经过大量的研究,我终于做到了,所以我真的很想在这里分享给任何有需要的人。
#include <gtk/gtk.h> #include <gdk/gdkscreen.h> #include <gdk/gdkkeysyms.h> #include <gtk/gtkgl.h> #include <GL/gl.h> #include <GL/glu.h> static gboolean supports_alpha = FALSE; /*** *** Configure the OpenGL framebuffer. ***/ static GdkGLConfig* configure_gl(void) { GdkGLConfig* glconfig; /* Try double-buffered visual */ glconfig = gdk_gl_config_new_by_mode(GDK_GL_MODE_RGBA | GDK_GL_MODE_ALPHA | GDK_GL_MODE_DEPTH | GDK_GL_MODE_DOUBLE); if (glconfig == NULL) { printf("Cannot find the double-buffered visual.\n"); printf("No appropriate OpenGL-capable visual found.\n"); exit(1); } printf("Find GLConfig with alpha channel.\n"); return glconfig; } static void screen_changed(GtkWidget* widget, GdkScreen* old_screen, gpointer userdata) { /* To check if the display supports alpha channels, get the colormap */ GdkScreen* screen = gtk_widget_get_screen(widget); GdkColormap* colormap = gdk_screen_get_rgba_colormap(screen); if (!colormap) { printf("Your screen does not support alpha channels!\n"); colormap = gdk_screen_get_rgb_colormap(screen); supports_alpha = FALSE; } else { printf("Your screen supports alpha channels!\n"); supports_alpha = TRUE; } gtk_widget_set_colormap(widget, colormap); } static gboolean expose(GtkWidget* widget, GdkEventExpose* event, gpointer userdata) { GdkGLContext* glcontext = gtk_widget_get_gl_context(widget); GdkGLDrawable* gldrawable = gtk_widget_get_gl_drawable(widget); if (!gdk_gl_drawable_gl_begin(gldrawable, glcontext)) { return FALSE; } glDrawBuffer(GL_BACK); glClearColor(0.0, 0.0, 0.0, 0.0); glClear(GL_COLOR_BUFFER_BIT); glBegin(GL_QUADS); glColor4f(1.0f, 0.0f, 0.0f, 0.3f); glVertex3f(-0.5f, -0.5f, 0); glVertex3f(+0.5f, -0.5f, 0); glVertex3f(+0.5f, +0.5f, 0); glVertex3f(-0.5f, +0.5f, 0); glEnd(); gdk_gl_drawable_swap_buffers(gldrawable); gdk_gl_drawable_gl_end(gldrawable); return TRUE; } int main(int argc, char** argv) { gtk_init(&argc, &argv); GtkWidget* window = gtk_window_new(GTK_WINDOW_TOPLEVEL); /* Added to config GLConfig */ GdkGLConfig* glconfig = configure_gl(); gtk_widget_set_gl_capability(window, glconfig, NULL, TRUE, GDK_GL_RGBA_TYPE); gtk_window_set_position(GTK_WINDOW(window), GTK_WIN_POS_CENTER); gtk_window_set_default_size(GTK_WINDOW(window), 400, 400); gtk_window_set_title(GTK_WINDOW(window), "Alpha Demo"); g_signal_connect(G_OBJECT(window), "delete-event", gtk_main_quit, NULL); gtk_widget_set_app_paintable(window, TRUE); g_signal_connect(G_OBJECT(window), "expose-event", G_CALLBACK(expose), NULL); g_signal_connect(G_OBJECT(window), "screen-changed", G_CALLBACK(screen_changed), NULL); screen_changed(window, NULL, NULL); gtk_widget_show_all(window); gtk_main(); return 0; }
字符串使用gcc main.c -o mainpkg-config --libs --cflags gtk+-2.0 gtkglext-1.0``编译。在Ubuntu 18.04上测试(除了gtk,您还需要安装libgtkglext1-dev)。
gcc main.c -o main
libgtkglext1-dev
编辑
我将渲染代码从简单的glClear更改为矩形。代码是this question和this question的修改版本。
glClear
的数据
ckx4rj1h7#
你可以将3d场景渲染到pbuffer中,然后使用颜色键将其blit到屏幕上。
qlvxas9a8#
ClanLib游戏SDK可以做到这一点。如果只需要静态透明边框,请使用以下技巧:创建5个窗口AAAAAB#CB#CDDDDDA、B、C、D是分层窗口“#”是主窗口。请参见-http://clanlib.org/wiki/ClanLib_2.2.9_Release_Notes底部的图像
8条答案
按热度按时间iyfamqjs1#
在这个问题上花了一些不成功的赏金来获得一些帮助之后,我终于意识到我感兴趣的问题有多复杂。
完成这项任务的少数人don't share much。在我的研究过程中,我发现了不同的方法来实现我所寻找的。其中最有趣的一个是AeroGL,它使用一种迄今为止没有提到的技术来显示snippets of code,即将图形渲染到device-independent bitmap(DIB)。
要永久关闭此线程,下面的源代码实现了该技术。代码本身是对here应用程序的轻微修改(非常感谢 Andrei Sapronov Y.)。
最终结果如下图所示:
的数据
该代码已在Windows XP(32位)和Windows 8.1(32位)上测试。享受吧
字符串
uqdfh47h2#
由于到目前为止给出的所有答案都只针对Windows,但肯定也有在X11上使用复合窗口管理器进行此操作的需求,为了参考,我将示例代码发布在这里(也可以在https://github.com/datenwolf/codesamples/blob/master/samples/OpenGL/x11argb_opengl/x11argb_opengl.c上找到
字符串
主要的技巧是获得正确的FBConfig。您需要请求alpha通道并测试关联的
XRenderPictFormat
是否存在alpha遮罩。llycmphe3#
我知道这是可能的Windows 7,不确定早期版本。
要删除窗口边框,您需要从窗口中删除
WS_OVERLAPPEDWINDOW
样式并添加WS_POPUP
样式:字符串
要使OpenGL窗口的背景透明,您需要使用
DwmEnableBlurBehindWindow
函数:型
在调用
glClearColor
时,还需要为alpha值指定0。型
此外,在创建OpenGL上下文时,请确保分配Alpha通道。
现在你的背景应该是完全透明的。如果保留窗口装饰,则背景将使用Aero模糊外观,您可以使用
glClearColor
中的alpha值调整透明度级别。mbjcgjjk4#
这是一个老问题了,但是由于新版本的Windows有合成和支持,正如datenwolf所暗示的那样,对于opengl,我们可以使用一些特殊的酱料来完成这一点。虽然这在DirectX中也很简单(去图...),但微软确实在opengl上下文中添加了合成提示。Yay反垄断恐惧!
因此,我们可以让合成引擎理解如何利用opengl上下文,而不是低效的复制到物理内存的操作。
所以,你必须创建一个opengl上下文,用pixelformat指定alpha通道,并且它应该使用合成(第82行)。然后,使用DwmApi. h例程启用一个指定了完全无效区域的模糊窗口(第179行),这将不模糊任何内容并使窗口透明。(你需要在窗口类上指定一个黑色+透明的笔刷!奇怪!)然后,你实际上只是使用opengl,因为你习惯使用它。在事件循环中,只要有机会,就可以绘制和交换缓冲区(第201行),并记住启用GL_BLEND!:)
请查看/fork https://gist.github.com/3644466或仅查看以下基于OP自己的答案的代码片段(您可以将其放在空项目中):
字符串
omhiaaxx5#
如果允许OpenGL窗口分层,这将非常容易。但他们不是,所以你必须去别的东西。
你可以做的是创建一个分层的窗口(WS_EX_LAYERED + SetLayeredWindowAttributes()-如果你不知道的话可以谷歌一下)来处理透明度,以及一个隐藏的OpenGL窗口来渲染。将OpenGL场景渲染到屏幕外缓冲区,读回并与分层窗口共享,然后将其bitblt(GDI函数)到分层窗口。
对于非常复杂的东西来说,这可能太慢了,但会给予你所要求的效果,并在Windows 2000及以上版本上工作。
编辑:在创建实际的屏幕外缓冲区时,帧缓冲区对象(FBO)可能是您的最佳选择。你可以在隐藏的OpenGL窗口上绘制,尽管我想我记得有人发帖说在这方面遇到了麻烦,因为像素所有权-建议使用FBO。你也可以使用像素缓冲区(pbuffers),但这些都有点过时了(打上“遗留”的印记),FBO被认为是实现这一点的现代方式。FBO应该为您提供硬件加速(如果支持),并且本身不会限制您使用特定的OpenGL版本。您需要一个OpenGL上下文来使用它,因此您必须创建隐藏的OpenGL窗口并从那里设置FBO。
以下是一些关于FBO的资源:
Wikipedia
FBO的
Gamedev article的
指南(适用于Mac,但可能会有帮助)
i34xakig6#
我知道这是旧的,但我试图将Xlib解决方案移植到Gtk+。经过大量的研究,我终于做到了,所以我真的很想在这里分享给任何有需要的人。
字符串
使用
gcc main.c -o main
pkg-config --libs --cflags gtk+-2.0 gtkglext-1.0``编译。在Ubuntu 18.04上测试(除了gtk,您还需要安装libgtkglext1-dev
)。编辑
我将渲染代码从简单的
glClear
更改为矩形。代码是this question和this question的修改版本。
的数据
ckx4rj1h7#
你可以将3d场景渲染到pbuffer中,然后使用颜色键将其blit到屏幕上。
qlvxas9a8#
ClanLib游戏SDK可以做到这一点。
如果只需要静态透明边框,请使用以下技巧:
创建5个窗口
AAAAA
B#C
B#C
DDDDD
A、B、C、D是分层窗口
“#”是主窗口。
请参见-http://clanlib.org/wiki/ClanLib_2.2.9_Release_Notes底部的图像