Làm thế nào để tạo bối cảnh kết xuất OpenGL với nền trong suốt?


99

Các bối cảnh kết xuất thường có một màu đồng nhất trên nền (màu đen hoặc bất kỳ màu gì, hãy xem hình ảnh bên dưới):

văn bản thay thế

Tôi đang tự hỏi liệu có thể thiết lập một cửa sổ, không có trang trí VÀ với nền trong suốt, trong khi cho phép tôi hiển thị nội dung OpenGL trên đó hay không.

Điều này sẽ tạo ra ảo giác rằng hình tam giác đang nổi trên màn hình. Nền trong suốt sẽ cho phép bạn nhìn thấy màn hình nền hoặc các ứng dụng khác có thể nằm sau nó.

Bạn có thể vui lòng ví dụ với mã nguồn?

Nền tảng: Windows (chỉ win32)

Câu trả lời:


98

Sau khi dành một chút danh tiếng cho một cuộc truy tìm tiền thưởng không thành công để nhận được một số trợ giúp về vấn đề này, cuối cùng tôi nhận ra rằng vấn đề mà tôi quan tâm phức tạp đến mức nào.

Số ít cá nhân đã hoàn thành nhiệm vụ này không chia sẻ nhiều . Trong quá trình nghiên cứu, tôi đã tìm ra những cách khác nhau để đạt được những gì tôi đang tìm kiếm. Một trong những ứng dụng thú vị nhất là AeroGL , và nó hiển thị các đoạn mã bằng cách sử dụng một kỹ thuật chưa được đề cập cho đến nay, đó là kết xuất đồ họa thành bitmap độc lập với thiết bị (DIB).

Để đóng chuỗi này vĩnh viễn, mã nguồn bên dưới thực hiện kỹ thuật đó. Bản thân mã là một sửa đổi nhỏ của một ứng dụng được trình bày ở đây (rất cảm ơn Andrei Sapronov Y. ).

Kết quả cuối cùng có thể được nhìn thấy trong hình ảnh dưới đây:

nhập mô tả hình ảnh ở đây

Mã đã được thử nghiệm trên Windows XP (32-bit) và Windows 8.1 (32-bit). Thưởng thức!

#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
Điều đáng nói là kỹ thuật này không thực tế cho các hoạt ảnh đồ họa và dựng hình phức tạp. Việc sao chép dữ liệu GPU vào RAM cho mỗi khung hình đòi hỏi rất nhiều trên CPU, dẫn đến FPS thấp. Kiểm tra các nhận xét về câu trả lời này: stackoverflow.com/questions/4780756/…
karlphillip

1
Lưu ý rằng trong Windows Vista và Windows 7, bạn có thể đạt được hiệu ứng khá giống như trong bản demo x11argb của tôi bên dưới. PIXELFORMATDESCRIPTOR hỗ trợ một cờ mới để cho phép sáng tác. Tuy nhiên, tôi vẫn chưa tạo bản demo cho điều này. Tuy nhiên, sẽ không xảy ra cho đến tháng Tư, khi tôi có thời gian cho việc đó một lần nữa.
datenwolf

38

Vì tất cả các câu trả lời được đưa ra cho đến nay chỉ nhắm mục tiêu đến Windows, nhưng chắc chắn cũng có nhu cầu thực hiện điều này trên X11 với trình quản lý cửa sổ tổng hợp, để tham khảo, tôi đăng mã ví dụ của mình tại đây (cũng có thể tìm thấy tại 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;
}

Bí quyết chính là nhận được FBConfig phù hợp. Bạn cần yêu cầu kênh alpha kiểm tra liên kết XRenderPictFormatđể biết sự hiện diện của mặt nạ alpha.


6
Uowwww! Đáng kinh ngạc! Tôi biên dịch nó với: g++ gl_transparent.cpp -o gl_transparent -lGL -lX11 -lXext -lXrender. Đây có thể trở thành một wiki cộng đồng, nếu chúng ta vẫn làm những việc như vậy ngày nay.
karlphillip

@karlphillip: Trong kho lưu trữ github của tôi, bạn đã tìm thấy một tệp trang. Và một biến thể của bản trình diễn này sử dụng công cụ đổ bóng phân mảnh để thêm hiệu ứng sóng - chỉ dành cho người khó nhìn. Thật không may, không thể kết hợp "nền" vào hiệu ứng đổ bóng, bởi vì toàn bộ nền chỉ được tạo bởi trình soạn thảo sau khi tất cả các cửa sổ đã vẽ nội dung của chúng.
datenwolf

Tôi hiểu. Cảm ơn cho những người đứng đầu lên.
karlphillip

1
@datenwolf Ban đầu tôi đang yêu cầu hỗ trợ nhưng tôi đã thành công trong việc chuyển đổi mã của bạn sang OpenGL hiện đại. Tôi sẽ đăng giải pháp của tôi ở đây một chút để tham khảo trong tương lai.
syk435

1
Cảm ơn rất nhiều cho các hướng dẫn. Tôi cũng muốn nó không có biên giới. Tôi muốn tạo một dây chun (vẽ hình chữ nhật trên màn hình) bằng opengl nhưng tôi không tìm thấy ví dụ nào về nó.
kenn

30

Tôi biết điều này có thể xảy ra với Windows 7, không chắc chắn về các phiên bản trước đó.

Để loại bỏ viền cửa sổ, bạn cần xóa WS_OVERLAPPEDWINDOWkiểu khỏi cửa sổ và thêm WS_POPUPkiểu:

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

Để làm cho nền của cửa sổ OpenGL trong suốt, bạn sẽ cần sử dụng DwmEnableBlurBehindWindowhàm:

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

Bạn cũng sẽ cần chỉ định 0 cho giá trị alpha khi gọi glClearColor.

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

Ngoài ra, khi tạo ngữ cảnh OpenGL của bạn, hãy đảm bảo bạn phân bổ kênh alpha.

Bây giờ nền của bạn sẽ hoàn toàn trong suốt. Nếu bạn giữ các trang trí cửa sổ, thì nền sẽ sử dụng giao diện Aero mờ và bạn có thể điều chỉnh mức độ trong suốt bằng cách sử dụng giá trị alpha trong glClearColor.


5
Cảm ơn bạn, nhưng DwmEnableBlurBehindWindow () là một phần của DWM, không thuộc API Win32. Giải pháp này hoạt động cho Windows Vista trở lên.
karlphillip

@karlphilip: Windows trước Vista: không có tính năng tổng hợp màn hình, vì vậy tôi không chắc bạn có thể làm điều đó tốt ở đó.
Macke

@karlphilip. Xin lỗi, cá nhân tôi chưa nhận được cửa sổ OpenGL trong suốt hoạt động với XP, nhưng tôi nhớ đã xem các bài đăng trên diễn đàn OpenGL về nó. Thử xem qua các kết quả tìm kiếm sau để biết thêm thông tin: google.com/…
flashk

1
Điều này thực sự hữu ích, nhưng tôi muốn thêm những điều sau: Đối với tôi, phương pháp trên đã hiển thị tất cả nền với độ mờ mặc định của Win7 và phản xạ ánh sáng giả. Để loại bỏ mờ và có được một cửa sổ trong suốt hoàn chỉnh, tôi đặt bb.hRgnBlurthông số thành CreateRectRgn(0, 0, 1, 1);bb.dwFlagsthành DWM_BB_ENABLE | DWM_BB_BLURREGION;. Điều này sẽ làm mờ chính xác một pixel và hiển thị phần còn lại của cửa sổ (nơi được xóa bằng glClear) là hoàn toàn trong suốt.
pholz

Khi tôi thử điều này, tôi nhận được identifier "DWM_BLURBEHIND" is undefined. Có thư viện nào tôi cần đưa vào không?
Stevoisiak

22

Đây là một câu hỏi cũ, nhưng vì các phiên bản Windows mới hơn có tính năng tổng hợp và hỗ trợ, như datenwolf gợi ý, đối với opengl, chúng tôi có thể sử dụng một số loại nước sốt đặc biệt đó để thực hiện điều này. Mặc dù nó cũng không đáng kể với DirectX (xem hình ...) Microsoft đã thêm các gợi ý tổng hợp vào các ngữ cảnh opengl. Yay nỗi sợ hãi chống lại niềm tin!

Vì vậy, thay vì một hành động sao chép sang bộ nhớ vật lý không hiệu quả, chúng ta có thể có công cụ tổng hợp chỉ cần hiểu cách sử dụng ngữ cảnh opengl.

Vì vậy, bạn phải tạo ngữ cảnh opengl với pixelformat chỉ định kênh alpha và kênh đó sẽ sử dụng thành phần (dòng 82). Sau đó, bạn sử dụng quy trình DwmApi.h để kích hoạt một cửa sổ bị mờ (dòng 179) với một vùng hoàn toàn không hợp lệ được chỉ định, vùng này sẽ không làm mờ và để cửa sổ trong suốt. (Bạn cần chỉ định một bàn chải màu đen + trong suốt trên lớp cửa sổ! Thật kỳ lạ!) Sau đó, bạn thực sự chỉ sử dụng opengl như bạn đã quen sử dụng nó. Trong vòng lặp sự kiện, mỗi khi có cơ hội, bạn chỉ cần vẽ và hoán đổi bộ đệm (dòng 201) và nhớ bật GL_BLEND! :)

Vui lòng xem lại / fork https://gist.github.com/3644466 hoặc chỉ xem đoạn mã sau dựa trên câu trả lời của chính OP bằng kỹ thuật này thay thế (bạn chỉ có thể thực hiện đoạn mã này trong một dự án trống):

#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
Hoạt động tuyệt vời trên Win 7. Khi tôi đặt kích thước cửa sổ chính xác bằng kích thước màn hình, nền trở thành màu đen thay vì trong suốt (như thể Aero giả định cửa sổ là toàn màn hình, mặc dù nó không thực sự). Tôi đã có thể giải quyết vấn đề này bằng cách làm cho cửa sổ cao hơn màn hình 1 pixel, tức là sử dụng window_x = 0, window_y = -1, window_width = screen_width, window_height = screen_height + 1làm các giá trị được chuyển đến CreateWindowEx, sau đó gọi glViewport(0, 0, screen_width, screen_height)như bình thường.
John Mellor

Câu trả lời tuyệt vời! Chỉ chính xác những gì tôi cần. Tất cả các câu trả lời khác cho thấy cách tiếp cận của việc vẽ vào một bộ đệm ngoài màn hình và sau đó BitBlt () nó vào một bối cảnh vẽ hiển thị, nó siêu chậm và không hoạt động đối với bất kỳ ứng dụng nghiêm trọng nào.
Jurlie

10

Điều này sẽ rất dễ dàng nếu các cửa sổ OpenGL được phép phân lớp. Nhưng chúng không phải vậy, vì vậy bạn sẽ phải tìm kiếm thứ khác.

Những gì bạn có thể làm là tạo một cửa sổ nhiều lớp (WS_EX_LAYERED + SetLayeredWindowAttributes () - của Google nếu bạn không biết chúng) để xử lý độ trong suốt và một cửa sổ OpenGL ẩn để hiển thị. Kết xuất cảnh OpenGL vào bộ đệm ngoài màn hình, đọc lại và chia sẻ nó với cửa sổ phân lớp, sau đó bitblt (chức năng GDI) nó vào cửa sổ phân lớp.

Điều này có thể quá chậm đối với những thứ rất phức tạp, nhưng sẽ mang lại cho bạn hiệu ứng mà bạn đang yêu cầu và hoạt động trên Windows 2000 trở lên.

CHỈNH SỬA: Khi nói đến việc tạo bộ đệm ngoài màn hình thực tế, các đối tượng bộ đệm khung (FBO) có lẽ là lựa chọn tốt nhất của bạn. Bạn chỉ có thể vẽ trên cửa sổ OpenGL ẩn, mặc dù tôi nghĩ rằng tôi nhớ ai đó đã đăng bài về việc gặp rắc rối với điều đó, vì quyền sở hữu pixel - FBO được khuyến khích. Bạn cũng có thể sử dụng bộ đệm pixel (bộ đệm), nhưng đây là loại lỗi thời ("di sản" được đóng dấu) và FBO được coi là cách hiện đại để làm điều này. FBO sẽ cung cấp cho bạn khả năng tăng tốc phần cứng (nếu được hỗ trợ) và bản thân nó sẽ không giới hạn bạn trong một phiên bản OpenGL cụ thể. Bạn sẽ cần một ngữ cảnh OpenGL để sử dụng nó, vì vậy bạn sẽ phải tạo cửa sổ OpenGL ẩn đó và thiết lập FBO từ đó.

Dưới đây là một số tài nguyên trên FBOs: Hướng dẫn bài viết
Wikipedia
FBO
Gamedev (dành cho mac, nhưng có thể hữu ích)


Điều này tương tự như những gì tôi muốn đề xuất. Kết xuất cảnh OpenGL của bạn vào bộ nhớ (FBO hoặc tương tự) và sau đó sử dụng glReadPixels để lưu trữ thành một đối tượng bitmap. Sau đó, bạn có thể chọn màu trong suốt của mình và bitblt nó vào màn hình bằng GDI.
Giawa

7

tập hợp các bản trình diễn tuyệt vời với nguồn hướng dẫn bạn từng bước:

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


Bản demo "OpenGL Layered Windows" về cơ bản là cách tốt nhất để làm điều đó, một bộ đệm nhanh hơn nhiều so với hiển thị trực tiếp vào DIB .DIB thường sử dụng trình kết xuất phần mềm nơi bộ đệm được tăng tốc
Christopher Lloyd

2

Tôi biết điều này đã cũ, nhưng tôi đã cố gắng chuyển giải pháp Xlib sang Gtk +. Sau rất nhiều nghiên cứu cuối cùng mình cũng làm được nên mình rất muốn chia sẻ lên đây cho ai có nhu cầu.

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

Tổng hợp với gcc main.c -o main `pkg-config --libs --cflags gtk+-2.0 gtkglext-1.0`. Đã thử nghiệm trên Ubuntu 18.04 (ngoài gtk, bạn sẽ cần phải cài đặt libgtkglext1-dev).

BIÊN TẬP

Tôi đã thay đổi mã kết xuất từ ​​đơn giản là glClearmột hình chữ nhật.

Mã là một phiên bản sửa đổi từ câu hỏi này và cũng là câu hỏi này .

nhập mô tả hình ảnh ở đây


Thật thú vị, một trong những liên kết bạn đã chia sẻ cũng là từ một câu trả lời khác của tôi. Hãy chắc chắn để bỏ phiếu tất cả mọi thứ. Nếu bạn chia sẻ ảnh chụp màn hình của chương trình này đang chạy để chúng tôi biết nó trông như thế nào, tôi sẽ bỏ phiếu cho câu trả lời này.
karlphillip

Ồ xin lỗi vì mặc dù mình sử dụng stackoverflow nhiều (từ google) nhưng mình bị mất mật khẩu và chưa đăng nhập được lâu. Tôi sẽ làm như vậy trong tương lai. Cũng cảm ơn câu trả lời khác.
Wu Zhenwei

Và cảm ơn vì những lời khuyên. Tôi sẽ cố gắng thêm ảnh chụp màn hình để cải thiện nhưng đó vẫn là lựa chọn của riêng bạn cho dù bạn có bỏ phiếu hay không. @karlphillip
Wu Zhenwei

Ảnh chụp màn hình đó sẽ thêm rất nhiều giá trị cho câu trả lời của bạn.
karlphillip

1

Bạn có thể kết xuất cảnh 3D thành một bộ đệm và chuyển nó lên màn hình bằng phím màu.


1

SDK trò chơi ClanLib thực hiện điều này.

Nếu bạn chỉ yêu cầu một đường viền trong suốt tĩnh, hãy sử dụng kỹ thuật sau:

Tạo 5 cửa sổ

AAAAA

B ### C

B ### C

DDDDD

A, B, C, D là các cửa sổ nhiều lớp

"#" là cửa sổ chính.

Xem những hình ảnh ở cuối - http://clanlib.org/wiki/ClanLib_2.2.9_Release_Notes


1
Cảm ơn, nhưng câu hỏi đặc biệt hỏi làm thế nào để làm hiệu ứng này sử dụng Win32 API chỉ .
karlphillip,
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.