Ventana parcialmente transparente OpenGL / Win32 - c ++, winapi, opengl

He leído todas las preguntas existentes sobre este tema complicado (nicho), pero estoy atascado. Tengo una ventana Win32 con un contexto OpenGL. Quiero que mi ventana sea parcialmente transparente.

Mi resultado hasta ahora es que la totalidad della ventana es transparente. Solo quiero que el área negra sea transparente, de modo que pueda dibujar algunos objetos 3D y se verán como si vinieran de la ventana.

enter image description here

Primero, en mi clase de ventana, configuré hbrBackground en negro.

Windows::WindowClass windowClass;
windowClass.cbSize = sizeof(Windows::WindowClass);
windowClass.style = Windows::CS_VREDRAW | Windows::CS_HREDRAW;
windowClass.lpfnWndProc = WndProc;
windowClass.cbClsExtra = 0;
windowClass.cbWndExtra = 0;
windowClass.hInstance = moduleHandle;
windowClass.hIcon = Windows::LoadIcon(0u, (X*)Windows::IDI_QUESTION);
windowClass.hCursor = Windows::LoadCursor(0u, (X*)Windows::IDC_ARROW);
windowClass.hbrBackground = Windows::CreateSolidBrush(0x00000000);
windowClass.lpszMenuName = nullptr;
windowClass.lpszClassName = (X*)name;
windowClass.hIconSm = Windows::LoadIcon(0u, (X*)Windows::IDI_QUESTION);

Creé mi ventana con el indicador WS_EX_LAYERED.

windowHandle = Windows::CreateWindow(Windows::WS_EX_LAYERED, (X*)name, "", Windows::WS_POPUP, w / 4, h / 4, w / 2, h / 2, 0u, 0u, moduleHandle, 0u);

En mi formato de píxeles, he habilitado alfa y composición.

PixelFormatDescriptor format;
format.nSize = sizeof(PixelFormatDescriptor);
format.nVersion = 1;
format.dwFlags = PFD_SUPPORT_OPENGL | PFD_DRAW_TO_WINDOW | PFD_DOUBLEBUFFER | PFD_SUPPORT_COMPOSITION;
format.iPixelType = PFD_TYPE_RGBA;
format.cColorBits = 32;
format.cRedBits = 0;
format.cRedShift = 0;
format.cGreenBits = 0;
format.cGreenShift = 0;
format.cBlueBits = 0;
format.cBlueShift = 0;
format.cAlphaBits = 8;
format.cAlphaShift = 0;
format.cAccumBits = 0;
format.cAccumRedBits = 0;
format.cAccumGreenBits = 0;
format.cAccumBlueBits = 0;
format.cAccumAlphaBits = 0;
format.cDepthBits = 24;
format.cStencilBits = 8;
format.cAuxBuffers = 0;
format.iLayerType = PFD_MAIN_PLANE;
format.bReserved = 0;
format.dwLayerMask = 0;
format.dwVisibleMask = 0;
format.dwDamageMask = 0;

He probado el "truco" de la región de desenfoque, pero no tiene ningún efecto. Mi resultado no está relacionado con este fragmento de código.

struct DwmBlurBehind
{
U4 dwFlags;
S4 fEnable;
X* blurRegionHandle;
S4 fTransitionOnMaximized;
};

DwmBlurBehind blurBehind;
blurBehind.dwFlags = Windows::DWM_BB_ENABLE | Windows::DWM_BB_BLURREGION;
blurBehind.fEnable = true;
blurBehind.blurRegionHandle = Windows::CreateRectRgn(0, 0, -1, -1);
blurBehind.fTransitionOnMaximized = false;
Windows::DwmEnableBlurBehindWindow(windowHandle, &blurBehind);

Finalmente, configuré LWA_COLORKEY yAtributos LWA_ALPHA. Esto es lo que me dio el efecto que se muestra. Sin embargo, la clave de color no parece tenerse en cuenta (también he intentado con valores distintos de cero).

Windows::SetLayeredWindowAttributes(windowHandle, 0, 170, Windows::LWA_COLORKEY | Windows::LWA_ALPHA);

No me olvidé de habilitar la mezcla.

GL::Enable(GL::BLEND);
GL::BlendFunc(GL::SRC_ALPHA, GL::ONE_MINUS_SRC_ALPHA);

Respuestas

1 para la respuesta № 1

Lo que quiere hacer requiere una composición de ventanas que ha existido desde Windows Vista, por lo que, básicamente, todas las versiones de Windows deben preocuparse (Windows XP y versiones anteriores son EoL).

Los pasos clave a seguir es habilitar la composición DWM dentro de la ventana activando "Blue Behind Window" y usar un WM_POPUP ventana; si no usas WM_POPUP estilo, el administrador de ventanas dibujará decoraciones y su representación de OpenGL se "colocará" encima de eso.

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

MARGINS margins = {-1};
impl_DwmExtendFrameIntoClientArea(hWnd, &margins);

A continuación, debe crear un contexto de OpenGL utilizando la nueva API de "atributos" en lugar de utilizar la selección del descriptor de formato de píxeles. Con el atributo API puedes seleccionar un transparente con alfa formato de ventana.

int attribs[] = {
WGL_DRAW_TO_WINDOW_ARB, TRUE,
WGL_DOUBLE_BUFFER_ARB, TRUE,
WGL_SUPPORT_OPENGL_ARB, TRUE,
WGL_PIXEL_TYPE_ARB, WGL_TYPE_RGBA_ARB,
WGL_TRANSPARENT_ARB, TRUE,
WGL_COLOR_BITS_ARB, 32,
WGL_RED_BITS_ARB, 8,
WGL_GREEN_BITS_ARB, 8,
WGL_BLUE_BITS_ARB, 8,
WGL_ALPHA_BITS_ARB, 8,
WGL_DEPTH_BITS_ARB, 24,
WGL_STENCIL_BITS_ARB, 8,
0, 0
};

INT iPF;
UINT num_formats_choosen;
if( !wglChoosePixelFormatARB(
hDC,
attribs,
NULL,
1,
&iPF,
&num_formats_choosen) ) {
fprintf(stderr, "error choosing proper pixel formatn");
return NULL;
}
if( !num_formats_choosen ) {
return NULL;
}

PIXELFORMATDESCRIPTOR pfd;
memset(&pfd, 0, sizeof(pfd));
/* now this is a kludge; we need to pass something in the PIXELFORMATDESCRIPTOR
* to SetPixelFormat; it will be ignored, mostly. OTOH we want to send something
* sane, we"re nice people after all - it doesn"t hurt if this fails. */
DescribePixelFormat(hDC, iPF, sizeof(pfd), &pfd);

if( !SetPixelFormat(hDC, iPF, &pfd) ) {
fprintf(stderr, "error setting proper pixel formatn");
ReleaseDC(hWnd, hDC);
DestroyWindow(hWnd);

return NULL;
}

Tengo un ejemplo completo de trabajo para esto en mi wglarb repositorio de envoltura en GitHub: https://github.com/datenwolf/wglarb/blob/master/test/layered.c


2 para la respuesta № 2

Es posible que te falte la llamada a UpdateLayeredWindow . IIRC, al no llamar a UpdateLayeredWindow, tiene un comportamiento extraño. YMMV.

Más detalles aquí


0 para la respuesta № 3

De acuerdo con SetLayeredWindowAttributes doc necesitas pasar

una estructura COLORREF que especifica elclave de color de transparencia para ser utilizado al componer la ventana en capas. Todos los píxeles pintados por la ventana en este color será transparente. Para generar un COLORREF, use la macro RGB.

Revise el segundo parámetro de su llamada a esta función.


Menú