首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
MCP广场
社区首页 >问答首页 >如何制作透明背景的OpenGL渲染上下文?

如何制作透明背景的OpenGL渲染上下文?
EN

Stack Overflow用户
提问于 2010-10-29 22:47:26
回答 6查看 59.1K关注 0票数 106

渲染上下文通常在背景上具有纯色(黑色或其他颜色,请参见下图):

我想知道是否有可能设置一个窗口,没有装饰和透明的背景,同时允许我在上面渲染OpenGL的东西。

这会给人一种三角形漂浮在屏幕上的错觉。透明背景应允许您看到桌面或可能在其后面的其他应用程序。

你能举例说明一下源代码吗?

平台: Windows (仅限win32)

EN

回答 6

Stack Overflow用户

发布于 2010-10-30 03:07:42

我知道这在Windows7上是可能的,但不确定更早的版本。

要去除窗口边框,您需要从窗口中移除WS_OVERLAPPEDWINDOW样式并添加WS_POPUP样式:

代码语言:javascript
运行
复制
DWORD style = ::GetWindowLong(hWnd, GWL_STYLE);
style &= ~WS_OVERLAPPEDWINDOW;
style |= WS_POPUP;
::SetWindowLong(hWnd, GWL_STYLE, style);

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

代码语言:javascript
运行
复制
DWM_BLURBEHIND bb = {0};
bb.dwFlags = DWM_BB_ENABLE;
bb.fEnable = true;
bb.hRgnBlur = NULL;
DwmEnableBlurBehindWindow(hWnd, &bb);

在调用glClearColor时,还需要将Alpha值指定为0。

代码语言:javascript
运行
复制
glClearColor(0.0f,0.0f,0.0f,0.0f);

此外,在创建OpenGL上下文时,请确保分配了alpha通道。

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

票数 31
EN

Stack Overflow用户

发布于 2012-09-06 05:43:42

这是一个古老的问题,但由于新版本的Windows有合成和对opengl的支持,正如datenwolf所暗示的那样,我们可以使用一些特殊的调料来实现这一点。尽管这对于DirectX来说也是微不足道的(如图所示)微软确实在opengl上下文中添加了合成提示。耶,反垄断的恐惧!

因此,我们可以让合成引擎只了解如何利用opengl上下文,而不是低效的复制到物理内存的操作。

因此,您必须使用指定alpha通道的像素格式创建一个opengl上下文,并且它应该使用合成(第82行)。然后,使用DwmApi.h例程启用一个模糊窗口(第179行),其中指定了一个完全无效的区域,这将模糊任何内容并使窗口保持透明。(您需要在窗口类上指定一个black+transparent笔刷!奇怪!)然后,您实际上只是使用opengl,就像您习惯使用它一样。在事件循环中,只要有机会,您就可以绘制和交换缓冲区(第201行),并记住启用GL_BLEND!:)

请查看/fork https://gist.github.com/3644466,或者只查看基于OP自己的答案的以下代码片段,而不是使用此技术(您可以将其放在一个空项目中):

代码语言:javascript
运行
复制
#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); 
}
票数 26
EN

Stack Overflow用户

发布于 2010-11-02 08:36:09

如果允许对OpenGL窗口进行分层,这将非常容易。但他们不是,所以你必须去找其他的东西。

你可以做的就是创建一个分层窗口(WS_EX_LAYERED + SetLayeredWindowAttributes() --如果你不知道的话就用Google 'em )来处理透明度,和一个隐藏的OpenGL窗口来渲染。将OpenGL场景渲染到离屏缓冲区,读回并与分层窗口共享,然后将其比特(GDI函数)渲染到分层窗口。

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

编辑:在创建实际的屏幕外缓冲区时,帧缓冲区对象(FBO)可能是最好的选择。你可以直接在隐藏的OpenGL窗口上绘图,尽管我记得有人发帖说因为像素所有权的原因而遇到了麻烦--推荐使用FBO。您也可以使用像素缓冲区(Pbuffer),但这些是一种过时的(标记为“遗留”),FBO被认为是现代的方式来做到这一点。FBO应该为您提供硬件加速(如果支持),而不会限制您特定的OpenGL版本。您需要一个FBO上下文才能使用它,因此您必须创建隐藏的OpenGL窗口并从那里设置OpenGL。

以下是关于FBO的一些资源:

Wikipedia

FBO

Gamedev article

Guide (适用于mac,但可能会有所帮助)

票数 10
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/4052940

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档