使透明度不显示什么是在opengl与c++的窗口后面

Make transparency not show what is behind the window in opengl with c++

本文关键字:c++ 窗口 opengl 透明度 显示 什么      更新时间:2023-10-16

我正在用c++在opengl中制作二维图像,并且我遇到了一个有趣的问题。每当我尝试在图像上绘制部分透明的多边形时,它都会使多边形所在的窗口本身部分透明。例如,当我运行程序(这是我不想要的)时,我可以看到我的窗口后面的任何东西(例如我的代码)。我还可以看到多边形后面的图像(我确实想要)。有什么方法可以关闭"透明窗口"行为吗?我把我认为相关的部分代码包括在下面:

glClearColor(0.0f, 0.0f, 0.0f, 0.0f); // I have tried 1.0f for the alpha value too
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
glHint(GL_LINE_SMOOTH_HINT, GL_NICEST);
glHint(GL_POLYGON_SMOOTH_HINT, GL_NICEST);
glEnable(GL_BLEND);
glEnable(GL_LINE_SMOOTH);
glEnable(GL_POLYGON_SMOOTH);
glPolygonMode (GL_FRONT_AND_BACK, GL_FILL);
glHint(GL_POINT_SMOOTH_HINT, GL_FASTEST);
glDisable(GL_POINT_SMOOTH);
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
glMatrixMode (GL_MODELVIEW);
glLoadIdentity ();
    // other code to draw my opaque "background" object
    // Draw my partially transparent quad (note: this is where the window itself becomes partially transparent)
glBegin(GL_QUADS); // Begin drawing quads
    glColor4f(1.0,1.0,1.0,0.5); // Make a white quad with .5 alpha
    glVertex2f(-0.5, 0.5);
    glVertex2f(0.5, .05);
    glVertex2f(0.5, -0.5);
    glVertex2f(-0.5, -0.5);
    glEnd();

其他相关信息:

  • 我正在运行CentOS 6
  • 我对opengl相当陌生,并且在之前的开发人员之后正在编写代码,所以我可能会错过一些微不足道的东西
  • 正在使用X Windows系统

下面是X窗口创建代码进一步调试,问题很可能在这里而不是上面的opengl代码。

/*  The simplest possible Linux OpenGL program? Maybe...
 Modification for creating a RGBA window (transparency with compositors)
 by Wolfgang 'datenwolf' Draxinger
 (c) 2002 by FTB. See me in comp.graphics.api.opengl
 (c) 2011 Wolfgang Draxinger. See me in comp.graphics.api.opengl and on StackOverflow
 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.
 --
 <___/>
 / O O 
 _____/  FTB.
 --
 datenwolf
 ------------------------------------------------------------------------*/
static void createTheWindow() {
XEvent event;
int x, y, attr_mask;
XSizeHints hints;
XWMHints *StartupState;
XTextProperty textprop;
XSetWindowAttributes attr;
static char *title = "Fix me";
/* Connect to the X server */
Xdisplay = XOpenDisplay(NULL);
if (!Xdisplay)
{
    fatalError("Couldn't connect to X servern");
}
Xscreen = DefaultScreen(Xdisplay);
Xroot = RootWindow(Xdisplay, Xscreen) ;
fbconfigs = glXChooseFBConfig(Xdisplay, Xscreen, VisData, &numfbconfigs);
for (int i = 0; i < numfbconfigs; i++)
{
    visual = (XVisualInfo_CPP*) glXGetVisualFromFBConfig(Xdisplay,
            fbconfigs[i]);
    if (!visual)
        continue;
    pictFormat = XRenderFindVisualFormat(Xdisplay, visual->visual);
    if (!pictFormat)
        continue;
    if (pictFormat->direct.alphaMask > 0)
    {
        fbconfig = fbconfigs[i];
        break;
    }
}
/* Create a colormap - only needed on some X clients, eg. IRIX */
cmap = XCreateColormap(Xdisplay, Xroot, visual->visual, AllocNone);
/* Prepare the attributes for our window */
attr.colormap = cmap;
attr.border_pixel = 0;
attr.event_mask = StructureNotifyMask | EnterWindowMask | LeaveWindowMask
        | ExposureMask | ButtonPressMask | ButtonReleaseMask
        | OwnerGrabButtonMask | KeyPressMask | KeyReleaseMask;
attr.background_pixmap = None;
attr_mask = CWBackPixmap | CWColormap | CWBorderPixel | CWEventMask; /* What's in the attr data */
width = DisplayWidth(Xdisplay, DefaultScreen(Xdisplay)) ;
height = DisplayHeight(Xdisplay, DefaultScreen(Xdisplay)) ;
x = width / 2, y = height / 2;
// x=0, y=10;
/* Create the window */
attr.do_not_propagate_mask = NoEventMask;
WindowHandle = XCreateWindow(Xdisplay, /* Screen */
Xroot, /* Parent */
x, y, width, height,/* Position */
1,/* Border */
visual->depth,/* Color depth*/
InputOutput,/* klass */
visual->visual,/* Visual */
attr_mask, &attr);/* Attributes*/
if (!WindowHandle)
{
    fatalError("Couldn't create the windown");
}
/* Configure it...  (ok, ok, this next bit isn't "minimal") */
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;
StartupState = XAllocWMHints();
StartupState->initial_state = NormalState;
StartupState->flags = StateHint;
XSetWMProperties(Xdisplay, WindowHandle, &textprop, &textprop,/* Window title/icon title*/
NULL, 0,/* Argv[], argc for program*/
&hints, /* Start position/size*/
StartupState,/* Iconised/not flag   */
NULL);
XFree(StartupState);
/* Open it, wait for it to appear */
int event_base, error_base = 0;
XMapWindow(Xdisplay, WindowHandle);
//   }
XIfEvent(Xdisplay, &event, WaitForMapNotify, (char*) &WindowHandle);
/* Set the kill atom so we get a message when the user tries to close the window */
if ((del_atom = XInternAtom(Xdisplay, "WM_DELETE_WINDOW", 0)) != None)
{
    XSetWMProtocols(Xdisplay, WindowHandle, &del_atom, 1);
}
}
以下是VisData的设置:
static int VisData[] = { GLX_RENDER_TYPE, GLX_RGBA_BIT, GLX_DRAWABLE_TYPE,
    GLX_WINDOW_BIT, GLX_DOUBLEBUFFER, True, GLX_RED_SIZE, 1, GLX_GREEN_SIZE,
    1, GLX_BLUE_SIZE, 1, GLX_ALPHA_SIZE, 1, GLX_DEPTH_SIZE, 1,
    None
};

下面是创建渲染上下文的地方:

static void createTheRenderContext() {
/* See if we can do OpenGL on this visual */
int dummy;
if (!glXQueryExtension(Xdisplay, &dummy, &dummy))
{
    fatalError("OpenGL not supported by X servern");
}
/* Create the OpenGL rendering context */
RenderContext = glXCreateNewContext(Xdisplay, fbconfig, GLX_RGBA_TYPE, 0,
        True);
if (!RenderContext)
{
    fatalError("Failed to create a GL contextn");
}
GLXWindowHandle = glXCreateWindow(Xdisplay, fbconfig, WindowHandle, NULL);
/* Make it current */
if (!glXMakeContextCurrent(Xdisplay, GLXWindowHandle, GLXWindowHandle,
        RenderContext))
{
    fatalError("glXMakeCurrent failed for windown");
}
}

棘轮畸形建议(Windows中的Aero Glass效果)不是偶然发生的,因为必须手动启用DWM透明度才能发生。

然而,在X11/GLX中,最终有一个默认Alpha通道的视觉模式是完全可能的。如果你想获得一个有或没有alpha通道的窗口,代码会比大多数工具包更复杂一些。

你正在使用的代码看起来非常熟悉。具体来说,它似乎源于我写的一个关于如何创建一个透明窗口的代码示例(您可以看到这是怎么回事),即以下代码:

https://github.com/datenwolf/codesamples/blob/master/samples/OpenGL/x11argb_opengl/x11argb_opengl.c

关键序列如下:

   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;
    }
}

它所做的是,它选择一个X11 Visual,它匹配先前选择的FBConfig之一,也包含一个alpha蒙版。

如果我不得不打赌,我怀疑你传递给glXChooseFBConfigVisData数组没有指定alpha通道。所以发生的是,你可能最终得到一个有X11 alpha蒙版的窗口,但不是OpenGL可以访问的alpha通道。

由于我从未打算将该代码用于没有alpha通道的窗口,因此如果VisData确实选择alpha通道,则该代码只做最初打算的事情。

你现在有两个选择:

  • 实施互补测试if(pict_format->direct.alphaMask == 0 && no_alpha_in(VisData)) break;

  • 在VisData中选择alpha通道,并使用OpenGL glClearColor(…,…,…,1.0f);将alpha通道清除为1.0

这不是opengl的问题,而是您正在创建的窗口类型的问题。我怀疑你运行的窗口管理器支持透明效果。无论哪种方式,可能发生的是,当你渲染透明多边形时,窗口画布以一些alpha结束,你的窗口管理器假设你想要透明的背景。关闭窗口管理器的所有高级效果来检查。

我不熟悉使用xlib创建窗口的代码,但它可能与您正在创建的窗口类型有关。