Teiltransparentes Fenster OpenGL / Win32 - c ++, winapi, opengl

Ich habe jede existierende Frage zu diesem heiklen (Nischen-) Thema gelesen, aber ich stecke fest. Ich habe ein Win32-Fenster mit einem OpenGL-Kontext. Ich möchte, dass mein Fenster teilweise transparent ist.

Mein bisheriges Ergebnis ist, dass die Gesamtheit derDas Fenster ist transparent. Ich möchte nur den schwarzen Bereich transparent machen, damit ich einige 3D-Objekte zeichnen kann und sie so aussehen, als kämen sie aus dem Fenster.

Bildbeschreibung hier eingeben

Zuerst habe ich in meiner Fensterklasse hbrBackground auf schwarz gesetzt.

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

Ich habe mein Fenster mit dem WS_EX_LAYERED Flag erstellt.

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

In meinem Pixelformat habe ich Alpha und Komposition aktiviert.

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;

Ich habe versucht, den Trick Trick Trick, aber es hat keine Wirkung. Mein Ergebnis bezieht sich nicht auf diesen Code.

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

Zum Schluss habe ich den LWA_COLORKEY und eingestelltLWA_ALPHA-Attribute Dies hat mir den angezeigten Effekt gegeben. Der Farbschlüssel scheint jedoch nicht berücksichtigt zu werden (ich habe auch Werte versucht, die nicht Null sind).

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

Ich habe nicht vergessen, Blending zu aktivieren.

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

Antworten:

1 für die Antwort № 1

Was Sie tun möchten, erfordert ein Fenster-Compositing, das seit Windows Vista existiert, so dass Sie im Grunde jede Version von Windows beachten müssen (Windows XP und früher sind EoL).

Die wichtigsten Schritte bestehen darin, DWM-Intra-Fenster-Compositing zu aktivieren, indem Sie "Blue Behind Window" aktivieren und a WM_POPUP Fenster; wenn du nicht benutzt WM_POPUP Stil Der Fenstermanager wird Dekorationen zeichnen und Ihr OpenGL-Rendering wird darüber "schweben".

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

Als Nächstes müssen Sie einen OpenGL-Kontext mit der neueren Attribut-API erstellen, anstatt die Pixelformat-Deskriptorauswahl zu verwenden. Mit der Attribut-API können Sie a auswählen transparent mit Alpha Fensterformat.

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

Dafür habe ich ein komplettes Arbeitsbeispiel in meinem wglarb Wrapper-Repository bei GitHub: https://github.com/datenwolf/wglarb/blob/master/test/layered.c


2 für die Antwort № 2

Sie könnten den Anruf zu verpassen UpdateLayeredWindow . IIRC, nicht UpdateLayeredWindow aufrufen führt zu einem seltsamen Verhalten. YMMV.

Mehr Details Hier


0 für die Antwort № 3

In Übereinstimmung mit SetLayeredWindowAttributes doc Du musst bestehen

eine COLORREF-Struktur, die denTransparenz Farbschlüssel zu sein Wird beim Erstellen des Ebenenfensters verwendet. Alle Pixel, die von der Fenster in dieser Farbe wird transparent sein. Um ein COLORREF zu erzeugen, benutze das RGB-Makro.

Überprüfen Sie den zweiten Parameter Ihres Anrufs für diese Funktion.