투명 배경을 사용하여 OpenGL 렌더링 컨텍스트를 만드는 방법
렌더링 컨텍스트의 배경은 보통 단색입니다(검은색이든 뭐든 아래 이미지 참조).
OpenGL을 렌더링하면서 데코레이션 없이 투명 배경의 창을 셋업할 수 있는지 궁금합니다.
이렇게 하면 화면에 삼각형이 떠 있는 것 같은 착각을 하게 됩니다.투명 배경에서 바탕 화면이나 그 뒤에 있을 수 있는 다른 응용 프로그램을 볼 수 있어야 합니다.
소스코드를 예로 들어주시겠습니까?
플랫폼: Windows (win32 한정)
이 문제에 대한 도움을 얻기 위해 성공적이지 못한 장려금에 약간의 평판을 쓴 후, 나는 마침내 내가 관심 있는 문제가 얼마나 복잡한지 깨달았다.
이 일을 해낸 몇 안 되는 사람들은 별로 공유하지 않는다.연구 중에 나는 내가 찾던 것을 성취하기 위한 다른 방법들을 찾아냈다.가장 흥미로운 것 중 하나는 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);
}
지금까지의 회답은 모두 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);
XFree(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
알파 마스크의 존재에 대해서요.
Windows 7 에서는 가능한 일이지만, 이전 버전에서는 확실하지 않습니다.
창 테두리를 합니다.WS_OVERLAPPEDWINDOW
에 있는 WS_POPUP
예:
DWORD style = ::GetWindowLong(hWnd, GWL_STYLE);
style &= ~WS_OVERLAPPEDWINDOW;
style |= WS_POPUP;
::SetWindowLong(hWnd, GWL_STYLE, style);
하게 하려면 해야 .DwmEnableBlurBehindWindow
★★★★
DWM_BLURBEHIND bb = {0};
bb.dwFlags = DWM_BB_ENABLE;
bb.fEnable = true;
bb.hRgnBlur = NULL;
DwmEnableBlurBehindWindow(hWnd, &bb);
, 0 을 호출할 때는, 에 0 을 .glClearColor
.
glClearColor(0.0f,0.0f,0.0f,0.0f);
또한 OpenGL 컨텍스트를 생성할 때는 알파 채널을 할당해야 합니다.
이제 배경이 완전히 투명해야 합니다. 룩이 되며 Aero의 할 수 .glClearColor
.
이것은 오래된 질문이지만, 새로운 버전의 Windows에는 데이터 울프의 힌트로 opengl에 대한 컴포지팅과 지원이 있기 때문에 이를 위해 특별한 소스를 사용할 수 있습니다.DirectX(go figure...)도 사소한 것이지만 마이크로소프트는 opengl 컨텍스트에 합성 힌트를 추가했다.반독점 공포!
따라서 비효율적인 물리적 메모리 복사 작업이 아니라 컴포지팅 엔진이 opengl 컨텍스트를 사용하는 방법만 이해하도록 할 수 있습니다.
따라서 알파 채널을 지정하고 합성(line 82)을 사용해야 하는 픽셀 형식을 사용하여 Opengl 컨텍스트를 만들어야 합니다.그런 다음 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);
}
OpenGL 창을 레이어화 할 수 있으면 매우 간단합니다.하지만 그렇지 않으니 다른 걸로 가셔야 할 겁니다.
투과성을 처리하는 계층형 창(WS_EX_LAYERED + SetLayered WindowAttributes() - 모르는 경우 Google 'em's)과 렌더링을 위한 숨겨진 OpenGL 창을 만듭니다.OpenGL 장면을 화면 밖의 버퍼로 렌더링하고 다시 읽어 계층화된 창과 공유한 다음 계층화된 창으로 비트블렛(GDI 기능)을 렌더링합니다.
이 방법은 매우 복잡한 작업에는 너무 느릴 수 있지만, 원하는 효과를 얻을 수 있으며 Windows 2000 이상에서 작동합니다.
편집: 실제 오프스크린 버퍼 작성에 관해서는 프레임 버퍼 오브젝트(FBO)를 사용하는 것이 가장 좋습니다.숨겨진 OpenGL 창에 그림을 그리면 됩니다만, 누군가 문제가 생겼다고 하는 글을 올린 것 같습니다만, 픽셀의 소유권 때문에 FBO를 추천합니다.픽셀 버퍼(퍼퍼퍼)를 사용할 수도 있지만, 이것들은 구식(「레거시」라고 찍힌 것)이기 때문에, FBO는 이것을 실현하는 최신의 방법으로 여겨지고 있습니다.FBO는 하드웨어 액셀러레이션을 제공합니다(지원되는 경우).또한 특정 OpenGL 버전으로 한정되지 않습니다.사용하려면 OpenGL 컨텍스트가 필요하므로 숨겨진 OpenGL 창을 만들고 거기에서 FBO를 설정해야 합니다.
다음은 FBO에 대한 몇 가지 리소스입니다.
위키백과
FBO
가메데프 기사
가이드(Mac용이지만 도움이 될 수 있음)
단계별로 설명하는 소스를 포함한 일련의 데모:
http://www.dhpoware.com/demos/index.html
오래된 것은 알지만 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
).
편집
렌더링 코드를 단순하게 변경했습니다.glClear
직사각형으로.
3d 장면을 pbuffer로 렌더링하고 컬러 키를 사용하여 화면에 블릿할 수 있습니다.
ClanLib 게임 SDK는 이것을 합니다.
정적 투과 테두리만 필요한 경우 다음 방법을 사용합니다.
5개의 창을 만듭니다.
아
B###C
B###C
Ddddd.
A,B,C,D는 레이어드 윈도
메인 창은 # 입니다.
아래쪽에 있는 이미지를 참조하십시오.http://clanlib.org/wiki/ClanLib_2.2.9_Release_Notes
언급URL : https://stackoverflow.com/questions/4052940/how-to-make-an-opengl-rendering-context-with-transparent-background
'sourcecode' 카테고리의 다른 글
"v[0] = name-of-module"이 일반적인 표준입니까? 아니면 일반적인 규약입니까? (0) | 2022.08.01 |
---|---|
gdb에서 백슬래시 이스케이프를 표시하지 않고 늘 종단 문자열과 줄 바꿈을 인쇄하려면 어떻게 해야 합니까? (0) | 2022.08.01 |
Recyserview가 CreateView를 호출하지 않음홀더 (0) | 2022.08.01 |
유닛 테스트 VueJS 구성 요소에서 Vuex 오류 발생 (0) | 2022.07.31 |
이미지를 업로드할 때 vue 구성 요소에서 이미지를 자동으로 업데이트하려면 어떻게 해야 합니까? (0) | 2022.07.31 |