Częściowo przezroczyste okno OpenGL / Win32 - c ++, winapi, opengl

Czytałem wszystkie istniejące pytania dotyczące tego trudnego (niszowego) tematu, ale utknąłem. Mam okno Win32 z kontekstem OpenGL. Chcę, aby moje okno było częściowo przezroczyste.

Mój dotychczasowy wynik jest taki, że całośćokno jest przezroczyste. Chcę, aby tylko czarny obszar był przezroczysty, aby móc narysować kilka obiektów 3D i będą wyglądać, jakby zbliżały się do okna.

wprowadź opis obrazu tutaj

Po pierwsze, w mojej klasie okna ustawiłem hbrBackground na czarny.

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

Stworzyłem moje okno z flagą 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);

W moim formacie pikseli włączam alfa i kompozycję.

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;

Próbowałem "triku" w obszarze rozmycia, ale nie ma on żadnego efektu. Mój wynik nie jest związany z tym fragmentem kodu.

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

Finally, I have set the LWA_COLORKEY and Atrybuty LWA_ALPHA. To właśnie dało mi efekt pokazany. Jednak wydaje się, że klucz koloru nie jest brany pod uwagę (próbowałem również wartości niezerowych).

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

Nie zapomniałem włączyć mieszania.

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

Odpowiedzi:

1 dla odpowiedzi № 1

To, co chcesz zrobić, wymaga kompozytu okien, który istnieje od czasów systemu Windows Vista, więc w zasadzie każda wersja systemu Windows musi się troszczyć (Windows XP i wcześniej to EoL).

Kluczowymi krokami do wykonania są: umożliwienie komponowania DWM między okienkami poprzez włączenie opcji "Niebieskie okno" i użycie znaku a WM_POPUP okno; jeśli nie używasz WM_POPUP styl menedżer okien będzie rysował dekoracje, a twoje renderowanie OpenGL będzie "najeżdżać" powyżej.

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

Następnie należy utworzyć kontekst OpenGL, używając nowszego "atrybutu" API zamiast korzystania z wyboru deskryptora pikselowego. Za pomocą atrybutu API możesz wybrać a przezroczysty z alfa format okna.

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

Mam do tego pełny przykład działania wglarb otwieranie repozytorium na GitHub: https://github.com/datenwolf/wglarb/blob/master/test/layered.c


2 dla odpowiedzi nr 2

Być może brakuje Ci połączenia UpdateLayeredWindow . IIRC, bez wywoływania UpdateLayeredWindow, powoduje dziwne zachowanie. YMMV.

Więcej szczegółów tutaj


0 dla odpowiedzi № 3

Zgodnie z SetLayeredWindowAttributes doc musisz przejść

struktura COLORREF, która określaklucz koloru przezroczystości używany podczas komponowania okna warstwowego. Wszystkie piksele namalowane przez okno w tym kolorze będzie przezroczyste. Aby wygenerować COLORREF, użyj makro RGB.

Przejrzyj drugi parametr twojego połączenia z tą funkcją.