Finestra parzialmente trasparente OpenGL / Win32 - c ++, winapi, opengl

Ho letto tutte le domande esistenti su questo argomento delicato (di nicchia), ma sono bloccato. Ho una finestra Win32 con un contesto OpenGL. Voglio che la mia finestra sia parzialmente trasparente.

My result so far is that the entirety of the la finestra è trasparente. Voglio solo che l'area nera sia trasparente, in modo da poter disegnare alcuni oggetti 3D e sembreranno come se stessero arrivando dalla finestra.

inserisci la descrizione dell'immagine qui

Per prima cosa, nella mia classe di finestre, ho impostato hbrBackground sul nero.

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);

Ho creato la mia finestra con la bandiera 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);

Nel mio formato pixel, ho abilitato l'alfa e la composizione.

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;

Ho provato il "trucco" della sfocatura, ma non ha alcun effetto. Il mio risultato non è legato a questo pezzo di codice.

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);

Infine, ho impostato il LWA_COLORKEY eAttributi LWA_ALPHA. Questo è ciò che mi ha dato l'effetto mostrato. Tuttavia, la chiave di colore non sembra essere presa in considerazione (ho provato anche valori diversi da zero).

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

Non ho dimenticato di abilitare la fusione.

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

risposte:

1 per risposta № 1

Quello che vuoi fare è compositing di finestre che è stato utilizzato da Windows Vista, quindi essenzialmente ogni versione di Windows che ti interessa (Windows XP e versioni precedenti sono EoL).

La procedura chiave da seguire è quella di abilitare il compositing finestra DWM abilitando "Blue Behind Window" e utilizzando a WM_POPUP finestra; se non lo usi WM_POPUP stile il gestore delle finestre disegna le decorazioni e il rendering di OpenGL "passerà sopra" sopra.

        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);

Quindi è necessario creare un contesto OpenGL utilizzando la più recente API "attribute" anziché utilizzare la selezione del descrittore pixelformat. Con l'API degli attributi puoi selezionare a trasparente con alfa formato della finestra.

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

Ho un esempio operativo completo per questo nel mio wglarb repository wrapper su GitHub: https://github.com/datenwolf/wglarb/blob/master/test/layered.c


2 per risposta № 2

Potrebbe mancare la chiamata a UpdateLayeredWindow . IIRC, non chiamando UpdateLayeredWindow causa alcuni comportamenti strani. YMMV.

Più dettagli Qui


0 per risposta № 3

D'accordo con Documento SetLayeredWindowAttributes devi passare

una struttura COLORREF che specifica ilchiave di colore trasparenza per essere usato quando si compone la finestra a più livelli. Tutti i pixel dipinti dal la finestra di questo colore sarà trasparente. Per generare un COLORREF, utilizzare la macro RGB.

Rivedere il secondo parametro della chiamata a questa funzione.


Menu