จะสร้างบริบทการแสดงผล OpenGL ที่มีพื้นหลังโปร่งใสได้อย่างไร


101

บริบทการแสดงผลมักจะมีสีทึบบนพื้นหลัง (สีดำหรืออะไรก็ตามดูภาพด้านล่าง):

ข้อความแสดงแทน

ฉันสงสัยว่าเป็นไปได้หรือไม่ที่จะตั้งค่าหน้าต่างโดยไม่มีการตกแต่งและมีพื้นหลังโปร่งใสในขณะที่อนุญาตให้ฉันแสดงสิ่งต่างๆของ OpenGL ได้

สิ่งนี้จะทำให้ภาพลวงตาว่าสามเหลี่ยมลอยอยู่บนหน้าจอ พื้นหลังโปร่งใสควรช่วยให้คุณเห็นเดสก์ท็อปหรือแอปพลิเคชันอื่น ๆ ที่อาจอยู่เบื้องหลัง

คุณช่วยยกตัวอย่างด้วยซอร์สโค้ดได้ไหม

แพลตฟอร์ม: Windows (win32 เท่านั้น)

คำตอบ:


100

หลังจากใช้ชื่อเสียงไปกับเงินรางวัลที่ไม่ประสบความสำเร็จเพื่อขอความช่วยเหลือเกี่ยวกับปัญหานี้ในที่สุดฉันก็รู้ว่าปัญหาที่ฉันสนใจนั้นซับซ้อนเพียงใด

บุคคลไม่กี่คนที่ได้ประสบความสำเร็จงานนี้ไม่ได้ใช้มาก ในระหว่างการวิจัยของฉันฉันพบวิธีต่างๆในการบรรลุสิ่งที่ฉันกำลังมองหา หนึ่งในสิ่งที่น่าสนใจที่สุดคือAeroGLและแสดงตัวอย่างโค้ดโดยใช้เทคนิคที่ยังไม่ได้กล่าวถึงซึ่งกำลังแสดงผลกราฟิกเป็นบิตแมป (DIB) ที่ไม่ขึ้นกับอุปกรณ์

หากต้องการปิดเธรดนี้อย่างถาวรซอร์สโค้ดด้านล่างจะใช้เทคนิคนั้น รหัสนี้เป็นการปรับเปลี่ยนเล็กน้อยของแอปพลิเคชันที่นำเสนอที่นี่ (ขอบคุณ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); 
}

6
ควรบอกว่าเทคนิคนี้ใช้ไม่ได้จริงกับการแสดงผลที่ซับซ้อนและภาพเคลื่อนไหวกราฟิก การคัดลอกข้อมูล GPU ไปยัง RAM สำหรับแต่ละเฟรมมีความต้องการ CPU สูงมากส่งผลให้ FPS ต่ำ ตรวจสอบความคิดเห็นเกี่ยวกับคำตอบนี้: stackoverflow.com/questions/4780756/…
karlphillip

1
โปรดทราบว่าใน Windows Vista และ Windows 7 คุณสามารถบรรลุผลเช่นเดียวกับในการสาธิต x11argb ของฉันด้านล่าง PIXELFORMATDESCRIPTOR รองรับแฟล็กใหม่เพื่อเปิดใช้งานการจัดองค์ประกอบ ฉันยังไม่ได้สร้างการสาธิตสำหรับสิ่งนี้แม้ว่า จะไม่เกิดขึ้นจนถึงเดือนเมษายน แต่เมื่อฉันมีเวลาสำหรับเรื่องนั้นอีกครั้ง
datenwolf

40

เนื่องจากคำตอบทั้งหมดที่ให้มาจึงกำหนดเป้าหมายไปที่ 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;
        }
    }

    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] =  {
    /*  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 ที่ถูกต้อง คุณต้องขอช่องอัลฟาและทดสอบความเกี่ยวข้องXRenderPictFormatว่ามีหน้ากากอัลฟาหรือไม่


6
อู้วววว! เหลือเชื่อ! ฉันรวบรวมด้วย: g++ gl_transparent.cpp -o gl_transparent -lGL -lX11 -lXext -lXrender. สิ่งนี้อาจกลายเป็นวิกิชุมชนถ้าเรายังคงทำสิ่งนั้นอยู่ในทุกวันนี้
karlphillip

@karlphillip: ในที่เก็บ github ของฉันคุณจะพบ makefile และรูปแบบของการสาธิตนี้ที่ใช้ Fragment Shader เพื่อเพิ่มเอฟเฟกต์คลื่น - สำหรับผู้ที่ชื่นชอบ น่าเสียดายที่ไม่สามารถรวม "พื้นหลัง" ลงในเอฟเฟ็กต์เงาได้เนื่องจากพื้นหลังทั้งหมดถูกสร้างขึ้นโดยผู้แต่งหลังจากที่หน้าต่างทั้งหมดวาดเนื้อหาแล้ว
datenwolf

ฉันเข้าใจ. ขอบคุณสำหรับหัวขึ้น.
karlphillip

1
@datenwolf เดิมฉันขอความช่วยเหลือ แต่ฉันประสบความสำเร็จในการแปลงรหัสของคุณเป็น OpenGL ที่ทันสมัย ฉันจะโพสต์วิธีแก้ปัญหาของฉันไว้ที่นี่เพื่อใช้อ้างอิงในอนาคต
syk435

1
ขอบคุณมากสำหรับบทเรียน ฉันต้องการมันแบบไม่มีขอบด้วย ฉันต้องการทำยางรัด (วาดรูปสี่เหลี่ยมผืนผ้าบนหน้าจอ) โดยใช้ opengl แต่ไม่พบตัวอย่าง
kenn

30

ฉันรู้ว่าเป็นไปได้กับ 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);

นอกจากนี้คุณยังจะต้องระบุ 0 glClearColorสำหรับค่าอัลฟาเมื่อโทร

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

นอกจากนี้เมื่อสร้างบริบท OpenGL ของคุณตรวจสอบให้แน่ใจว่าคุณได้จัดสรรช่องอัลฟา

ตอนนี้พื้นหลังของคุณควรโปร่งใสเต็มที่ ถ้าคุณเก็บตกแต่งหน้าต่างแล้วพื้นหลังจะใช้ Aero ดูเบลอและคุณสามารถปรับระดับของความโปร่งใสโดยใช้ค่า alpha glClearColorใน


5
ขอบคุณ แต่ DwmEnableBlurBehindWindow () เป็นส่วนหนึ่งของ DWM ซึ่งไม่ได้อยู่ใน Win32 API โซลูชันนี้ใช้ได้กับ Windows Vista ขึ้นไป
karlphillip

@karlphilip: Pre-Vista Windows: es ไม่มีคอมโพสิตเดสก์ท็อปดังนั้นฉันไม่แน่ใจว่าคุณจะทำได้ดีที่นั่น
Macke

@karlphilip. ขออภัยฉันไม่ได้ใช้หน้าต่าง OpenGL แบบโปร่งใสที่ทำงานร่วมกับ XP เป็นการส่วนตัว แต่ฉันจำได้ว่าเห็นโพสต์ในฟอรัม OpenGL เกี่ยวกับเรื่องนี้ ลองดูผลการค้นหาต่อไปนี้สำหรับข้อมูลเพิ่มเติม: google.com/…
flashk

1
สิ่งนี้มีประโยชน์มาก แต่ฉันต้องการเพิ่มสิ่งต่อไปนี้: สำหรับฉันวิธีการข้างต้นแสดงผลพื้นหลังทั้งหมดด้วยค่าเริ่มต้นของ Win7 เบลอและการสะท้อนแสงปลอม เพื่อกำจัดเบลอและได้รับหน้าต่างโปร่งใส completeley ผมตั้งค่าbb.hRgnBlurพารามิเตอร์CreateRectRgn(0, 0, 1, 1);และการbb.dwFlags DWM_BB_ENABLE | DWM_BB_BLURREGION;สิ่งนี้จะเบลอหนึ่งพิกเซลและแสดงส่วนที่เหลือของหน้าต่าง (ที่ล้างด้วย glClear) ว่าโปร่งใสทั้งหมด
pholz

identifier "DWM_BLURBEHIND" is undefinedเมื่อฉันพยายามนี้ผมได้รับ จำเป็นต้องมีห้องสมุดหรือไม่
Stevoisiak

24

นี่เป็นคำถามเก่า แต่เนื่องจาก Windows เวอร์ชันใหม่กว่ามีการผสมผสานและการสนับสนุนดังคำแนะนำของ datenwolf สำหรับ opengl เราจึงสามารถใช้ซอสพิเศษบางอย่างเพื่อทำสิ่งนี้ได้ แม้ว่า DirectX จะเป็นเรื่องเล็กน้อย (ไปคิด ... ) Microsoft ได้เพิ่มคำแนะนำการประกอบให้กับบริบทของ opengl เย่อต่อต้านความเชื่อมั่น!

ดังนั้นแทนที่จะเป็นการดำเนินการคัดลอกไปยังหน่วยความจำกายภาพที่ไม่มีประสิทธิภาพเราสามารถให้เอนจินการประกอบเพียงแค่เข้าใจวิธีใช้ประโยชน์จากบริบท opengl

ดังนั้นคุณต้องสร้างบริบท opengl ด้วยรูปแบบพิกเซลที่ระบุช่องทางอัลฟาและควรใช้องค์ประกอบ (บรรทัดที่ 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); 
}

4
ใช้งานได้ดีกับ Win 7 เมื่อฉันสร้างขนาดหน้าต่างให้เท่ากับขนาดหน้าจอพื้นหลังจะกลายเป็นสีดำแทนที่จะเป็นแบบโปร่งใส (ราวกับว่า Aero ถือว่าหน้าต่างเป็นแบบเต็มหน้าจอแม้ว่าจะไม่ได้เป็นจริงก็ตาม) ฉันสามารถแก้ไขปัญหานี้ได้โดยทำให้หน้าต่างสูงกว่าหน้าจอ 1 พิกเซลนั่นคือใช้window_x = 0, window_y = -1, window_width = screen_width, window_height = screen_height + 1เป็นค่าที่ส่งผ่านไปยัง CreateWindowEx จากนั้นเรียกใช้glViewport(0, 0, screen_width, screen_height)ตามปกติ
John Mellor

คำตอบที่ยอดเยี่ยม! สิ่งที่ฉันต้องการ คำตอบอื่น ๆ ทั้งหมดแสดงวิธีการวาดไปยังบัฟเฟอร์นอกหน้าจอแล้ว BitBlt () ไปยังบริบทการวาดที่มองเห็นได้ซึ่งช้ามากและใช้ไม่ได้กับแอปพลิเคชันที่จริงจังใด ๆ
Jurlie

10

สิ่งนี้จะง่ายมากถ้าหน้าต่าง OpenGL ได้รับอนุญาตให้เป็นเลเยอร์ แต่ไม่ใช่ดังนั้นคุณจะต้องไปหาอย่างอื่น

สิ่งที่คุณสามารถทำได้คือสร้างหน้าต่างที่มีเลเยอร์ (WS_EX_LAYERED + SetLayeredWindowAttributes () - Google ถ้าคุณไม่รู้จัก) เพื่อจัดการกับความโปร่งใสและหน้าต่าง OpenGL ที่ซ่อนไว้สำหรับการแสดงผล แสดงฉาก OpenGL เป็นบัฟเฟอร์นอกหน้าจออ่านย้อนกลับและแชร์กับหน้าต่างเลเยอร์จากนั้น bitblt (ฟังก์ชัน GDI) ไปยังหน้าต่างเลเยอร์

สิ่งนี้อาจช้าเกินไปสำหรับสิ่งที่ซับซ้อนมาก แต่จะให้เอฟเฟกต์ที่คุณต้องการและทำงานบน Windows 2000 ขึ้นไป

แก้ไข: เมื่อพูดถึงการสร้างบัฟเฟอร์นอกหน้าจอจริง framebuffer objects (FBOs) อาจเป็นทางออกที่ดีที่สุดของคุณ คุณสามารถวาดบนหน้าต่าง OpenGL ที่ซ่อนอยู่ได้แม้ว่าฉันคิดว่าฉันจำได้ว่ามีคนโพสต์เกี่ยวกับปัญหานั้นเนื่องจากความเป็นเจ้าของพิกเซล - แนะนำให้ใช้ FBO คุณยังสามารถใช้บัฟเฟอร์พิกเซล (pbuffers) ได้ แต่สิ่งเหล่านี้ล้าสมัย ("แบบเดิม" ที่ประทับตรา) และ FBO ถือเป็นวิธีที่ทันสมัย FBO ควรให้การเร่งฮาร์ดแวร์แก่คุณ (หากรองรับ) และจะไม่ จำกัด คุณไว้ที่ OpenGL เวอร์ชันเฉพาะ คุณจะต้องมีบริบท OpenGL เพื่อใช้งานดังนั้นคุณจะต้องสร้างหน้าต่าง OpenGL ที่ซ่อนอยู่และตั้งค่า FBO จากที่นั่น

นี่คือแหล่งข้อมูลบางส่วนใน FBO: คู่มือบทความ
Wikipedia
FBO
Gamedev (สำหรับ Mac แต่อาจมีประโยชน์)


สิ่งนี้คล้ายกับที่ฉันแนะนำ แสดงฉาก OpenGL ของคุณไปยังหน่วยความจำ (FBO หรือคล้ายกัน) จากนั้นใช้ glReadPixels เพื่อจัดเก็บลงในวัตถุบิตแมป จากนั้นคุณสามารถเลือกสีโปร่งใสและ bitblt ไปยังหน้าจอโดยใช้ GDI
Giawa

7

ชุดสาธิตที่ยอดเยี่ยมพร้อมแหล่งที่มาที่จะนำคุณไปทีละขั้นตอน

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


การสาธิต "OpenGL Layered Windows" เป็นวิธีที่ดีที่สุดโดยทั่วไปแล้ว pbuffer จะเร็วกว่าการแสดงผลใน DIB โดยตรงมากโดยปกติแล้ว DIB จะใช้ตัวแสดงผลซอฟต์แวร์ที่ pbuffer เร่งความเร็ว
Christopher Lloyd

2

ฉันรู้ว่านี่เก่า แต่ฉันพยายามพอร์ตโซลูชัน 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 main `pkg-config --libs --cflags gtk+-2.0 gtkglext-1.0`. ทดสอบบน Ubuntu 18.04 (นอกเหนือจาก gtk แล้วคุณจะต้องติดตั้งlibgtkglext1-dev)

แก้ไข

ฉันเปลี่ยนรหัสการแสดงผลจากเพียง a glClearเป็นสี่เหลี่ยมผืนผ้า

รหัสเป็นรุ่นที่แก้ไขจากคำถามนี้และคำถามนี้ด้วย

ป้อนคำอธิบายภาพที่นี่


ที่น่าสนใจลิงค์หนึ่งที่คุณแชร์ก็มาจากคำตอบอื่นของฉันเช่นกัน อย่าลืมโหวตทุกอย่าง หากคุณแชร์ภาพหน้าจอของโปรแกรมนี้เพื่อให้เรารู้ว่าหน้าตาเป็นอย่างไรฉันจะโหวตคำตอบนี้
karlphillip

ขออภัยเพราะถึงแม้ว่าฉันจะใช้ stackoverflow เป็นจำนวนมาก (จาก google) แต่ฉันก็ทำรหัสผ่านหายและไม่ได้เข้าสู่ระบบเป็นเวลานาน ฉันจะทำเช่นนั้นในอนาคต ขอบคุณสำหรับคำตอบอื่น ๆ
Wu Zhenwei

และขอบคุณสำหรับคำแนะนำ. ฉันจะพยายามเพิ่มภาพหน้าจอเพื่อปรับปรุง แต่ยังคงเป็นตัวเลือกของคุณเองว่าจะโหวตหรือไม่ @karlphillip
Wu Zhenwei

ภาพหน้าจอนั้นจะเพิ่มมูลค่าให้กับคำตอบของคุณเป็นอย่างมาก
karlphillip


1

SDK เกม ClanLib ทำสิ่งนี้

หากคุณต้องการเพียงเส้นขอบโปร่งใสแบบคงที่ให้ใช้เทคนิคต่อไปนี้:

สร้าง 5 หน้าต่าง

AAAAA

B ### ค

B ### ค

DDDDD

A, B, C, D เป็นหน้าต่างหลายชั้น

"#" คือหน้าต่างหลัก

ดูภาพด้านล่างของ - http://clanlib.org/wiki/ClanLib_2.2.9_Release_Notes


1
ขอบคุณ แต่คำถามเฉพาะถามถึงวิธีการที่จะทำเช่นนี้มีผลใช้ Win32 API เท่านั้น
karlphillip
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.